基本排序算法(冒泡,快排,插入,希爾,選擇,歸並)


這篇文章僅僅為心中自證,不是算法教學,也不想誤人子弟,謝謝各位。

第一章:一些感慨

  我斷斷續續學習算法兩年多了,這說起來是多么苦澀,是我笨嘛?一直不知道算法是什么東西。

從《算法導論》再到《C算法》不清楚看了多少遍,它們就是我過不去的坎嗎?

  

  不敢說什么大話,但是我有一個心得,學習算法,一定要理解,理解比會寫更重要,會寫,很有可能僅僅是記憶好,

但是過一段時間忘了, 就對這個算法完全沒有印象了,我就是這樣。

  所以我以后學習算法,一定抱着理解的心態,理解了,就很好。

第二章:基本排序算法

2.1 冒泡排序

  人們常說,冒泡排序是最初級的排序算法,人們說這句話的時候是從時間復雜度這個角度來說的,這么說或許沒錯,

但是,冒泡排序是相當漂亮的排序,這個“漂亮”是說,假如把排序算法可視化起來,x軸從小到大,依次對應0到n,y軸對應的是a[x],

然后排序開始了,你會發現冒泡很飄逸,看起來很賞心悅目,大概人們都喜歡美麗的泡泡吧。

  冒泡排序的中心思想:不寫中心思想至少也有十年了吧,記得高中之后語文老師就不搞什么中心思想之類的。

但是我還是要寫一寫冒泡排序的中心思想,而且,現在我不看資料,我想描述一下,看一看我到底能不能描述。

  冒泡排序的思想是這樣的,從數組a[0]開始,比較相鄰的兩項的大小順序,假如順序不對,則交換兩項。

5 4 6 3 2

  比如上面的數組,先比較a[0]和a[1],發現a[0]大於a[1],我們認為從小到大排,所以順序就不對了,那就交換吧,交換之后就是

4 5 6 3 2

  再然后就是比較a[1]和a[2]了,就這樣,一次冒泡,最大項就冒到了頂部。

  很明顯,我們需要兩層循環,可是第二次循環的時候,我們就沒必要從0到n了,因為我們知道a[n-1]項已經是最大的了。

 1 void BubbleSort(Item a[],int left,int right)
 2 {
 3       int i = 0,j = 0;
 4       for(i = left; i < right; i++) 
 5       {
 6             for(j = left;j < right -i - 1; j++)
 7             {
 8                    compexch(a[j],a[j+1]);
 9             }
10       }  
11 }
12 void BubbleSort(Item a[],int left,int right)
13 {
14       int i = 0,j = 0;
15       for(i = left; i < right; i++) 
16       {
17             for(j = right;j > i; j--)
18             {
19                    compexch(a[j-1],a[j]);
20             }
21       }  
22 }

2.2 快速排序

  記得有誰說過,快速排序是在冒泡排序的基礎上的,這個,我信了。

      快速排序的中心思想:在我看來快速排序的中心思想是很簡單的,我不知道快排的發明人是怎么想出來的。

      快排的思想是,選擇數組中的一個數,把它放到排序結束后它應該在的位置。

      這是一句很有意思的話,我怎么知道一個數排序結束后它在哪呢?其實可以知道的,

      我們希望一次排序結束后,這個數左邊的所有數都比這個數小,這個數右邊所有的數都比這個數大。

      然后我們對它的左邊用快排,然后對他的右邊用快排。

      最原始的寫法是這樣的。

 1 int partition(int * a,int l,int r)
 2 {
 3     int i = l-1,j = r;
 4     int v = a[r];
 5     for(;;)
 6     {
 7         while(a[++i] < v);
 8         while(v < a[--j])
 9             if(j == l)
10             break;
11         if(i >= j)
12             break;
13         EXCH(a[i],a[j]);
14     }
15     EXCH(a[i],a[r]);
16     return i;
17 }
18 void QuickSort(int * a,int l,int r)
19 {
20     int i;
21     if(r <= l)
22         return;
23     i = partition(a,l,r);
24     QuickSort(a,l,i-1);
25     QuickSort(a,i+1,r);
26 }

  partition函數的中心思想:partition函數的功能,就是從數組中選取一個數,然后讓左邊的全部小於它,右邊的全部大於它,然后返回位置就行了。

