堆、二叉堆 - 图1

二叉堆

实现

二叉堆通过数组实现,假设第一个元素在数组中的索引为零的话:

  1. 索引为 i 的左孩子的索引是 (2*i+1)
  2. 索引为 i 的右孩子的索引是 (2*i+2)
  3. 索引为 i 的父节点的索引是 floor((i-1)/2)

将从根节点开始依次从左到右放入每一个节点的值:
可以看到满足堆的性质,是一颗完全树(除叶子节点外其他节点都是满的),而且根节点一定大于儿子节点
image.png

实现代码

  1. // Java
  2. import java.util.Arrays;
  3. import java.util.NoSuchElementException;
  4. public class BinaryHeap {
  5. //这个d表示二叉树,如果想要三叉树、多叉树可以改变d的值
  6. private static final int d = 2;
  7. private int[] heap;
  8. private int heapSize;
  9. /**
  10. * This will initialize our heap with default size.
  11. */
  12. public BinaryHeap(int capacity) {
  13. heapSize = 0;
  14. heap = new int[capacity + 1];
  15. Arrays.fill(heap, -1);
  16. }
  17. public boolean isEmpty() {
  18. return heapSize == 0;
  19. }
  20. public boolean isFull() {
  21. return heapSize == heap.length;
  22. }
  23. private int parent(int i) {
  24. return (i - 1) / d;
  25. }
  26. /**
  27. * 计算左右孩子的位置
  28. * i是父亲节点的位置
  29. * k=1就是左儿子,k=2就是右儿子
  30. */
  31. private int kthChild(int i, int k) {
  32. return d * i + k;
  33. }
  34. /**
  35. * Inserts new element in to heap
  36. * Complexity: O(log N)
  37. * As worst case scenario, we need to traverse till the root
  38. */
  39. public void insert(int x) {
  40. if (isFull()) {
  41. throw new NoSuchElementException("Heap is full, No space to insert new element");
  42. }
  43. heap[heapSize] = x;
  44. heapSize ++;
  45. heapifyUp(heapSize - 1);
  46. }
  47. /**
  48. * Deletes element at index x
  49. * Complexity: O(log N)
  50. */
  51. public int delete(int x) {
  52. if (isEmpty()) {
  53. throw new NoSuchElementException("Heap is empty, No element to delete");
  54. }
  55. int maxElement = heap[x];
  56. heap[x] = heap[heapSize - 1];
  57. heapSize--;
  58. heapifyDown(x);
  59. return maxElement;
  60. }
  61. /**
  62. * Maintains the heap property while inserting an element.
  63. */
  64. private void heapifyUp(int i) {
  65. int insertValue = heap[i];
  66. while (i > 0 && insertValue > heap[parent(i)]) {
  67. heap[i] = heap[parent(i)];
  68. i = parent(i);
  69. }
  70. heap[i] = insertValue;
  71. }
  72. /**
  73. * Maintains the heap property while deleting an element.
  74. */
  75. private void heapifyDown(int i) {
  76. int child;
  77. int temp = heap[i];
  78. while (kthChild(i, 1) < heapSize) {
  79. child = maxChild(i);
  80. if (temp >= heap[child]) {
  81. break;
  82. }
  83. heap[i] = heap[child];
  84. i = child;
  85. }
  86. heap[i] = temp;
  87. }
  88. private int maxChild(int i) {
  89. int leftChild = kthChild(i, 1);
  90. int rightChild = kthChild(i, 2);
  91. return heap[leftChild] > heap[rightChild] ? leftChild : rightChild;
  92. }
  93. /**
  94. * Prints all elements of the heap
  95. */
  96. public void printHeap() {
  97. System.out.print("nHeap = ");
  98. for (int i = 0; i < heapSize; i++)
  99. System.out.print(heap[i] + " ");
  100. System.out.println();
  101. }
  102. /**
  103. * This method returns the max element of the heap.
  104. * complexity: O(1)
  105. */
  106. public int findMax() {
  107. if (isEmpty())
  108. throw new NoSuchElementException("Heap is empty.");
  109. return heap[0];
  110. }
  111. public static void main(String[] args) {
  112. BinaryHeap maxHeap = new BinaryHeap(10);
  113. maxHeap.insert(10);
  114. maxHeap.insert(4);
  115. maxHeap.insert(9);
  116. maxHeap.insert(1);
  117. maxHeap.insert(7);
  118. maxHeap.insert(5);
  119. maxHeap.insert(3);
  120. maxHeap.printHeap();
  121. maxHeap.delete(5);
  122. maxHeap.printHeap();
  123. maxHeap.delete(2);
  124. maxHeap.printHeap();
  125. }
  126. }

Insert 的实现细节

  1. 新元素一律先插到堆的尾部
  2. 依次向上调整整个堆的结构(一直到根即可)

如果要把85插到二叉堆中:
image.png
image.png

image.png

核心代码

  1. public void insert(int x) {
  2. if (isFull()) {
  3. throw new NoSuchElementException("Heap is full, No space to insert new element");
  4. }
  5. heap[heapSize] = x;
  6. heapSize ++;
  7. heapifyUp(heapSize - 1);
  8. }
  9. /**
  10. * Maintains the heap property while inserting an element.
  11. */
  12. private void heapifyUp(int i) {
  13. int insertValue = heap[i];
  14. while (i > 0 && insertValue > heap[parent(i)]) {
  15. heap[i] = heap[parent(i)];
  16. i = parent(i);
  17. }
  18. heap[i] = insertValue;
  19. }

Delete Max 的实现细节

  1. 将堆尾元素替换到顶部
  2. 依次从根部向下调整整个堆的结构(一直到堆尾即可)

image.png

核心代码

  1. /**
  2. * Deletes element at index x
  3. * Complexity: O(log N)
  4. */
  5. public int delete(int x) {
  6. if (isEmpty()) {
  7. throw new NoSuchElementException("Heap is empty, No element to delete");
  8. }
  9. int maxElement = heap[x];
  10. heap[x] = heap[heapSize - 1];
  11. heapSize--;
  12. heapifyDown(x);
  13. return maxElement;
  14. }
  15. /**
  16. * Maintains the heap property while deleting an element.
  17. */
  18. private void heapifyDown(int i) {
  19. int child;
  20. int temp = heap[i];
  21. while (kthChild(i, 1) < heapSize) {
  22. child = maxChild(i);
  23. if (temp >= heap[child]) {
  24. break;
  25. }
  26. heap[i] = heap[child];
  27. i = child;
  28. }
  29. heap[i] = temp;
  30. }