演算法是一種與語言無關的東西,更確切地說就算解決問題的思路,就是一個通用的思想的問題。代碼本身不重要,演算法思想才是重中之重
我們在面試的時候總會被問到一下演算法,雖然演算法是一些基礎知識,但是難起來也會讓人非常頭疼。
排序演算法應該算是一些簡單且基礎的演算法,但是我們可以從簡單的演算法排序鍛煉我們的演算法思維。這里我就介紹經典十大演算法用python是怎麼實現的。
十大經典演算法可以分為兩大類:
比較排序: 通過對數組中的元素進行比較來實現排序。
非比較排序: 不通過比較來決定元素間的相對次序。
演算法復雜度
冒泡排序比較簡單,幾乎所有語言演算法都會涉及的冒泡演算法。
基本原理是兩兩比較待排序數據的大小 ,當兩個數據的次序不滿足順序條件時即進行交換,反之,則保持不變。
每次選擇一個最小(大)的,直到所有元素都被輸出。
將第一個元素逐個插入到前面的有序數中,直到插完所有元素為止。
從大范圍到小范圍進行比較-交換,是插入排序的一種,它是針對直接插入排序演算法的改進。先對數據進行預處理,使其基本有序,然後再用直接插入的排序演算法排序。
該演算法是採用 分治法 對集合進行排序。
把長度為n的輸入序列分成兩個長度為n/2的子序列,對這兩個子序列分別採用歸並排序,最終合並成序列。
選取一個基準值,小數在左大數在在右。
利用堆這種數據結構所設計的一種排序演算法。
堆是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。利用最大堆和最小堆的特性。
採用字典計數-還原的方法,找出待排序的數組中最大和最小的元素,統計數組中每個值為i的元素出現的次數,對所有的計數累加,將每個元素放在新數組依次排序。
設置一個定量的數組當作空桶;遍歷輸入數據,並且把數據一個一個放到對應的桶里去;對每個不是空的桶進行排序;從不是空的桶里把排好序的數據拼接起來。
元素分布在桶中:
然後,元素在每個桶中排序:
取得數組中的最大數,並取得位數;從最低位開始取每個位組成新的數組;然後進行計數排序。
上面就是我整理的十大排序演算法,希望能幫助大家在演算法方面知識的提升。看懂之後可以去試著自己到電腦上運行一遍。最後說一下每個排序是沒有調用數據的,大家記得實操的時候要調用。
參考地址:https://www.runoob.com/w3cnote/ten-sorting-algorithm.html
『貳』 面試必會八大排序演算法(Python)
一、插入排序
介紹
插入排序的基本操作就是將一個數據插入到已經排好序的有序數據中,從而得到一個新的、個數加一的有序數據。
演算法適用於少量數據的排序,時間復雜度為O(n^2)。
插入排演算法是穩定的排序方法。
步驟
①從第一個元素開始,該元素可以認為已經被排序
②取出下一個元素,在已經排序的元素序列中從後向前掃描
③如果該元素(已排序)大於新元素,將該元素移到下一位置
④重復步驟3,直到找到已排序的元素小於或者等於新元素的位置
⑤將新元素插入到該位置中
⑥重復步驟2
排序演示
演算法實現
二、冒泡排序
介紹
冒泡排序(Bubble Sort)是一種簡單的排序演算法,時間復雜度為O(n^2)。
它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。
這個演算法的名字由來是因為越小的元素會經由交換慢慢「浮」到數列的頂端。
原理
循環遍歷列表,每次循環找出循環最大的元素排在後面;
需要使用嵌套循環實現:外層循環控制總循環次數,內層循環負責每輪的循環比較。
步驟
①比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
②對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。
③針對所有的元素重復以上的步驟,除了最後一個。
④持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。
演算法實現:
三、快速排序
介紹
快速排序(Quicksort)是對冒泡排序的一種改進,借用了分治的思想,由C. A. R. Hoare在1962年提出。
基本思想
快速排序的基本思想是:挖坑填數 + 分治法。
首先選出一個軸值(pivot,也有叫基準的),通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。
實現步驟
①從數列中挑出一個元素,稱為 「基準」(pivot);
②重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊);
③對所有兩個小數列重復第二步,直至各區間只有一個數。
排序演示
演算法實現
四、希爾排序
介紹
希爾排序(Shell Sort)是插入排序的一種,也是縮小增量排序,是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法,時間復雜度為:O(1.3n)。
希爾排序是基於插入排序的以下兩點性質而提出改進方法的:
·插入排序在對幾乎已經排好序的數據操作時, 效率高, 即可以達到線性排序的效率;
·但插入排序一般來說是低效的, 因為插入排序每次只能將數據移動一位。
基本思想
①希爾排序是把記錄按下標的一定量分組,對每組使用直接插入演算法排序;
②隨著增量逐漸減少,每組包1含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,演算法被終止。
排序演示
演算法實現
五、選擇排序
介紹
選擇排序(Selection sort)是一種簡單直觀的排序演算法,時間復雜度為Ο(n2)。
基本思想
選擇排序的基本思想:比較 + 交換。
第一趟,在待排序記錄r1 ~ r[n]中選出最小的記錄,將它與r1交換;
第二趟,在待排序記錄r2 ~ r[n]中選出最小的記錄,將它與r2交換;
以此類推,第 i 趟,在待排序記錄ri ~ r[n]中選出最小的記錄,將它與r[i]交換,使有序序列不斷增長直到全部排序完畢。
排序演示
選擇排序的示例動畫。紅色表示當前最小值,黃色表示已排序序列,藍色表示當前位置。
演算法實現
六、堆排序
介紹
堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序演算法,它是選擇排序的一種。
利用數組的特點快速指定索引的元素。
基本思想
堆分為大根堆和小根堆,是完全二叉樹。
大根堆的要求是每個節點的值不大於其父節點的值,即A[PARENT[i]] >=A[i]。
在數組的非降序排序中,需要使用的就是大根堆,因為根據大根堆的要求可知,最大的值一定在堆頂。
排序演示
演算法實現
七、歸並排序
介紹
歸並排序(Merge sort)是建立在歸並操作上的一種有效的排序演算法。該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。
基本思想
歸並排序演算法是將兩個(或兩個以上)有序表合並成一個新的有序表,即把待排序序列分為若干個子序列,每個子序列是有序的。然後再把有序子序列合並為整體有序序列。
演算法思想
自上而下遞歸法(假如序列共有n個元素)
① 將序列每相鄰兩個數字進行歸並操作,形成 floor(n/2)個序列,排序後每個序列包含兩個元素;
② 將上述序列再次歸並,形成 floor(n/4)個序列,每個序列包含四個元素;
③ 重復步驟②,直到所有元素排序完畢。
自下而上迭代法
① 申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合並後的序列;
② 設定兩個指針,最初位置分別為兩個已經排序序列的起始位置;
③ 比較兩個指針所指向的元素,選擇相對小的元素放入到合並空間,並移動指針到下一位置;
④ 重復步驟③直到某一指針達到序列尾;
⑤ 將另一序列剩下的所有元素直接復制到合並序列尾。
排序演示
演算法實現
八、基數排序
介紹
基數排序(Radix Sort)屬於「分配式排序」,又稱為「桶子法」。
基數排序法是屬於穩定性的排序,其時間復雜度為O (nlog(r)m) ,其中 r 為採取的基數,而m為堆數。
在某些時候,基數排序法的效率高於其他的穩定性排序法。
基本思想
將所有待比較數值(正整數)統一為同樣的數位長度,數位較短的數前面補零。然後,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以後,數列就變成一個有序序列。
基數排序按照優先從高位或低位來排序有兩種實現方案:
MSD(Most significant digital) 從最左側高位開始進行排序。先按k1排序分組, 同一組中記錄, 關鍵碼k1相等,再對各組按k2排序分成子組, 之後, 對後面的關鍵碼繼續這樣的排序分組, 直到按最次位關鍵碼kd對各子組排序後. 再將各組連接起來,便得到一個有序序列。MSD方式適用於位數多的序列。
LSD (Least significant digital)從最右側低位開始進行排序。先從kd開始排序,再對kd-1進行排序,依次重復,直到對k1排序後便得到一個有序序列。LSD方式適用於位數少的序列。
排序效果
演算法實現
九、總結
各種排序的穩定性、時間復雜度、空間復雜度的總結:
平方階O(n²)排序:各類簡單排序:直接插入、直接選擇和冒泡排序;
從時間復雜度來說:
線性對數階O(nlog₂n)排序:快速排序、堆排序和歸並排序;
O(n1+§))排序,§是介於0和1之間的常數:希爾排序 ;
線性階O(n)排序:基數排序,此外還有桶、箱排序。
『叄』 快速排序演算法原理與實現
快速排序的基本思想就是從一個數組中任意挑選一個元素(通常來說會選擇最左邊的元素)作為中軸元素,將剩下的元素以中軸元素作為比較的標准,將小於等於中軸元素的放到中軸元素的左邊,將大於中軸元素的放到中軸元素的右邊。
然後以當前中軸元素的位置為界,將左半部分子數組和右半部分子數組看成兩個新的數組,重復上述操作,直到子數組的元素個數小於等於1(因為一個元素的數組必定是有序的)。
以下的代碼中會常常使用交換數組中兩個元素值的Swap方法,其代碼如下
publicstaticvoidSwap(int[] A, inti, intj){
inttmp;
tmp = A[i];
A[i] = A[j];
A[j] = tmp;
(3)要求用排序演算法實現擴展閱讀:
快速排序演算法 的基本思想是:將所要進行排序的數分為左右兩個部分,其中一部分的所有數據都比另外一 部分的數據小,然後將所分得的兩部分數據進行同樣的劃分,重復執行以上的劃分操作,直 到所有要進行排序的數據變為有序為止。
定義兩個變數low和high,將low、high分別設置為要進行排序的序列的起始元素和最後一個元素的下標。第一次,low和high的取值分別為0和n-1,接下來的每次取值由劃分得到的序列起始元素和最後一個元素的下標來決定。
定義一個變數key,接下來以key的取值為基準將數組A劃分為左右兩個部分,通 常,key值為要進行排序序列的第一個元素值。第一次的取值為A[0],以後毎次取值由要劃 分序列的起始元素決定。
從high所指向的數組元素開始向左掃描,掃描的同時將下標為high的數組元素依次與劃分基準值key進行比較操作,直到high不大於low或找到第一個小於基準值key的數組元素,然後將該值賦值給low所指向的數組元素,同時將low右移一個位置。
如果low依然小於high,那麼由low所指向的數組元素開始向右掃描,掃描的同時將下標為low的數組元素值依次與劃分的基準值key進行比較操作,直到low不小於high或找到第一個大於基準值key的數組元素,然後將該值賦給high所指向的數組元素,同時將high左移一個位置。
重復步驟(3) (4),直到low的植不小於high為止,這時成功劃分後得到的左右兩部分分別為A[low……pos-1]和A[pos+1……high],其中,pos下標所對應的數組元素的值就是進行劃分的基準值key,所以在劃分結束時還要將下標為pos的數組元素賦值 為 key。
『肆』 排序演算法如何實現 C++
一、簡單排序演算法
由於程序比較簡單,所以沒有加什麼注釋。所有的程序都給出了完整的運行代碼,並在我的VC環境
下運行通過。因為沒有涉及MFC和WINDOWS的內容,所以在BORLAND C++的平台上應該也不會有什麼
問題的。在代碼的後面給出了運行過程示意,希望對理解有幫助。
1.冒泡法:
這是最原始,也是眾所周知的最慢的演算法了。他的名字的由來因為它的工作看來象是冒泡:
#include <iostream.h>
void BubbleSort(int* pData,int Count)
{
int iTemp;
for(int i=1;i<Count;i++)
{
for(int j=Count-1;j>=i;j--)
{
if(pData[j]<pData[j-1])
{
iTemp = pData[j-1];
pData[j-1] = pData[j];
pData[j] = iTemp;
}
}
}
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
BubbleSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
倒序(最糟情況)
第一輪:10,9,8,7->10,9,7,8->10,7,9,8->7,10,9,8(交換3次)
第二輪:7,10,9,8->7,10,8,9->7,8,10,9(交換2次)
第一輪:7,8,10,9->7,8,9,10(交換1次)
循環次數:6次
交換次數:6次
其他:
第一輪:8,10,7,9->8,10,7,9->8,7,10,9->7,8,10,9(交換2次)
第二輪:7,8,10,9->7,8,10,9->7,8,10,9(交換0次)
第一輪:7,8,10,9->7,8,9,10(交換1次)
循環次數:6次
交換次數:3次
上面我們給出了程序段,現在我們分析它:這里,影響我們演算法性能的主要部分是循環和交換, 顯然,次數越多,性能就越差。從上面的程序我們可以看出循環的次數是固定的,為1+2+...+n-1。 寫成公式就是1/2*(n-1)*n。 現在注意,我們給出O方法的定義:
若存在一常量K和起點n0,使當n>=n0時,有f(n)<=K*g(n),則f(n) = O(g(n))。(呵呵,不要說沒 學好數學呀,對於編程數學是非常重要的!!!)
現在我們來看1/2*(n-1)*n,當K=1/2,n0=1,g(n)=n*n時,1/2*(n-1)*n<=1/2*n*n=K*g(n)。所以f(n) =O(g(n))=O(n*n)。所以我們程序循環的復雜度為O(n*n)。 再看交換。從程序後面所跟的表可以看到,兩種情況的循環相同,交換不同。其實交換本身同數據源的 有序程度有極大的關系,當數據處於倒序的情況時,交換次數同循環一樣(每次循環判斷都會交換), 復雜度為O(n*n)。當數據為正序,將不會有交換。復雜度為O(0)。亂序時處於中間狀態。正是由於這樣的 原因,我們通常都是通過循環次數來對比演算法。
2.交換法:
交換法的程序最清晰簡單,每次用當前的元素一一的同其後的元素比較並交換。
#include <iostream.h>
void ExchangeSort(int* pData,int Count)
{
int iTemp;
for(int i=0;i<Count-1;i++)
{
for(int j=i+1;j<Count;j++)
{
if(pData[j]<pData[i])
{
iTemp = pData[i];
pData[i] = pData[j];
pData[j] = iTemp;
}
}
}
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
ExchangeSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
倒序(最糟情況)
第一輪:10,9,8,7->9,10,8,7->8,10,9,7->7,10,9,8(交換3次)
第二輪:7,10,9,8->7,9,10,8->7,8,10,9(交換2次)
第一輪:7,8,10,9->7,8,9,10(交換1次)
循環次數:6次
交換次數:6次
其他:
第一輪:8,10,7,9->8,10,7,9->7,10,8,9->7,10,8,9(交換1次)
第二輪:7,10,8,9->7,8,10,9->7,8,10,9(交換1次)
第一輪:7,8,10,9->7,8,9,10(交換1次)
循環次數:6次
交換次數:3次
從運行的表格來看,交換幾乎和冒泡一樣糟。事實確實如此。循環次數和冒泡一樣 也是1/2*(n-1)*n,所以演算法的復雜度仍然是O(n*n)。由於我們無法給出所有的情況,所以 只能直接告訴大家他們在交換上面也是一樣的糟糕(在某些情況下稍好,在某些情況下稍差)。
3.選擇法:
現在我們終於可以看到一點希望:選擇法,這種方法提高了一點性能(某些情況下) 這種方法類似我們人為的排序習慣:從數據中選擇最小的同第一個值交換,在從省下的部分中 選擇最小的與第二個交換,這樣往復下去。
#include <iostream.h>
void SelectSort(int* pData,int Count)
{
int iTemp;
int iPos;
for(int i=0;i<Count-1;i++)
{
iTemp = pData[i];
iPos = i;
for(int j=i+1;j<Count;j++)
{
if(pData[j]<iTemp)
{
iTemp = pData[j];
iPos = j;
}
}
pData[iPos] = pData[i];
pData[i] = iTemp;
}
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
SelectSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
倒序(最糟情況)
第一輪:10,9,8,7->(iTemp=9)10,9,8,7->(iTemp=8)10,9,8,7->(iTemp=7)7,9,8,10(交換1次)
第二輪:7,9,8,10->7,9,8,10(iTemp=8)->(iTemp=8)7,8,9,10(交換1次)
第一輪:7,8,9,10->(iTemp=9)7,8,9,10(交換0次)
循環次數:6次
交換次數:2次
其他:
第一輪:8,10,7,9->(iTemp=8)8,10,7,9->(iTemp=7)8,10,7,9->(iTemp=7)7,10,8,9(交換1次)
第二輪:7,10,8,9->(iTemp=8)7,10,8,9->(iTemp=8)7,8,10,9(交換1次)
第一輪:7,8,10,9->(iTemp=9)7,8,9,10(交換1次)
循環次數:6次
交換次數:3次
遺憾的是演算法需要的循環次數依然是1/2*(n-1)*n。所以演算法復雜度為O(n*n)。 我們來看他的交換。由於每次外層循環只產生一次交換(只有一個最小值)。所以f(n)<=n 所以我們有f(n)=O(n)。所以,在數據較亂的時候,可以減少一定的交換次數。
4.插入法:
插入法較為復雜,它的基本工作原理是抽出牌,在前面的牌中尋找相應的位置插入,然後繼續下一張
#include <iostream.h>
void InsertSort(int* pData,int Count)
{
int iTemp;
int iPos;
for(int i=1;i<Count;i++)
{
iTemp = pData[i];
iPos = i-1;
while((iPos>=0) && (iTemp<pData[iPos]))
{
pData[iPos+1] = pData[iPos];
iPos--;
}
pData[iPos+1] = iTemp;
}
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
InsertSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
倒序(最糟情況)
第一輪:10,9,8,7->9,10,8,7(交換1次)(循環1次)
第二輪:9,10,8,7->8,9,10,7(交換1次)(循環2次)
第一輪:8,9,10,7->7,8,9,10(交換1次)(循環3次)
循環次數:6次
交換次數:3次
其他:
第一輪:8,10,7,9->8,10,7,9(交換0次)(循環1次)
第二輪:8,10,7,9->7,8,10,9(交換1次)(循環2次)
第一輪:7,8,10,9->7,8,9,10(交換1次)(循環1次)
循環次數:4次
交換次數:2次
上面結尾的行為分析事實上造成了一種假象,讓我們認為這種演算法是簡單演算法中最好的,其實不是, 因為其循環次數雖然並不固定,我們仍可以使用O方法。從上面的結果可以看出,循環的次數f(n)<= 1/2*n*(n-1)<=1/2*n*n。所以其復雜度仍為O(n*n)(這里說明一下,其實如果不是為了展示這些簡單 排序的不同,交換次數仍然可以這樣推導)。現在看交換,從外觀上看,交換次數是O(n)(推導類似 選擇法),但我們每次要進行與內層循環相同次數的『=』操作。正常的一次交換我們需要三次『=』 而這里顯然多了一些,所以我們浪費了時間。
最終,我個人認為,在簡單排序演算法中,選擇法是最好的。
二、高級排序演算法:
高級排序演算法中我們將只介紹這一種,同時也是目前我所知道(我看過的資料中)的最快的。 它的工作看起來仍然象一個二叉樹。首先我們選擇一個中間值middle程序中我們使用數組中間值,然後 把比它小的放在左邊,大的放在右邊(具體的實現是從兩邊找,找到一對後交換)。然後對兩邊分別使 用這個過程(最容易的方法——遞歸)。
1.快速排序:
#include <iostream.h>
void run(int* pData,int left,int right)
{
int i,j;
int middle,iTemp;
i = left;
j = right;
middle = pData[(left+right)/2]; //求中間值
do{
while((pData[i]<middle) && (i<right))//從左掃描大於中值的數
i++;
while((pData[j]>middle) && (j>left))//從右掃描大於中值的數
j--;
if(i<=j)//找到了一對值
{
//交換
iTemp = pData[i];
pData[i] = pData[j];
pData[j] = iTemp;
i++;
j--;
}
}while(i<=j);//如果兩邊掃描的下標交錯,就停止(完成一次)
//當左邊部分有值(left<j),遞歸左半邊
if(left<j)
run(pData,left,j);
//當右邊部分有值(right>i),遞歸右半邊
if(right>i)
run(pData,i,right);
}
void QuickSort(int* pData,int Count)
{
run(pData,0,Count-1);
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
QuickSort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
這里我沒有給出行為的分析,因為這個很簡單,我們直接來分析演算法:首先我們考慮最理想的情況
1.數組的大小是2的冪,這樣分下去始終可以被2整除。假設為2的k次方,即k=log2(n)。
2.每次我們選擇的值剛好是中間值,這樣,數組才可以被等分。
第一層遞歸,循環n次,第二層循環2*(n/2)......
所以共有n+2(n/2)+4(n/4)+...+n*(n/n) = n+n+n+...+n=k*n=log2(n)*n
所以演算法復雜度為O(log2(n)*n)
其他的情況只會比這種情況差,最差的情況是每次選擇到的middle都是最小值或最大值,那麼他將變 成交換法(由於使用了遞歸,情況更糟)。但是你認為這種情況發生的幾率有多大??呵呵,你完全 不必擔心這個問題。實踐證明,大多數的情況,快速排序總是最好的。 如果你擔心這個問題,你可以使用堆排序,這是一種穩定的O(log2(n)*n)演算法,但是通常情況下速度要慢 於快速排序(因為要重組堆)。
三、其他排序
1.雙向冒泡:
通常的冒泡是單向的,而這里是雙向的,也就是說還要進行反向的工作。 代碼看起來復雜,仔細理一下就明白了,是一個來回震盪的方式。 寫這段代碼的作者認為這樣可以在冒泡的基礎上減少一些交換(我不這么認為,也許我錯了)。 反正我認為這是一段有趣的代碼,值得一看。
#include <iostream.h>
void Bubble2Sort(int* pData,int Count)
{
int iTemp;
int left = 1;
int right =Count -1;
int t;
do {
//正向的部分
for(int i=right;i>=left;i--)
{
if(pData[i]<pData[i-1])
{
iTemp = pData[i];
pData[i] = pData[i-1];
pData[i-1] = iTemp;
t = i;
}
}
left = t+1;
//反向的部分
for(i=left;i<right+1;i++)
{
if(pData[i]<pData[i-1])
{
iTemp = pData[i];
pData[i] = pData[i-1];
pData[i-1] = iTemp;
t = i;
}
}
right = t-1;
}while(left<=right);
}
void main()
{
int data[] = {10,9,8,7,6,5,4};
Bubble2Sort(data,7);
for (int i=0;i<7;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
2.SHELL排序
這個排序非常復雜,看了程序就知道了。 首先需要一個遞減的步長,這里我們使用的是9、5、3、1(最後的步長必須是1)。 工作原理是首先對相隔9-1個元素的所有內容排序,然後再使用同樣的方法對相隔5-1個元素的排序,以次類推。
#include <iostream.h>
void ShellSort(int* pData,int Count)
{
int step[4];
step[0] = 9;
step[1] = 5;
step[2] = 3;
step[3] = 1;
int i,Temp;
int k,s,w;
for(int i=0;i<4;i++)
{
k = step[i];
s = -k;
for(int j=k;j<Count;j++)
{
iTemp = pData[j];
w = j-k;//求上step個元素的下標
if(s ==0)
{
s = -k;
s++;
pData[s] = iTemp;
}
while((iTemp<pData[w]) && (w>=0) && (w<=Count))
{
pData[w+k] = pData[w];
w = w-k;
}
pData[w+k] = iTemp;
}
}
}
void main()
{
int data[] = {10,9,8,7,6,5,4,3,2,1,-10,-1};
ShellSort(data,12);
for (int i=0;i<12;i++)
cout<<data[i]<<" ";
cout<<"\n";
}
呵呵,程序看起來有些頭疼。不過也不是很難,把s==0的塊去掉就輕松多了,這里是避免使用0 步長造成程序異常而寫的代碼。這個代碼我認為很值得一看。 這個演算法的得名是因為其發明者的名字D.L.SHELL。依照參考資料上的說法:「由於復雜的數學原因 避免使用2的冪次步長,它能降低演算法效率。」另外演算法的復雜度為n的1.2次冪。同樣因為非常復雜並 「超出本書討論范圍」的原因(我也不知道過程),我們只有結果了