1. 程式人生 > >十大經典排序演算法(一)

十大經典排序演算法(一)

1.氣泡排序

  1. 演算法思想:a:比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
  2. b:對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。
  3. c:針對所有的元素重複以上的步驟,除了最後一個。
  4. d:持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
圖解: 實現程式碼:
for (j = 0; j < n - 1; j++)
        for (i = 0; i < n - 1 - j; i++)
        {
            if(a[i] > a[i + 1])
            {
                temp = a[i];
                a[i] = a[i + 1];
                a[i + 1] = temp;
            }
        }
2.快速排序 演算法思想: 設要排序的陣列是A[0]……A[N-1],首先任意選取一個數據(通常選用陣列的第一個數)作為關鍵資料,然後將所有比它小的數都放到它前面,所有比它大的數都放到它後面,這個過程稱為一趟快速排序。值得注意的是,快速排序不是一種穩定的排序演算法,也就是說,多個相同的值的相對位置也許會在演算法結束時產生變動。 一趟快速排序的演算法是: 1)設定兩個變數i、j,排序開始的時候:i=0,j=N-1; 2)以第一個陣列元素作為關鍵資料,賦值給key,即key=A[0]; 3)從j開始向前搜尋,即由後開始向前搜尋(j--),找到第一個小於key的值A[j],將A[j]和A[i]互換;
4)從i開始向後搜尋,即由前開始向後搜尋(i++),找到第一個大於key的A[i],將A[i]和A[j]互換; 5)重複第3、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小於key,4中A[i]不大於key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到為止。找到符合條件的值,進行交換的時候i, j指標位置不變。另外,i==j這一過程一定正好是i+或j-完成的時候,此時令迴圈結束)。 圖解:
程式碼實現:
void sort(int *a, int left, int right)
{
    if(left >= right)/*如果左邊索引大於或者等於右邊的索引就代表已經整理完成一個組了*/
    {
        return ;
    }
    int i = left;
    int j = right;
    int key = a[left];
     
    while(i < j)                               /*控制在當組內尋找一遍*/
    {
        while(i < j && key <= a[j])
        /*而尋找結束的條件就是,1,找到一個小於或者大於key的數(大於或小於取決於你想升
        序還是降序)2,沒有符合條件1的,並且i與j的大小沒有反轉*/ 
        {
            j--;/*向前尋找*/
        }
         
        a[i] = a[j];
        /*找到一個這樣的數後就把它賦給前面的被拿走的i的值(如果第一次迴圈且key是
        a[left],那麼就是給key)*/
         
        while(i < j && key >= a[i])
        /*這是i在當組內向前尋找,同上,不過注意與key的大小關係停止迴圈和上面相反,
        因為排序思想是把數往兩邊扔,所以左右兩邊的數大小與key的關係相反*/
        {
            i++;
        }
         
        a[j] = a[i];
    }
     
    a[i] = key;/*當在當組內找完一遍以後就把中間數key迴歸*/
    sort(a, left, i - 1);/*最後用同樣的方式對分出來的左邊的小組進行同上的做法*/
    sort(a, i + 1, right);/*用同樣的方式對分出來的右邊的小組進行同上的做法*/
                       /*當然最後可能會出現很多分左右,直到每一組的i = j 為止*/
}
3.插入排序 演算法思想:插入排序的基本操作就是將一個數據插入到已經排好序的有序資料中,從而得到一個新的、個數加一的有序資料,演算法適用於少量資料的排序,時間複雜度為O(n^2) 圖解: 程式碼: 
int I,j;
Redtype temp;
for (i=1;i<n;i++)
{
	temp = r[i];
	j=i-1;
	while (j>-1 &&temp.key<r[j].key)
	{
		r[j+1]=r[j];
j--;
}
r[j+1]=temp;
}
4.希爾排序是基於插入排序的以下兩點性質而提出改進方法的: 插入排序在對幾乎已經排好序的資料操作時,效率高,即可以達到線性排序的效率。
  1. 但插入排序一般來說是低效的,因為插入排序每次只能將資料移動一位。(別如資料逆序,我們就要將該資料一位以一位的移動,浪費時間)
    先將整個待排序的記錄序列分割成為若干子序列分別進行直接插入排序,待整個序列中的記錄“基本有序”時,再對全體記錄進行依次直接插入排序。
  2. 演算法步驟:

    1)選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;

    2)按增量序列個數k,對序列進行k 趟排序;

    3)每趟排序,根據對應的增量ti,將待排序列分割成若干長度為m 的子序列,分別對各子表進行直接插入排序。僅增量因子為1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。

圖解: 程式碼: 
void shellInsert(int array[],int n,int dk)
{
    int i,j,temp;
    for(i=dk;i<n;i++)//分別向每組的有序區域插入
    {
        temp=array[i];
        for(j=i-dk;(j>=i%dk)&&array[j]>temp;j-=dk)//比較與記錄後移同時進行
            array[j+dk]=array[j];
        if(j!=i-dk)
            array[j+dk]=temp;//插入
    }
}
5.堆排序 演算法思想:堆思想 圖解: 程式碼:
/array是待調整的堆陣列,i是待調整的陣列元素的位置,nlength是陣列的長度
//本函式功能是:根據陣列array構建大根堆
void HeapAdjust(int array[],int i,int nLength)
{
    int nChild;
    int nTemp;
    for(;2*i+1<nLength;i=nChild)
    {
        //子結點的位置=2*(父結點位置)+1
        nChild=2*i+1;
        //得到子結點中較大的結點
        if(nChild<nLength-1&&array[nChild+1]>array[nChild])++nChild;
        //如果較大的子結點大於父結點那麼把較大的子結點往上移動,替換它的父結點
        if(array[i]<array[nChild])
        {
            nTemp=array[i];
            array[i]=array[nChild];
            array[nChild]=nTemp; 
        }
        else break; //否則退出迴圈
    }
}