堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左孩子和右孩子节点的值。
最大堆和最小堆是二叉堆的两种形式。
最大堆:根结点的键值是所有堆结点键值中最大者。
最小堆:根结点的键值是所有堆结点键值中最小者。
1 public class HeapSort { 2 3 /** 4 * @param args 5 */ 6 public static void main(String[] args) { 7 // TODO Auto-generated method stub 8 9 int a[] = new int[6]; 10 a[0] = 7; 11 a[1] = 5; 12 a[2] = 3; 13 a[3] = 8; 14 a[4] = 9; 15 a[5] = 2; 16 17 // 这是通过每次向上调整得到最大堆,整体自上而下 18 for (int i = a.length / 2 - 1; i < a.length; i++) { 19 shiftUp(a, i, a.length); 20 } 21 for (int i = 0; i < a.length; i++) { 22 System.out.println(a[i]); 23 } 24 for (int i = a.length - 1; i > 0; i--) { 25 int temp = a[i]; 26 a[i] = a[0]; 27 a[0] = temp; 28 shiftUp(a, i - 1, i); 29 } 30 31 //这是通过每次向下调整得到最大堆,整体自底向上(推荐) 32 for (int i = (a.length) / 2 - 1; i >= 0; i--) { 33 shiftDown(a, i, a.length); 34 } 35 for (int i = 0; i < a.length; i++) { 36 System.out.println(a[i]); 37 } 38 for (int i = a.length - 1; i > 0; i--) { 39 int temp = a[i]; 40 a[i] = a[0]; 41 a[0] = temp; 42 shiftDown(a, 0, i); 43 } 44 45 //输出排序结果 46 for (int i = 0; i < a.length; i++) { 47 System.out.println(a[i]); 48 } 49 } 50 51 //最大最小堆是相对的,只要稍微修改就可以 52 public static void shiftDown(int a[], int i, int length) { 53 while (2 * i + 1 < length) { 54 int j = (i << 1) + 1; 55 if (j + 1 < length && a[j] < a[j + 1]) 56 j = j + 1; 57 if (a[i] < a[j]) { 58 int temp = a[i]; 59 a[i] = a[j]; 60 a[j] = temp; 61 } else { 62 break; 63 } 64 i = j; 65 } 66 } 67 68 public static void shiftUp(int a[], int i, int length) { 69 while (i > 0) { 70 int j = (i & 1) == 1 ? i + 1 : i - 1; 71 int parent = (i - 1) >> 1; 72 if (j < length && a[j] > a[i]) { 73 i = j; 74 } 75 if (a[parent] < a[i]) { 76 int temp = a[i]; 77 a[i] = a[parent]; 78 a[parent] = temp; 79 } 80 i = parent; 81 } 82 } 83 }
以上代码实现两种方式建立大顶堆并且实现排序。
堆很常用,用于排序效率很高。
并且在top k问题中很常见:
求top max k问题,可以用小顶堆实现,首先建立一个k大小的小顶堆,后面的数据依次与堆顶的最小值比较,如果比最小值大,则交换两个之后重新调整堆,最后就是top max k。
同理,top min k,用大顶堆实现。