選擇類排序

選擇類排序的基本思想是每一趟在n-(i-1)個待排序的記錄中選取一個關鍵字最小的記錄做爲有序序列中的第i個記錄。經常使用的選擇類排序法有簡單選擇排序和堆排序。算法

1.簡單選擇排序

簡單選擇排序是對選擇類排序基本思想的直接實現。在第一趟排序中,從第一個記錄開始在待排序的n個記錄中選擇一個最小的記錄,並和第一個記錄做交 換;在第二趟排序中,從第二個記錄開始從待排序的n-1個記錄中選擇一個最小的記錄,並和第二個記錄作交換。依次類推,第i趟排序過程即從第i個元素開始 在待排序的n-(i-1)個元素中選擇一個最小的記錄,並和第i個記錄做交換。數組

1 void selectSort(int *r, int length)
2 {
3     int i, j, k, n;
4  
5     n = length;
6  
7     for ( i = 1; i <= n - 1; i++) {
8         k = i;
9  
10         for ( j = i + 1; j <= n; j++)
11             if (r[j] < r[k])
12                 k = j;
13         if ( k != i) {
14             r[0] = r[i];
15             r[i] = r[k];
16             r[k] = r[0];
17         }
18     output(r, length);
19     }
20 }

在具體實現時,外部循環用來控制總的排序趟數,而內部循環用於在剩餘待排序記錄中挑選一個最小的記錄。在每一趟排序中,使用k記錄最小記錄的索引。code

2.堆排序

堆排序將一維的待排序記錄按照徹底二叉樹的形式進行組織,並利用徹底二叉樹中父節點和孩子節點之間的關係來選擇記錄,最終達到排序的目的。堆排序只 是利用了徹底二叉樹的特性,待排序記錄仍然採用一維數組進行存儲,而非採用樹的存儲結構。 堆排序的算法思想是將待排序的記錄r[1,n]看做是一棵徹底二叉樹,將記錄1做爲徹底二叉樹的根節點,記錄中的其餘元素依次逐層從左至右順序排序。首先 將該徹底二叉樹調整爲大根堆(最終排列成遞減序列),也就是建立堆的過程;接着,將根元素從二叉樹中移除並做爲有序記錄集合中的第一個元素,同時再次調整 該二叉樹讓其造成另外一個大根堆。不斷重複上述過程直到該徹底二叉樹爲空。實現代碼以下:排序

1 void heapSort(int *r, int length)
2 {
3     int i, n;
4     int t;
5  
6     create_heap(r, length);
7  
8     n = length;
9  
10     for ( i = n; i >= 2; i--) {
11         t = r[1];
12         r[1] = r[i];
13         r[i]= t;
14         adjust_heap(r, 1, i - 1);
15         output(r, length);
16     }
17 }

在具體的實現堆排序時,一般是將堆頂元素和堆尾元素進行交換,再次調整剩餘待排序的元素造成堆。第i趟排序是將堆頂元素r[1]和堆尾元素r[n-i+1]進行交換,此時序列r中後i個元素是有序的。索引

堆的建立就是自底向上逐層調整該徹底二叉樹的子樹。對於n個元素的記錄來講,先將以第n/2個元素爲根的子樹調整爲大根堆,再將以n/2-1個元素爲根的子樹調整爲大根堆,按照逐層自底向上的順序,直到根節點。table

1 void create_heap(int *r, int length)
2 {
3     int i, n;
4  
5     n = length;
6  
7     for ( i = n / 2; i >= 1; i--)
8         adjust_heap(r, i, n);
9 }

整個堆排序的核心算法是調整堆,其中r[k,m]是一個以k元素爲根的徹底二叉樹,該算法將此二叉樹調整爲堆。具體實現時,用r[0]備份當前二叉 樹的根元素,用j表示i元素的左孩子。算法中使用循環不斷將二叉樹調整爲堆,它首先肯定i節點的兩個孩子中的較大值,再進一步判斷是否須要與根節點進行交 換。若是根節點大於i節點較大的那個孩子節點j,整個調整過程結束,由於此時該二叉樹就是一個堆。不然將這個較大值的孩子j移到節點i處,接下來以j爲根 節點繼續如上考察它的兩個孩子節點的大小。class

1 void adjust_heap(int *r, int k, int m)
2 {
3     int i, j, t;
4     int finished;
5  
6     r[0] = r[k];
7     i = k;
8     j = 2 * i;
9  
10     finished = 0;
11  
12     while (j <= m && !finished) {
13         if (j < m && r[j] < r[j + 1])
14             j++;
15         if (r[0] >= r[j])
16             finished = 1;
17         else {
18             r[i] = r[j];
19             i = j;
20             j = 2 * i;
21         }
22     }
23  
24     r[i] = r[0];
25 }

整個調整堆的過程是由根節點逐步向下篩選的過程。select

相關文章
相關標籤/搜索