学习参考:堆排序 Heap Sort、排序六 堆排序
堆结构:一棵完全二叉树。大根堆:K[ i ] < K[ 2i ] 、K[ i ] < K[ 2i+1 ] 。小根堆反之。
本文测试数据:《严奶奶数据结构》P281
由于笔者学业繁忙,没有编写使树形结构可视化的代码。各位读者请心中脑补。
- 堆调整函数:
1 protected void HeapAdjust(int [] nums,int a,int b){ 2 int i; 3 for(i=a;a<=b;){ 4 //左子树=根*2+1,右子树=根*2+2 5 int lPos=a*2+1; 6 int rPos=(a+1)*2; 7 //比较找出左右子树最小的一颗 8 int min=nums[a];//根结点 9 int nextPos=lPos;//下一个转向的树 10 boolean isSwaped=false; 11 if(lPos<=b && nums[lPos]<min){ 12 nextPos=lPos; 13 min=nums[lPos]; 14 isSwaped=true; 15 } 16 if(rPos<=b && nums[rPos]<min){ 17 nextPos=rPos; 18 isSwaped=true; 19 } 20 if(!isSwaped) break; 21 swap(nums,a,nextPos); 22 a=nextPos; 23 } 24 }
函数描述:这个函数用于【建堆】、【筛选】两个操作。在这个函数中,对数组【a,b】中的元素进行处理,其认为除了“a”,在【a+1,b】中的元素都是满足{堆结构}的定义的。
1.求出左右子树的下标 2.进行比较,在左右子树存在的情况下,获得值最小的子树(这个值最小的子树,它的值要比根节点的值小) 3.如果没有这样的子树,跳出循环。 有的话,转到子树进行操作,回到 1 进行循环。
- 建堆
1 //建堆 2 for(i=len/2-1;i>=0;i--){ 3 HeapAdjust(nums,i,len-1); 4 }
认为最下层的子树是规整(满足堆定义)的。通过从下层往上层调整,建立一棵满足堆定义的小根堆。
- 筛选
1 //筛选 2 int ans[]=new int [len]; 3 for(i=0;i<len;i++){ 4 ans[i]=nums[0]; 5 nums[0]=nums[len-1-i]; 6 HeapAdjust(nums,0,len-2-i); 7 }
1.拿出小根堆的根节点(最小),放入输出数组中
2.把最末尾的节点放入根节点。因为认为现在除了根节点,其他节点都是满足根定义的。所以对根节点使用【堆调整函数】
3.重复 1,直到拿走堆中所有的节点。
测试:
输入:49,38,65,97,76,13,27,49
输出:13 27 38 49 49 65 76 97
完整java代码:
1 public class Main { 2 3 public static void main(String[] args) { 4 int []nums={49,38,65,97,76,13,27,49}; 5 HeapSort sort=new HeapSort(nums); 6 System.out.print(sort); 7 } 8 9 } 10 11 class HeapSort{ 12 int [] sortAns; 13 HeapSort(){} 14 HeapSort(int[] nums){ 15 int i; 16 int len=nums.length; 17 //建堆 18 for(i=len/2-1;i>=0;i--){ 19 HeapAdjust(nums,i,len-1); 20 } 21 //筛选 22 int ans[]=new int [len]; 23 for(i=0;i<len;i++){ 24 ans[i]=nums[0]; 25 nums[0]=nums[len-1-i]; 26 HeapAdjust(nums,0,len-2-i); 27 } 28 sortAns=ans; 29 } 30 //对[a,b]的元素进行调整。认为除了a都满足堆的条件 31 protected void HeapAdjust(int [] nums,int a,int b){ 32 int i; 33 for(i=a;a<=b;){ 34 //左子树=根*2+1,右子树=根*2+2 35 // System.out.println("a="+a); 36 int lPos=a*2+1; 37 int rPos=(a+1)*2; 38 //比较找出左右子树最小的一颗 39 int min=nums[a];//根结点 40 int nextPos=lPos;//下一个转向的树 41 boolean isSwaped=false; 42 if(lPos<=b && nums[lPos]<min){ 43 nextPos=lPos; 44 min=nums[lPos]; 45 isSwaped=true; 46 } 47 if(rPos<=b && nums[rPos]<min){ 48 nextPos=rPos; 49 isSwaped=true; 50 } 51 if(!isSwaped) break; 52 swap(nums,a,nextPos); 53 a=nextPos; 54 } 55 } 56 void printNums(int[] nums){ 57 int i; 58 for(i=0;i<nums.length;i++) System.out.print(nums[i]+" "); 59 System.out.println(); 60 } 61 private void swap(int []arr,int a,int b){ 62 int tmp=arr[a]; 63 arr[a]=arr[b]; 64 arr[b]=tmp; 65 } 66 public String toString(){ 67 int i; 68 String str=new String(""); 69 for(i=0;i<sortAns.length;i++) str+=String.valueOf(sortAns[i])+" "; 70 str+=" "; 71 return str; 72 } 73 }