1.简单选择排序
基本思想:
(1)初始状态:整个数组 r 划分成两个部分,即有序区(初始为空)和无序区。(2)基本操作:从无序区中选择关键字值最小的记录,将
其与无序区的第一个记录交换(实质是添加到有序区尾部)。
从初态(有序区为空)开始,重复步骤(2),直到终态
(无序区为空)。
排序过程
首先通过 n-1 次关键字比较,从n 个记录中找出关
键字最小的记录,将它与第一个记录交换;
再通过 n-2次比较,从剩余的 n-1 个记录中找出关
键字次小的记录,将它与第二个记录交换;
重复上述操作,共进行n-1趟 排序后,排序结束。
算法:
void Selectsort()
{ for (i=1;i<n;i++)
{ k=i;
for (j=i+1;j<=n;j++)
if (R[j].key<R[k].key) // 选择关键字值最小的记录
k=j;
if ( k!=i )
{ R[0]=R[i];
R[i]=R[k];
R[k]=R[0];
} // 交换记录
}
}
效率分析:
简单选择排序比较次数与关键字初始排序无关。
找第一个最小记录需进行n-1次比较,找第二个最小记录需要比较n-2次,找第i个最小记录需要进行n-i次比较,总的比较次数为:
(n-1)+(n-2)+……+(n-i)+……2+1=n(n-1)/2=n2/2
时间复杂度:O(n2)
辅助空间:O(1)
简单选择排序是不稳定的排序方法。
2. 堆排序
堆排序法是利用堆树(Heap Tree)来进行排序的方法,堆树是一种特殊的二叉树,其具备以下特征:(1)是一棵完全二叉树。
(2)每一个根结点的值均大于或等于它的两个子结点的值。
(3)树根的值是堆树中最大的。
基本思想:
(1)把用数组存储的待排序数据,转换成一棵完全二叉树。(2)将完全二叉树转换成堆树。
(3)有了堆树后,便可以排序。
例:输入数据序列为:80 13 6 88 27 75 42 69
分析其堆排序的过程。
(1)画出完全二叉树
位置(i) 1 2 3 4 5 6 7 8
一维数组中的数据 80 13 6 88 27 75 42 69
对于任一位置,若父结点的位置为i ,则它的两个子结点分别
位于 2i 和 2i+1 。 根据数组中的数据可画出如图所示的完全二叉树。
(2)建堆过程
1) 从数组中间开始调整。2) 找出此父结点的两个子结点的较大者,再与父结点比较,若父结点小,则交换。然后以交换后的子结点作为新的父结点,重复此步骤直到没有子结点。
3) 把步骤 2)中原来的父结点的位置往前推一个位置,作为新的父结点。重复步骤 2),直到树根为止。
(3) 实现堆排序:
堆排序:将无序序列建成一个堆,得到关键字最大(或最小)
的记录;输出堆顶的最大(小)值后, 使剩余的 n-1个元素重又
建成一个堆,则可得到n 个元素的次大(小)值;重复执行,得
到一个有序序列。
实现堆排序要解决的一个问题:
即输出堆顶元素后,怎样调整剩余的 n-1个元素,使其按关
键码成为一个新堆。
调整方法:
设有m个元素的堆,输出堆顶元素后,剩下m-1个元素。
将堆底元素送入堆顶,堆被破坏,其原因仅是根结点不满
足堆的性质。将根结点与左、右子女中较大的进行交换。
若与左子女交换,则左子树堆被破坏,且仅左子树的根结
点不满足堆的性质;若与右子女交换,则右子树堆被破坏,
且仅右子树的根结点不满足堆的性质。继续对不满足堆性
质的子树进行上述交换操作,直到叶子结点,堆被建成。
称这个自根结点到叶子结点的调整过程为筛选。
此过程的输出序列为从大到小。
其过程如图所示:
调整方法:
输出堆顶元素之后,以堆中最后一个元素替代之;然后将根结
点值与左、右子树的根结点值进行比较,并与其中小者进行交换;
重复上述操作,直至叶子结点,将得到新的堆,称这个从堆顶至
叶子的调整过程为筛选。
此过程的输出序列为从小到大。
算法:
void HeapAdjust (S_TBL *h,int s,int m) { //a[s…m]中的记录关键码除a[s]外均满足堆的定义,本函数 将对第s个结点为根的子树筛选,使其成为大顶堆 ac=h->a[s]; for (j=2*s;j<=m;j=j*2) //沿关键码较大的子女结点向下筛选 { if (j<m&&h->a[j].key<h->a[j+1].key) j=j+1; //为关键码较大的元素下标 if (ac.key<h->a[j].key) baeak; // ac应插入在位置s上 h->a[s]=h->a[j]; s=j; // 使s结点满足堆定义 } h->a[s]=ac; // 插入 }
void HeapSoat (S_TBL *h) { for (i=h->length/2;i>0;i- -) // 将a[1..length]建成堆 HeapAdjust (h,i,h->length); for (i=h->length;i>1;i- -) { h->a[1]<-->h->a[i]; // 堆顶与堆低元素交换 HeapAdjust (h,1,i-1); // 将a[1..i-1]重新调整为堆 } }
算法评价:
时间复杂度:最好、坏情况下T(n)=O(nlogn)----n较大时比较有效
空间复杂度:S(n)=O(1)
堆排序为不稳定排序。