最大堆性质:任一节点比其左右节点值都大。

 最小堆性质:任一节点比其左右节点值都小。

 

应用:解决TopK问题。

TopK问题是指从大量数据(源数据)中获取最大(或最小)的K个数据。

 

  1 package com.sunshine.AlgorithmTemplate;
  2 
  3 import org.junit.Test;
  4 
  5 import java.util.Arrays;
  6 import java.util.Random;
  7 
  8 public class HeapTemplate2 {
  9 
 10     /***
 11      * 父节点
 12      */
 13     private int parent(int pos) {
 14         return (pos - 1) / 2;
 15     }
 16 
 17     /***
 18      * 左孩子
 19      */
 20     private int leftChild(int pos) {
 21         return pos * 2 + 1;
 22     }
 23 
 24     /***
 25      * 右孩子
 26      */
 27     private int rightChild(int pos) {
 28         return pos * 2 + 2;
 29     }
 30 
 31     /***
 32      * 值交换
 33      */
 34     private void swap(int[] heap, int i, int j) {
 35         int tmp = heap[i];
 36         heap[i] = heap[j];
 37         heap[j] = tmp;
 38     }
 39 
 40     /***
 41      * 按树结构打印
 42      */
 43     public void printHeap(int[] heap, int size) {
 44         int a = 2;
 45         for (int i = 0; i < size; i++) {
 46             System.out.print(heap[i] + " ");
 47             if (i == a - 2) {
 48                 a *= 2;
 49                 System.out.println();
 50             }
 51         }
 52         System.out.println();
 53     }
 54 
 55     /***
 56      * 打印排序后数组
 57      */
 58     public void printArrSorted(int[] arr) {
 59         Arrays.sort(arr);
 60         for (int i : arr) {
 61             System.out.print(i + " ");
 62         }
 63         System.out.println();
 64     }
 65 
 66     /***
 67      * 打印数组
 68      */
 69     public void printArr(int[] arr) {
 70         for (int i : arr) {
 71             System.out.print(i + " ");
 72         }
 73         System.out.println();
 74     }
 75 
 76     /***
 77      * 前N个最大值
 78      */
 79     @Test
 80     public void topMaxN() {
 81         final int len = 20;
 82         final int topN = 7;
 83         int[] heap = new int[len];
 84         Random random = new Random();
 85         for (int i = 0; i < len; i++) {
 86             heap[i] = random.nextInt(100);
 87         }
 88         
 89         //创建topN最小堆
 90         createHeapMin(heap, topN);
 91         //遍历数组,并维护topN最小堆
 92         findTopMaxN(heap, topN);
 93         
 94         
 95         printHeap(heap, topN);
 96         printArr(heap);
 97         printArrSorted(heap);
 98         System.out.println();
 99         System.out.println(heap[heap.length - topN]);
100     }
101 
102 
103     /***
104      * 遍历数据组,并维护最小堆
105      */
106     private void findTopMaxN(int[] heap, int topN) {
107         for (int i = topN; i < heap.length; i++) {
108             adjustDownTopMaxN(heap, topN, i);
109         }
110     }
111 
112     /***
113      * 创建最小堆
114      */
115     private void createHeapMin(int[] heap, int size) {
116         for (int i = 1; i < size; i++) {
117             adjustUpMin(heap, i);
118         }
119     }
120 
121     /***
122      * 向上调整新加入节点位置
123      */
124     private void adjustUpMin(int[] heap, int pos) {
125         while (parent(pos) >= 0 && heap[parent(pos)] > heap[pos]) {
126             int parent = parent(pos);
127             swap(heap, parent, pos);
128             pos = parent;
129         }
130     }
131 
132     /***
133      * 向下调整新加入节点位置,并维护最小堆
134      */
135     private void adjustDownTopMaxN(int[] heap, int topN, int pos) {
136         //比topN中最小的还要小直接返回
137         if (heap[0] >= heap[pos]) {
138             return;
139         }
140         swap(heap, 0, pos);
141         pos = 0;
142         while (leftChild(pos) < topN) {
143             int child = leftChild(pos);
144             //判断左右孩子的大小,child代表较小的孩子
145             if (child + 1 < topN && heap[child + 1] < heap[child]) {
146                 child++;
147             }
148             //新节点比较小的孩子都小,说明找到对应位置,直接跳出勋魂
149             if (heap[child] >= heap[pos]) {
150                 break;
151             }
152             swap(heap, pos, child);
153             pos = child;
154         }
155     }
156 
157 
158     /***
159      * 前N个最小值
160      */
161     @Test
162     public void topMinN() {
163         final int len = 200;
164         final int topN = 7;
165         int[] heap = new int[len];
166         Random random = new Random();
167         for (int i = 0; i < len; i++) {
168             heap[i] = random.nextInt(10000);
169         }
170         //创建topN最大堆
171         createHeapMax(heap, topN);
172         //遍历数组,并维护topN最小堆
173         findTopMinN(heap,topN);
174         
175         printHeap(heap, topN);
176         printArrSorted(heap);
177         System.out.println();
178         System.out.println(heap[topN-1]);
179     }
180 
181     /***
182      * 遍历数据组,并维护最大堆
183      */
184     private void findTopMinN(int[] heap, int topN) {
185         for (int i = topN; i < heap.length; i++) {
186             adjustDownTopMinN(heap, topN, i);
187         }
188     }
189 
190     /***
191      * 创建最大堆
192      */
193     private void createHeapMax(int[] heap, int size) {
194         for (int i = 1; i < size; i++) {
195             adjustUpMax(heap, i);
196         }
197     }
198 
199     /***
200      * 向上调整新加入节点位置
201      */
202     private void adjustUpMax(int[] heap, int pos) {
203         while (parent(pos) >= 0 && heap[parent(pos)] < heap[pos]) {
204             int parent = parent(pos);
205             swap(heap, parent, pos);
206             pos = parent;
207         }
208     }
209 
210     /***
211      * 向下调整新加入节点位置,并维护最大堆
212      */
213     private void adjustDownTopMinN(int[] heap, int topN, int pos) {
214         //比topN中最大的还要大直接返回
215         if (heap[0] <= heap[pos]) {
216             return;
217         }
218         swap(heap, 0, pos);
219         pos = 0;
220         while (leftChild(pos) < topN) {
221             int child = leftChild(pos);
222             //判断左右孩子的大小,child代表较大的孩子
223             if (child + 1 < topN && heap[child + 1] > heap[child]) {
224                 child++;
225             }
226             //新节点比较大的孩子都大,说明找到位置,直接跳出循环
227             if (heap[child] <= heap[pos]) {
228                 break;
229             }
230             swap(heap, pos, child);
231             pos = child;
232         }
233     }
234 }