10.4 选择排序
Selection Sort的基本思想是:每一趟在n-i+1(i=1, ... ,n-1)个记录中选取最小的记录作为有序序列中第i个记录。
1: Simple Selection Sort
2: void SelectSort (SqList &L)
3: for (i = 1; i < L.length; ++i)
4: {
5: j = SelectMinKey(L, i);
6: if (i != j) Swap(L.r[i], L.r[j]);
7: }
8: }
能否改进?选择排序主要进行的是关键字间的比较,考虑如何减少比较?在n个关键字中选出最小值,至少需要n-1 次比较,继续在剩下的n-1 个关键字中选择次小值可以考虑如何利用上一次比较所得的信息。
实例:锦标赛,8名运动员决出前3名至多需要11场比赛,而不是7+6+5=18 场比赛(前提,甲胜已,已胜丙,则甲一定胜丙)
树形选择排序(Tree Selection Sort),又称锦标赛排序(Tournament Sort)
首先,选择最小关键字,对n个关键字两两比较,在其中n/2 个较小的之间再两两比较,如此重复,选出最小关键字。
然后,选择次小关键字,将以前最小关键字所在的叶子结点值写改为MAX,比较,修改,的次小关键字。
最后,重复,得排序。
Tree Selection Sort 时间复杂度O(nlogn),但是有所需存储空间较多,和“最大值”进行多余的比较等缺点,于是就有了堆排序(1964 J.willioms)
堆的定义 如下:n个元素的序列{k1, ... , kn}当且仅当满足如下关系时,称为堆。
ki <= k2i ki >= k2i
ki <= k2i+1 或 ki >= k2i+1
输出堆顶元素后,使剩余的n-1 个元素的序列重又建成一个堆,则得次小(大)元素,如此反复,得到一个有序序列,这个过程称之为堆排序。
实现堆排序需要解决的两个问题:1,如何由一个无序序列建成一个堆?2,如何在输出堆顶元素之后调整剩余元素成为一个新的堆。可以考虑先解决第二个问题,而从一个无序序列建堆的过程就是一个反复筛选的过程,!!!若将一个序列看成一个完全二叉树,则最后一个非终端节点是第n/2个元素,由此,筛选从第n/2个元素开始。
算法描述如下:
1: typedef SqList HeapType //堆采用顺序表存储表示
2: void HeapAdjust(HeapType &H, int s, int m)
3: {
4: //已知H.r[s...m]中记录的关键字除H.r[s].key外均满足堆的定义,本函数调整H.r[s]的关键字,
5: //使H.r[s...m]成为一个大顶堆(对其记录的关键字而言)
6: rc = H.r[s];
7: for (j = 2 * s; j <= m; j *= 2)
8: {
9: //沿key较大的孩子结点向下筛选
10: if (j < m && LT(H.r[j].key, H.r[j+1].key)) ++j; //j为key较大的记录的下标
11: if (!LT(rc.key, H.r[j].key)) break; //rc应插入在位置s上
12: H.r[s] = H.r[j]; s = j;
13: }
14: H.r[s] = rc; //插入
15: }
16: void HeapSort(HeapType &H)
17: {
18: for (i = H.length/2; i > 0; --i)
19: HeapAdjust(H, i, H.length);
20: for (i = H.length; i > 1; --i)
21: {
22: Swap(H.r[1], H.r[i]);
23: HeapAdjust(H, 1, i - 1);
24: }
25: }
堆排序方法对记录较少的文件不值得提倡,因为其运行时间主要耗费在建立初始堆时进行的反复筛选上,其时间复杂度最坏为O(nlogn),排序时仅需一个记录大小供交换用的辅助空间。
具体实例:
1: #include <stdio.h>
2: typedef int InfoType;
3:
4: #define EQ(a, b) ((a) == (b))
5: #define LT(a, b) ((a) < (b))
6: #define LQ(a, b) ((a) <= (b))
7:
8: #define MAXSIZE 20
9: typedef int KeyType;
10: typedef struct
11: {
12: KeyType key;
13: InfoType otherinfo;
14: }RedType;
15: typedef struct
16: {
17: RedType r[MAXSIZE+1]; //r[0]闲置或作哨兵
18: int length;
19: }SqList;
20:
21: typedef SqList HeapType;
22: void HeapAdjust (HeapType *H, int s, int m)
23: {
24: RedType rc;
25: int j;
26: rc = (*H).r[s];
27: for (j = 2*s; j <= m; j *= 2)
28: {
29: if (j < m && LT((*H).r[j].key, (*H).r[j+1].key)) ++j;
30: if (!LT(rc.key, (*H).r[j].key))
31: break;
32: (*H).r[s] = (*H).r[j];
33: s = j;
34: }
35: (*H).r[s] = rc;
36: }
37: void HeapSort(HeapType *H)
38: {
39: RedType t;
40: int i;
41: for (i = (*H).length/2; i > 0; --i)
42: HeapAdjust(H, i, (*H).length);
43: for (i = (*H).length; i > 1; --i)
44: {
45: t = (*H).r[1];
46: (*H).r[1] = (*H).r[i];
47: (*H).r[i] = t;
48: HeapAdjust(H, 1, i-1);
49: }
50: }
51: void print(HeapType H)
52: {
53: int i;
54: for(i = 1; i <= H.length; ++i)
55: printf("(%d, %d)", H.r[i].key, H.r[i].otherinfo);
56: printf("\n");
57: }
58: #define N 8
59: int main()
60: {
61: RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8}};
62: HeapType h;
63: int i;
64: for (i = 0; i < N; ++i)
65: h.r[i+1] = d[i];
66: h.length = N;
67: printf("排序前:\n");
68: print(h);
69: HeapSort(&h);
70: printf("排序后:\n");
71: print(h);
72: return 0;
73: }