堆排序

xiaoxiao2021-02-28  90

堆排序


堆排序是什么? 堆是一种特殊的完全二叉树。

二叉树中有两种特殊的二叉树,一种是满二叉树,另一种是完全二叉树。满二叉树的每个结点都有两个儿子,也是满二叉树的所有叶子结点都有同样的深度。

而一颗二叉树除了最右边位置上有一个或者几个叶结点缺少外,其他是丰满的,那这样的二叉树就是完全二叉树。如果一个结点有右子结点,那它必定有左结点。

所有的父结点都比子结点都小,符合这样特点的完全二叉树称为最小堆。而所有的父结点都比子结点要大,这样的完全二叉树称为最大堆。 堆的操作有建堆、插入数,删除数等,但新增加数不符合最大最小堆的特性,就要将数调整到合适的位置。


堆调整的代码

向下调整的代码

void siftDown(int i)//传入一个向下调整的结点编号i从顶点开始向下调整 { int t,flag=0; while(i*2<=n && flag==0) { //判断结点和它的左右儿子用t记录值较小的结点编号 if(h[i]<h[i*2]) t=i*2; else t=i; if(i*2+1 <= n) { //如果右儿子的值更小,更新较小的结点编号 if(h[t] < h[i*2+1]) t=i*2+1; } if(t!=i) { Swap(t,i);//交换他们两个结点 i=t; } else flag=1; } return; }

向上调整的代码

void siftup(int i) { int flag=0; if(i==1) return; while(i!=1 && flag==0) { //判断是否比父结点小 if(h[i]<h[i/2]) swap(i,i/2); else flag=1; i=i/2; } return; }

完整堆排序代码: 以下为从小到大排序,利用最大堆做从小到大排序更好,最大堆建好之后,每次将顶部的最大值放在与末尾的数字交换位置,将第一个位置上的数字向下调整到符合最大堆,并且堆的长度在交换后就减一,则末尾的最大值不会再调整上来,循环到最后,就按照从小到大排列好了。同理,从大到小可以用最小堆来实现。

当然,也可以从小到大排列时用最小堆来实现,此时可以把堆顶元素拿出,也就是删除堆顶的操作,这时可以将末尾的元素拿上来,再调整使其符合堆的性质。

# include <stdio.h> int h[101]; int n; void Create(); void heapSorted(); void Swap(int x, int y) { int t; t=h[x]; h[x]=h[y]; h[y]=t; return; } void siftDown(int i)//传入一个向下调整的结点编号i从顶点开始向下调整 { int t,flag=0; while(i*2<=n && flag==0) { //判断结点和它的左右儿子用t记录值较小的结点编号 if(h[i]<h[i*2]) t=i*2; else t=i; if(i*2+1 <= n) { //如果右儿子的值更小,更新较小的结点编号 if(h[t] < h[i*2+1]) t=i*2+1; } if(t!=i) { Swap(t,i);//交换他们两个结点 i=t; } else flag=1; } return; } int main() { int i,num; printf("Please input the array's length.\n");//输入序列的长度 scanf("%d",&num); printf("Please input the numbers will be sorted.\n");//读入序列 for(i=1;i<=num;i++) scanf("%d",&h[i]); n=num; Create();//建堆 heapSorted();//堆排序 //输出排序好的序列 printf("The numbers have be sorted:\n"); for(i=1;i<=num;i++) printf("%d ",h[i]); return 0; } void Create() { int i; for(i=n/2;i>=1;i--) siftDown(i); return; } void heapSorted() { while(n>1) { Swap(1,n); n--; siftDown(1); } return; }

结果:

转载请注明原文地址: https://www.6miu.com/read-50047.html

最新回复(0)