選擇類排序的基本思想是每一趟在n-(i-1)個待排序的記錄中選取一個關鍵字最小的記錄做爲有序序列中的第i個記錄。經常使用的選擇類排序法有簡單選擇排序和堆排序。算法
簡單選擇排序是對選擇類排序基本思想的直接實現。在第一趟排序中,從第一個記錄開始在待排序的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
堆排序將一維的待排序記錄按照徹底二叉樹的形式進行組織,並利用徹底二叉樹中父節點和孩子節點之間的關係來選擇記錄,最終達到排序的目的。堆排序只 是利用了徹底二叉樹的特性,待排序記錄仍然採用一維數組進行存儲,而非採用樹的存儲結構。 堆排序的算法思想是將待排序的記錄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