1. 程式人生 > >[answerer的演算法課堂]簡單描述4種排序演算法(C語言實現)

[answerer的演算法課堂]簡單描述4種排序演算法(C語言實現)

[answerer的演算法課堂]簡單描述4種排序演算法(C語言實現)

這是我第一次寫文章,想要記錄自己的學習生活,寫得不好請包涵or指導,本來想一口氣寫好多種,後來發現,寫太多的話反而可讀性不強,而且,我文筆,知識有限吶。慢慢來吧

目錄

名稱氣泡排序直接選擇排序直接插入排序希爾排序
時間複雜度 O(n^2) O(n^2) O(n^2) O(n^(1.3—2))

ps.沒有講到穩定性和空間複雜度。

氣泡排序

氣泡排序(Bubble Sort),是一種電腦科學領域的較簡單的排序演算法。
它重複地走訪過要排序的元素列,依次比較兩個相鄰的元素,如果順序(如從大到小、首字母從從Z到A)錯誤就把他們交換過來。走訪元素的工作是重複地進行直到沒有相鄰元素需要交換,也就是說該元素列已經排序完成。

摘自百度百科

時間複雜度大約為O(n^2),可進行一些優化
這應該是c語言課程裡頭第一次講到的排序演算法,可以說得上是所有排序演算法裡頭最簡單的演算法了。

思想:按一定的順序,比如要求從大到小進行排序,那麼第一位到最後一位(也可從最後一位到第一位)依次進行多次比較


這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端(升序或降序排列),就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端一樣,故名“氣泡排序”。

程式碼實現(未優化版本)
這裡按從小到大排序
 
for(int i=0;i<n;i++)//比較n輪
for(int j=0;j<n,j++)//n輪中每一輪比較n次
{
  if(a[j]>a[j+1])
  {
    temp=a[j];
    a[j]=a[j+1];
    a[j+1]=temp;
  }
} 

 

 
程式碼實現(優化版本)
for(int i=0;i<n;i++)//比較n輪
for(int j=0;j<n-i;j++)//每一輪比較n-j次
{
  if(a[j]>a[j+1])
  {
    temp=a[j];
    a[j]=a[j+1];
    a[j+1]=temp;
  }
}

 

 

忽略我的排版,確實很糟糕,我會努力去改的

為什麼可以這樣優化呢?這就需要從機理來研究了,由於冒泡是每一次選出的是每一輪中的最大(小)的數,那麼下輪開始,我們就不需要再將未排序的數再與已經排序的數進行比較了!
這裡希望大家重視一下優化的版本,優化過後,時間複雜度會低些,這樣程式執行時間就會減少,雖然在冒泡這裡體現並不明顯,但隨著學習的深入,你會逐漸發現,演算法的優劣(時間複雜度&&空間複雜度),對一個程式而言很重要,特別是在資訊學競賽中(才不會用冒泡這種低端演算法呢)





02.直接選擇排序

直接選擇排序(Straight Select Sorting) 也是一種簡單的排序方法,它的基本思想是:第一次從R[0]R[n-1]中選取最小值,與R[0]交換,第二次從R[1]~R[n-1]中選取最小值,與R[1]交換,....,第i次從R[i-1]~R[n-1]中選取最小值,與R[i-1]交換,.....,第n-1次從R[n-2]R[n-1]中選取最小值,與R[n-2]交換,總共通過n-1次,得到一個按排序碼從小到大排列的有序序列。

摘自百度百科

ps.其實並不一定是從小到大,也可從大到小。

選擇排序的時間複雜度也是O(n^2)

思想:也是和冒泡一樣,進行多輪比較,但不一樣的地方在於,經過每一次比較之後,每一輪會確定一個最小(大)的數對應的位置,最後才進行一次交換,相比之下,冒泡是一直在交換,事實上,冒泡和直接選擇排序一樣,比較低端,能不用盡量不用,尤其對長度較大的陣列。

程式碼實現
int temp;
for(int i=0;i<n-1;i++)
{
  int k=i;
  for(int j=i+1;j<n;j++)
    if(a[j]<a[k])
    k=j;//每一輪中選出最小的陣列元素對應的下標
temp=a[k];
a[k]=a[i];
a[i]=temp;
}

 

 
動態圖解





03.直接插入排序

直接插入排序(Straight Insertion Sort)是一種最簡單的排序方法,其基本操作是將一條記錄插入到已排好的有序表中,從而得到一個新的、記錄數量增1的有序表。

摘自百度百科

直接插入排序的時間複雜度還是O(n^2)
思想:每次選擇一個元素,將這個元素與陣列中該元素之前所有的元素進行比較,然後將它插到合適的位置。

程式碼實現
    int i,j,temp;
    for ( i = 1; i < n; i++) {
         temp = a[i];//每一輪選出一個元素
        for ( j = i; j > 0 && a[j - 1] > temp; j--) {
            a[j] = a[j - 1];//與前面的元素比較大小,然後插進去,後面的元素退一位
        }
        a[j] = temp;
    }

 

 
動態圖解





04.希爾排序

希爾排序(Shell's Sort)是插入排序的一種又稱“縮小增量排序”(Diminishing Increment Sort),是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法。該方法因D.L.Shell於1959年提出而得名。
希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個檔案恰被分成一組,演算法便終止。

希爾排序是基於插入排序的以下兩點性質而提出改進方法的:
插入排序在對幾乎已經排好序的資料操作時,效率高,即可以達到線性排序的效率。
但插入排序一般來說是低效的,因為插入排序每次只能將資料移動一位。

摘自百度百科

在某些極端情況下,希爾排序的時間複雜度會達到O(n^2)


希爾排序的平均時間複雜度是O(n^(1.3—2))
思想:直接插入排序要進行多次的比較交換,如果說,一個數組中大部分元素都處於有序的狀態下,那麼就不需要進行多次的交換了。那麼就需要先對陣列進行一定的處理。

程式碼實現

以下是希爾增量下的希爾排序,關於希爾排序的增量,有很多種選擇,例如Hibbard增量,這些增量有些是通過數學證明得到的,有些則是還沒有得到證明的,人們確信正確的經驗得出的。。個人感覺有點像孿生素數猜想那樣的吧,但證明難度應該沒有那麼高。

  for (int gap= n/2; gap > 0; gap /= 2)//分組
    {
        for (int i = gap; i < n; i ++ )
        {
            int temp = a[i];
            int j;          //這裡基本上和插入排序差不多
            for (j = i; j >= gap && a[j - gap] > temp; j -= gap)
                a[j] = a[j - gap];
            a[j] = temp;
        }
    }
    

 

 
圖解

ps.希爾排序的動圖我在網上找不到,只能用圖片代替了 對於這樣的一個數組,進行分組,gap=n/2,然後每分好之後,再gap/=2,一直到gap=1,這個過程使得陣列的整體有序性提高,從而使直接插入排序的工作量減少很多.

對於其它增量實現的,這裡不貼出來了,因為,我不會寫唉(逃





最後,這是我第一次寫部落格,很多東西,如markdown語法什麼的都不太會,希望大家包涵,如有錯誤,請指正,萬分感謝!

圖片來源於網路,侵刪