一:算法介绍
堆是一种数据结构,可以看作是一可完全二叉树,这棵完全二叉树满足:所有的双亲节点都不大于(不小于)其左右孩子节点的值,叫做小顶堆(大顶堆);
(考虑递增排序)
假定我们要构造大顶堆,这棵完全二叉树的根节点就是当前序列中的最大值,根据这一思想我们就可以把当前序列执行堆排序,找到最大值,与当前序列的最后一个元素交换,再把除最后一个元素以外的序列执行堆排序,直到当前序列需要排序的就一个元素结束。
二:一次执行流程
原始序列
49 | 38 | 65 | 97 | 76 | 13 | 27 | 49 |
1:建堆
2:调整
从第一个非叶子节点开始(从右向左,从下向上)
① 调整 97 : 97 > 49 满足条件不需要。
② 调整 65 :65 > 13 65 >27 满足条件不需要。
③ 调整 38: 38 < 97 38 < 76,需要调整 (注:在这里值得一提的是有个小技巧,编程时如果按这样比较比较麻烦,所以在编程时我们这样考虑,如果该非叶子结点同时有左右孩子,则先比较左右孩子的值选最大值与该节点交换)。
交换后38是49的根节点又不满足定义,则在调整得到
④ 调整 49 :49<97 49 < 65 则最终调整为:
相信到这里小伙伴都看懂了将序列调整为堆的过程,下面就让我们代码实现一下。
三:代码实现
我们用到了一颗完全二叉树来进行对序列实现堆,对于完全二叉树的存储方式我们选用顺序存储结构,采用数组的方式。当我们用数组来表示完全二叉树时,数组的中i位置元素的左孩子在 2*i处(2*j小于元素个数) 右孩子在2*i+1处。所以这里的数组下标从1开始,下标0可以选择不用,还有根据完全二叉树的性质和该存储方式的特点我们很容易发现第一个非叶子结点在 n/2处(n是元素的个数,0处的元素不算)。如下:(8)n=length-1;
0 | 49 | 38 | 65 | 97 | 76 | 13 | 27 | 49 |
1 public class DuiSort { 2 3 public static void main(String[] args) { 4 5 int num[] = {0,49,38,65,97,76,13,27,49}; 6 7 for(int n = num.length-1; n>=1; n--){ 8 9 //一次堆排序 10 for(int i = n/2;i>=1 ; i--){ 11 shift(num,i,n); 12 } 13 //一次堆排序后将根节点与元素最后一个元素交换 14 int temp = num[n]; 15 num[n] = num[1]; 16 num[1] =temp; 17 18 } 19 for(int i = 1 ; i<=num.length-1;i++){ 20 System.out.print(num[i]+" "); 21 } 22 23 } 24 //将序列进行堆 25 private static void shift(int[] num, int low, int heigh) { 26 int i = low,j = 2*i; 27 int temp = num[i]; 28 while(j<=heigh){ 29 if(j<heigh && num[j] <num[j+1]){++j;} 30 if(num[j] > temp){ 31 num[i] = num[j]; 32 i = j; 33 j = 2*i; 34 } 35 else{ 36 break; 37 } 38 } 39 num[i] = temp; 40 } 41 }