选择排序的基本思想是:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子表的最后,直到全部记录排序完毕。
两种选择排序方法:(1)简单选择排序(或称直接选择排序)(2)堆排序
一、直接选择排序
基本思想:第i趟排序开始时,当前有序区和无序区分别为R[0..i-1]和R[i..n-1](0≤i<n-1),该趟排序则是从当前无序区中选出关键字最小的记录R[k],将它与无序区的第1个记录R[i]交换,使R[0..i]和R[i+1..n-1]分别变为新的有序区和新的无序区。
void SelectSort(RecType R[],int n)
{ int i,j,k; RecType temp;
for (i=0;i
for (j=i+1;j
if (k!=i) //交换R[i]和R[k]
{ temp=R[i]; R[i]=R[k]; R[k]=temp; }
}
}
例1 设待排序的表有10个记录,其关键字分别为{6,8,7,9,0,1,3,2,4,5}。说明采用直接选择排序方法进行排序的过程。
对 n 个记录进行简单选择排序,所需进行的 关键字间的比较次数 总计为:
二、堆排序
堆排序是一树形选择排序,它的特点是,在排序过程中,将R[1..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录。
堆的定义是:n个关键字序列K1,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):
(1)Ki≤K2i 且 Ki≤K2i+1 或
(2)Ki≥K2i 且 Ki≥K2i+1(1≤i≤n/2)
满足第(1)种情况的堆称为小根堆,满足第(2)种情况的堆称为大根堆。下面讨论的堆是大根堆。
例如:{12, 36, 27, 65, 40, 34, 98, 81, 73, 55, 49}是小根堆
调整堆:完全二叉树的左右子树都满足堆的条件、仅根节点不满足堆的条件
void sift(RecType R[],int low,int high) //调整堆的算法
{ int i=low,j=2*i; //R[j]是R[i]的左孩子}
堆排序:将根节点与最后的一个叶子节点顺序交换,交换后输出根节点,叶子节点作为根,调整进行下一轮排序
实现堆排序的算法如下:
void HeapSort(RecType R[],int n)
{ int i; RecType temp;
for (i=n/2;i>=1;i--) //循环建立初始堆
sift(R,i,n);
for (i=n;i>=2;i--) //进行n-1次循环,完成推排序
{ temp=R[1]; //将第一个元素同当前区间内R[1]对换
R[1]=R[i];R[i]=temp;
sift(R,1,i-1); //筛选R[1]结点,得到i-1个结点的堆
}
}
例2 设待排序的表有10个记录,其关键字分别为{6,8,7,9,0,1,3,2,4,5}。说明采用堆排序方法进行排序的过程。
排序:
1. 对深度为 k 的堆,“筛选”所需进行的关键字,比较的次数至多为2(k-1);
2. 对 n 个关键字,建成深度为h(=log2n+1)的堆,所需进行的关键字比较的次数不超过4n;
3. 调整“堆顶” n-1 次,总共进行的关键字比较的次数不超过
2 (log2(n-1)+ log2(n-2)+ …+log22) < 2n(log2n)
因此,堆排序的时间复杂度为O(nlogn)。