7.4选择类排序
算法思想:每一趟(例如第i趟)在后面n-i+2(i=1,2,3,…,n-1)个待排序的元素中选取关键字最小的元素,作为有序子序列的第i个元素,直到第n-1趟做完,待排序的元素只剩一个,就不用再选了。
包括简单排序和堆排序。
简单排序:
void SelctSort(ElemType A[],int n){
for(int i=0;i<n-1;i++){ //依次从后面的序列中选择当前最小元素作为第i个元素,最后一个元素不用排
min=i;
for(int j=i+1;j<n;j++) //从第i个元素往后找,一直找到最后一个元素
if(A[j]<A[min])
min=j;
if(min!=i){
ElemType temp =A[i];
A[i]=A[ming];
A[min]=temp;
}
}
}
算法分析:
堆排序:
什么是堆排序:我们知道对于对于一个堆来说,他的根结点是整个堆中所有结点的值的最大值(大顶堆)或者
最小值(小顶堆),所以堆排序的思想就是每次将无序序列调节成一个堆,然后在堆中选择堆顶元素的值,把这个值加入有序序列,无序序列减少一个,再反复调节无序序列,直到所有的关键字都加入到有序序列。
算法思想:
1)建堆:堆初始序列的完全二叉树调整成一个大顶堆
调整方法:二叉树由下至上由左至又(数组的下标又大到小),检查每个结点是否满足大顶堆的要求,如果不满足进行调整。
2)将堆顶结点和最后一个结点19交换,也就是将最大值92移动到数组的最末尾,有序序列中加入了结点92,无序序列减少结点92到这了堆排序的第一趟完成。
3)调堆:调整二叉树的结点是的满足大顶堆的要求。调整方法和建堆一样。
4)重复上述过程,直到排完。
算法流程:设最后一个结点编号为N,N等于二叉树中结点数量,它肯定是叶子结点。所以第一个可能需要调整的非叶子结点的下标为[N/2],从他的右孩子开始检查,它的左孩子下标为[N/2]*2如果发生交换,下一轮检查交换过结点的左右孩子。
算法代码:
/*建堆*/:
void BuildMaxHeap(ElemType A[],int len){
for(int i=len/2;i>0;i--) //从第一个可能需要调整过的非叶子结点开始检查,直到根结点(注意根结点的下标不是0,是从1开始存储的)
AdjustDown(A,i,len);
}
/*调整堆*/
void AdjustDown(ElemType A[],int k,int len){ //A是存储的数组,K需要检查的结点下标,Len是堆中结点的个数
A[0]=A[k]; //A[]暂存这个需要检查的结点值
for(i=2*k;i<=len;i*=2){
if(i<len&&A[i]<A[i+1])
i++;
if(A[0]>A[i])
break;
else{
A[K]=A[i];
k=i;
}
}
A[K]=A[0];
}
/*堆排序算法*/
void HeapSort(ElemType A[],int len){
BuildMaxHeap(A.len);
for(i=len,i>1;i--){
//输出堆顶元素(和堆底元素交换)
ElemType temp =A[i];
A[i]=A[1];
A[1]=temp;
printf(A[i]);
AdjustDown(A,1,i-1); //把剩余的i-1个元素整理成新的大顶堆
}
}
算法分析: