堆的目的并不是为了排序,而是为了组建优先队列这种数据结构

replace

取出最大元素后,放入一个新元素

  • 实现:可以先extractMax,再add, 两次O(logn)的操作
  • 实现:可以直接将堆顶元素替换以后Sift Down,一次O(logn)的操作

    heapify

    将任意数组整理成堆的形状。

  • 实现:从最后一个非叶子节点开始不断进行siftdown。

  • 将n个元素逐个插入到一个空堆中,算法复杂度是O(nlogn)
  • heapify的过程,算法复杂度为O(n)

image.png
image.png
image.png

  1. class Heap {
  2. private int[] a = null;
  3. private int n = 0;
  4. // 下沉
  5. public void sink(int i) {
  6. int j = 0;
  7. int t = a[i];
  8. // 找到i结点的左子结点
  9. while ((j = (i << 1) + 1) < n) {
  10. // j < n - 1判断是否有右子结点
  11. // 如果有,并且右子结点更大,那么
  12. // j指向右子结点
  13. if (j < n - 1 && a[j] < a[j + 1]) {
  14. j++;
  15. }
  16. // 如果子结点比t大
  17. // 那么t的位置还需要往后排
  18. if (a[j] > t) {
  19. a[i] = a[j];
  20. i = j;
  21. } else {
  22. // 找到了t的位置
  23. // 此时t是大于所有的子结点的
  24. break;
  25. }
  26. }
  27. // 将t放在找到的位置那里
  28. a[i] = t;
  29. }
  30. // 上浮
  31. public void swim(int i) {
  32. int t = a[i];
  33. int par = 0;
  34. // 如果还存在父结点
  35. while (i > 0 && (par = (i - 1) >> 1) != i) {
  36. // 如果父结点比t值小
  37. if (a[par] < t) {
  38. a[i] = a[par];
  39. i = par;
  40. } else {
  41. break;
  42. }
  43. }
  44. a[i] = t;
  45. }
  46. public void push(int v) {
  47. // push是先把元素追加到数组尾巴上,然后再执行上浮操作
  48. a[n++] = v;
  49. swim(n - 1);
  50. }
  51. public int pop() {
  52. int ret = a[0];
  53. a[0] = a[--n];
  54. sink(0);
  55. return ret;
  56. }
  57. public int size() {
  58. return n;
  59. }
  60. }