以下code 来源于 啊哈磊大神~ =-=
你可以百度 --- 啊哈磊 ---
都是 关于heap的一些操作...
向下调整:->
1 void siftdown(int i) //传入一个需要向下调整的结点编号i,这里传入1,即从堆的顶点开始向下调整 2 { 3 int t,flag=0;//flag用来标记是否需要继续向下调整 4 //当i结点有儿子的时候(其实是至少有左儿子的情况下)并且有需要继续调整的时候循环窒执行 5 while( i*2<=n && flag==0 ) 6 { 7 //首先判断他和他左儿子的关系,并用t记录值较小的结点编号 8 if( h[ i] > h[ i*2] ) 9 t=i*2; 10 else 11 t=i; 12 //如果他有右儿子的情况下,再对右儿子进行讨论 13 if(i*2+1 <= n) 14 { 15 //如果右儿子的值更小,更新较小的结点编号 16 if(h[ t] > h[ i*2+1]) 17 t=i*2+1; 18 } 19 //如果发现最小的结点编号不是自己,说明子结点中有比父结点更小的 20 if(t!=i) 21 { 22 swap(t,i);//交换它们,注意swap函数需要自己来写 23 i=t;//更新i为刚才与它交换的儿子结点的编号,便于接下来继续向下调整 24 } 25 else 26 flag=1;//则否说明当前的父结点已经比两个子结点都要小了,不需要在进行调整了 27 } 28 }
向上调整:->
1 void siftup(int i) //传入一个需要向上调整的结点编号i 2 { 3 int flag=0; //用来标记是否需要继续向上调整 4 if(i==1) return; //如果是堆顶,就返回,不需要调整了 5 //不在堆顶 并且 当前结点i的值比父结点小的时候继续向上调整 6 while(i!=1 && flag==0) 7 { 8 //判断是否比父结点的小 9 if(h[ i]<h[ i/2]) 10 swap(i,i/2);//交换他和他爸爸的位置 11 else 12 flag=1;//表示已经不需要调整了,当前结点的值比父结点的值要大 13 i=i/2; //这句话很重要,更新编号i为它父结点的编号,从而便于下一次继续向上调整 14 } 15 }
的确 很 易懂
两种方式对元素 进行堆排序:->
1 #include <stdio.h> 2 int h[ 101];//用来存放堆的数组 3 int n;//用来存储堆中元素的个数,也就是堆的大小 4 5 6 //交换函数,用来交换堆中的两个元素的值 7 void swap(int x,int y) 8 { 9 int t; 10 t=h[ x]; 11 h[ x]=h[ y]; 12 h[ y]=t; 13 } 14 15 16 //向下调整函数 17 void siftdown(int i) //传入一个需要向下调整的结点编号i,这里传入1,即从堆的顶点开始向下调整 18 { 19 int t,flag=0;//flag用来标记是否需要继续向下调整 20 //当i结点有儿子的时候(其实是至少有左儿子的情况下)并且有需要继续调整的时候循环窒执行 21 while( i*2<=n && flag==0 ) 22 { 23 //首先判断他和他左儿子的关系,并用t记录值较小的结点编号 24 if( h[ i] > h[ i*2] ) 25 t=i*2; 26 else 27 t=i; 28 //如果他有右儿子的情况下,再对右儿子进行讨论 29 if( i*2+1 <= n) 30 { 31 //如果右儿子的值更小,更新较小的结点编号 32 if(h[ t] > h[ i*2+1]) 33 t=i*2+1; 34 } 35 //如果发现最小的结点编号不是自己,说明子结点中有比父结点更小的 36 if(t!=i) 37 { 38 swap(t,i);//交换它们,注意swap函数需要自己来写 39 i=t;//更新i为刚才与它交换的儿子结点的编号,便于接下来继续向下调整 40 } 41 else 42 flag=1;//则否说明当前的父结点已经比两个子结点都要小了,不需要在进行调整了 43 } 44 } 45 46 47 //建立堆的函数 48 void creat() 49 { 50 int i; 51 //从最后一个非叶结点到第1个结点依次进行向上调整 52 for(i=n/2;i>=1;i--) 53 { 54 siftdown(i); 55 } 56 } 57 58 59 //删除最小的元素 60 int deletemin() 61 { 62 int t; 63 t=h[ 1];//用一个临时变量记录堆顶点的值 64 h[ 1]=h[ n];//将堆得最后一个点赋值到堆顶 65 n--;//堆的元素减少1 66 siftdown(1);//向下调整 67 return t;//返回之前记录的堆得顶点的最小值 68 } 69 70 71 int main() 72 { 73 int i,num; 74 //读入数的个数 75 scanf("%d",&num); 76 77 78 for(i=1;i<=num;i++) 79 scanf("%d",&h[ i]); 80 n=num; 81 82 //建堆 83 creat(); 84 85 //删除顶部元素,连续删除n次,其实也就是从小到大把数输出来 86 for(i=1;i<=num;i++) 87 printf("%d ",deletemax()); 88 getchar(); 89 getchar(); 90 return 0; 91 }
1 #include <stdio.h> 2 int h[ 101];//用来存放堆的数组 3 int n;//用来存储堆中元素的个数,也就是堆的大小 4 5 6 //交换函数,用来交换堆中的两个元素的值 7 void swap(int x,int y) 8 { 9 int t; 10 t=h[ x]; 11 h[ x]=h[ y]; 12 h[ y]=t; 13 } 14 15 16 //向下调整函数 17 void siftdown(int i) //传入一个需要向下调整的结点编号i,这里传入1,即从堆的顶点开始向下调整 18 { 19 int t,flag=0;//flag用来标记是否需要继续向下调整 20 //当i结点有儿子的时候(其实是至少有左儿子的情况下)并且有需要继续调整的时候循环窒执行 21 while( i*2<=n && flag==0 ) 22 { 23 //首先判断他和他左儿子的关系,并用t记录值较大的结点编号 24 if( h[i] < h[i*2] ) 25 t=i*2; 26 else 27 t=i; 28 //如果他有右儿子的情况下,再对右儿子进行讨论 29 if( i*2+1 <= n) 30 { 31 //如果右儿子的值更大,更新较小的结点编号 32 if(h[t] < h[ i*2+1]) 33 t=i*2+1; 34 } 35 //如果发现最大的结点编号不是自己,说明子结点中有比父结点更大的 36 if(t!=i) 37 { 38 swap(t,i);//交换它们,注意swap函数需要自己来写 39 i=t;//更新i为刚才与它交换的儿子结点的编号,便于接下来继续向下调整 40 } 41 else 42 flag=1;//则否说明当前的父结点已经比两个子结点都要大了,不需要在进行调整了 43 } 44 } 45 46 47 //建立堆的函数 48 void creat() 49 { 50 int i; 51 //从最后一个非叶结点到第1个结点依次进行向上调整 52 for(i=n/2;i>=1;i--) 53 { 54 siftdown(i); 55 } 56 } 57 58 59 //堆排序 60 void heapsort() 61 { 62 while( n>1 ) 63 { 64 swap(1,n); 65 n--; 66 siftdown(1); 67 } 68 } 69 70 71 int main() 72 { 73 int i,num; 74 //读入n个数 75 scanf("%d",&num); 76 77 78 for(i=1;i<=num;i++) 79 scanf("%d",&h[ i]); 80 n=num; 81 82 83 //建堆 84 creat(); 85 86 87 //堆排序 88 heapsort(); 89 90 91 //输出 92 for(i=1;i<=num;i++) 93 printf("%d ",h[i]); 94 95 getchar(); 96 getchar(); 97 return 0; 98 }
// 这里的 swap 使用 引用传递形参值 更好
真正理解一个东西 你可以将它以很简单的方式 讲解出来~