选择排序的主要操作是选择,其主要思想是:每趟排序在当前待排序序列中选出关键码最小的记录,添加到有序序列中。
简单选择排序
基本思想:第i 趟在n-i+1(i=1,2,…,n-1)个记录中选取关键码最小的记录作为有序序列中的第i个记录。
关键问题⑴:如何在无序区中选出关键码最小的记录?
解决方法:
设置一个整型变量index,用于记录在一趟比较的过程中关键码最小的记录位置。
关键问题⑵:如何确定最小记录的最终位置?
解决方法:
第i趟简单选择排序的待排序区间是r[i] ~ r[n],则r[i]是无序区第一个记录,所以,将index所记载的关键码最小的记录与r[i]交换。
void selectSort ( int r[ ], int n)
{
for ( i=1; i<n; i++)
{
index=i;
for (j=i+1; j<=n; j++)
if (r[j]<r[index]) index=j;
if (index!=i) r[i]<==>r[index];
}
}
**堆排序**
堆是具有下列性质的完全二叉树:每个结点的值都小于或等于其左右孩子结点的值(称为小根堆),或每个结点的值都大于或等于其左右孩子结点的值(称为大根堆)。
基本思想
首先将待排序的记录序列构造成一个堆(大顶堆),
此时,选出了堆中所有记录的最大者,然后将它从堆中移走,
将剩余的记录再调整成堆,
这样又找出了次大的记录,以此类推,直到堆中只有一个记录。
堆调整:在一棵完全二叉树中,根结点的左右子树均是堆,如何调整根结点,使整个完全二叉树成为一个堆?
void sift ( int r[ ], int k, int m )
{//要筛选结点的编号为k,堆中最后一个结点的编号为m
i=k; j=2*i; temp=r[i]; //将筛选记录暂存
while (j<=m ) //筛选还没有进行到叶子
{
if (j<m && r[j]<r[j+1]) j++; //左右孩子中取较大者
if (temp>r[j]) break;
else {
r[i]=r[j]; i=j; j=2*i;
}
}
r[i]=temp; //将筛选记录移到正确位置
}
关键问题⑴:如何由一个无序序列建成一个堆?
最后一个结点(叶子)的序号是n,
则最后一个分支结点即为结点n的双亲,
其序号是n/2。
算法描述:
for (i=n/2; i>=1; i--)
sift(r, i, n) ;
关键问题⑶:如何调整剩余记录,成为一个新堆?
解决方法:
第 1 次调整剩余记录,此时,剩余记录有?个,调整范围?
第 i 次调整剩余记录,此时,剩余记录有n-i个,调整根结点至第n-i个记录。
算法描述:
sift(r, 1, n-i);
建堆:O(n)
删除堆顶的调整:O(log2n)
一次建堆 ,n次删除堆顶
总时间代价为O(nlog n)
空间代价为O(1)
void HeapSort ( int r[], int n)
{
for (i=n/2; i>=1; i--)
sift(r, i, n) ;
for (i=1; i>n; i++ )
{
r[1]←→r[n-i+1];
sift(r, 1, n-i);
}
}
本文详细介绍了选择排序和堆排序两种算法的工作原理。选择排序通过每趟选择最小元素来构建有序序列;堆排序利用堆的数据结构特性,先构造堆,然后每次删除堆顶元素。两种排序算法的时间复杂度分别为O(n^2)和O(nlog n),空间复杂度为O(1)。
18万+

被折叠的 条评论
为什么被折叠?



