二叉堆与堆排序的简单实现

一、二叉堆

堆有序:
一颗二叉树中每个节点都大于或者等于其两个孩子时,就称为堆有序。
根节点是堆有序的二叉树的最大节点。

堆有序的二叉树可以用指针来表示,
堆有序的完全二叉树除了可以用指针表示外,还可以用数组表示。

二叉堆:
二叉堆是一组堆有序的完全二叉树,并且在数组中按层级存储(不使用数组中0号位置的元素)。
二叉堆可以方便的实现优先队列的各种操作。

对于给定堆中任意的位置k
其父亲的位置:K/2
其两个孩子的位置:2k或者2k+1
这样就可以不使用指针来实现向上查找和向下查找。

二、二叉堆实现

  1 package agheap;
  2 
  3 import java.util.ArrayList;
  4 
  5 class Node{
  6     public final int value;
  7     Node(int value){
  8         this.value = value;
  9     }
 10     public String toString(){
 11         return "value:"+value;
 12     }
 13 }
 14 public class BinHeap {
 15     private static void swap(ArrayList<Node> aryList,int indexA,int indexB){
 16         Node tmp;
 17         tmp = aryList.get(indexA);
 18         aryList.set(indexA, aryList.get(indexB));
 19         aryList.set(indexB, tmp);
 20     }
 21     
 22     //上浮堆有序化
 23     private static void swim(ArrayList<Node> aryList,int index) {
 24         while(index > 1 && aryList.get(index).value > aryList.get(index/2).value){//当前元素非堆顶且大于其父亲,需要上浮调整
 25             swap(aryList, index, index/2);
 26             index = index/2;
 27         }
 28     }
 29     
 30     //下沉堆有序化
 31     private static void sink(ArrayList<Node> aryList,int index,int high){
 32         int indexOfMaxChild;
 33         while(true){
 34             if (2*index > high) {break;}//ary[2*index]无孩子
 35             if (2*index == high) {//ary[2*index]有左孩子,此时indexOfMaxChild无选择
 36                 indexOfMaxChild = 2*index;
 37             }else {//ary[2*index]有左右两孩子,此时indexOfMaxChild有选择
 38                 indexOfMaxChild = aryList.get(2*index).value > aryList.get(2*index+1).value?2*index:2*index+1;
 39             }
 40             if (aryList.get(index).value <aryList.get(indexOfMaxChild).value) {//当前ary[index]不满足局部堆有序
 41                 swap(aryList, index, indexOfMaxChild);
 42             }
 43             index = indexOfMaxChild;//继续向下迭代
 44         }
 45     }
 46     
 47     //sink()构造大根堆
 48     public static void createHeap(ArrayList<Node> aryList){
 49         int high = aryList.size()-1;
 50         for (int i = high/2; i > 0; i--) {//从非叶节点开始构造,同时sink()保持堆有序
 51             sink(aryList, i, high);
 52         }
 53     }
 54     
 55 //    //swim()构造大根堆
 56 //    public static void createHeap(ArrayList<Node> aryList){
 57 //        int high = aryList.size()-1;
 58 //        for (int i = 1; i <= high; i++) {//从索引1位置开始逐个加入,同时swim()保持堆有序
 59 //            swim(aryList, i);
 60 //        }
 61 //    }
 62     public static void insert(ArrayList<Node> aryList,Node target){
 63         aryList.add(target);
 64         swim(aryList, aryList.size()-1);
 65     }
 66     //删除堆顶元素
 67     public static Node deleteMax(ArrayList<Node> aryList){
 68         int high = aryList.size()-1;
 69         Node node = null;
 70         if (high > 0) {
 71             swap(aryList, 1, high);//将末尾元素和堆顶元素交换
 72             node = aryList.remove(high);//删除末尾元素
 73             sink(aryList, 1, high-1);//对堆顶元素重新,使其重新堆有序
 74         }
 75         return node;
 76     }
 77     public static void main(String[] args) {
 78         // TODO Auto-generated method stub
 79         try {
 80             int[] ary = {0,12,9,78,10,30,8,20,12,15};
 81             ArrayList<Node> aryList = new ArrayList<Node>();
 82             for (int i = 0; i < ary.length; i++) {
 83                 aryList.add(new Node(ary[i]));
 84             }
 85             createHeap(aryList);
 86             insert(aryList, new Node(5));
 87 //            for(Node node:aryList){
 88 //                System.out.println(node);
 89 //            }
 90             int size = aryList.size()-1;
 91             for (int i = 0; i < size; i++) {
 92                 System.out.println(deleteMax(aryList));
 93             }
 94         } catch (Exception e) {
 95             // TODO: handle exception
 96             e.printStackTrace();
 97         }
 98     }
 99 
100 }

三、借助二叉堆实现堆排序

 1     private static void createHeap(int[] ary,int index,int high){
 2         int indexOfMaxChild;
 3         while(true){
 4             if (2*index > high) {break;}//ary[2*index]无孩子
 5             if (2*index == high) {//ary[2*index]有左孩子,此时indexOfMaxChild无选择
 6                 indexOfMaxChild = 2*index;
 7             }else {//ary[2*index]有左右两孩子,此时indexOfMaxChild有选择
 8                 indexOfMaxChild = ary[2*index] > ary[2*index+1]?2*index:2*index+1;
 9             }
10             if (ary[index] < ary[indexOfMaxChild]) {//当前ary[index]不满足局部堆有序
11                 swap(ary, index, indexOfMaxChild);
12             }
13             index = indexOfMaxChild;//继续向下迭代
14         }
15     }
16     public static void heapSort(int[] ary){
17         int high = ary.length-1;
18         for (int i = high/2; i > 0; i--) {//从最大的非叶节点开始构造堆,堆顶位置为1,舍弃数组的0位
19             createHeap(ary, i, high);
20         }
21         while(high > 0){
22             swap(ary, 1, high);//将大根堆的堆顶元素(最大值)与数组尾部值交换。
23             high--;//大根堆的范围缩小一个单位。
24             createHeap(ary, 1, high);//重构大根堆。
25             
26         }
27     }

 

posted @ 2017-09-17 18:13  Qcer  阅读(764)  评论(0编辑  收藏  举报