但是上面的partition真是大有問題,在正序和逆序的時候,很多人都哭了,所以常見的做法是,選取的這個數是隨機選取的。

一個或許可能的解決方案是這個,(我又空手敲代碼了,我有可能寫出來嗎?)(沒有,我又看了好多資料,調試了好久。)

int partition(int * a,int l,int r)
{
    int i = l-1;
    int j = r;
    int m = l+rand()%(r-l+1);
    EXCH(a[m],a[r]);
    int v = a[r];
    for(;;)
    {
        while(a[++i] < v);
        while(v < a[--j])
            if(j == l)
                break;
        if(i >= j)
            break;
        EXCH(a[i],a[j]);
        PrintArray(a);
    }
    EXCH(a[i],a[r]);
    PrintArray(a);
    return i;
}

 2.3 插入排序

       或許,我根本不適合學習算法,還是放棄吧,寫完這一章。

       插入排序的中心思想:我是這樣理解的,待排序項一直左移,已經排好的一直右移,直到某一項小於待排序項。

       從第二項開始一直執行這樣的操作。

       缺點:數組移動。

 1 void InsertSort(int * a,int l,int r)
 2 {
 3      for(int i = l+1;i < r; i++)
 4      {
 5            int j = i;
 6            int v = a[j];
 7            while(--j >= 0)
 8            {
 9                  if(v < a[j])
10                  {
11                       a[j+1] = a[j];
12                  }
13                  else
14                  {
15                        break;
16                  }
17            }
18            ++j;
19            a[j] = v;
20            PrintArray(a);
21      }
22 }

2.4 希爾排序

      希爾排序是分組的插入排序,

      划分公式可以是n*x+1,一個划分可能的划分是1 4 7 10 13 16,另一個可能的划分是1 5 9 13 17 21。

2.5 選擇排序

      選擇排序,首先選取數組第一小元素放到第一項,數組第二小的元素放到第二項。

      

void Array::SelectSort()
{
    int i = 0;
    int j = 0;
    for(i = 0; i < 10; i++)
    {
        int min = i;
        for(j = i+1;j < 10; j++)
        {
            if(first[j] < first[min])
            {
                min = j;
            }
        }
        first[i].Exchange(first[min]);
    }
}

 

2.6 歸並排序

      歸並排序和快速排序的形式相反,兩個遞歸之后跟一個歸並函數。

      歸並函數的要點是,對已經排序過的數組進行排序。可以原位歸並,或者借助一個數組。

      下面的代碼來自《C算法》不知道打錯了沒有。

 1 void mergesort(Item * a,int l,int r)
 2 {
 3      int m = (r+l)/2;
 4      if(r <= l)
 5      {
 6            mergesort(a,l,m);
 7            mergesort(a,m+1,r);
 8            merge(a,l,m,r);
 9      }
10 }
11 merge(Item * a, int l, int m, int r)
12 {
13      int i,j,k;
14      for(i = m+1; i > l; i--)
15           aux[i-1] = a[i-1];
16      for(i = m; j < r;j++)
17           aux[r+m-j] = a[j+1];
18      //上面兩行代碼,為的是生成bitonic序列,下面才是排序開始。
19      for(k = l; k < r;k++)
20           if(less(aux[j],aux[i]))
21                a[k] = aux[j--];
22           else
23                a[k] = aux[i++];
24 }

 

第三章:總結

心有千千結,心思總難知,這篇文章僅僅為心中自證,不是算法教學,也不想誤人子弟,謝謝各位。  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM