• 数据结构与算法【堆】的Java实现


    前言 

    之前已经说过堆的特点了,具体文章在数据结构与算法【队列】的Java实现-CSDN博客。因此直接实现堆的其他功能。

    建堆

    所谓建堆,就是将一个初始的堆变为大顶堆或是小顶堆。这里以大顶堆为例。展示如何建堆。

    1. 找到最后一个非叶子节点
    2. 从后向前,对每个节点执行下潜

    一些规律(0作为根节点时满足)

    • 一棵满二叉树节点个数为 2^h-1,如下例中高度 h=3 节点数是 2^3-1=7
    • 非叶子节点范围为 [0, size/2-1]

    建堆的时间复杂度为O(n)。

    一个基础的大顶堆实现代码如下

    1. public class MaxHeap {
    2. int[] array;
    3. int size;
    4. public MaxHeap(int capacity) {
    5. this.array = new int[capacity];
    6. }
    7. public MaxHeap(int[] array) {
    8. this.array = array;
    9. this.size = array.length;
    10. heapify();
    11. }
    12. /**
    13. * 获取堆顶元素
    14. *
    15. * @return 堆顶元素
    16. */
    17. public int peek() {
    18. return array[0];
    19. }
    20. /**
    21. * 删除堆顶元素
    22. *
    23. * @return 堆顶元素
    24. */
    25. public int poll() {
    26. int top = array[0];
    27. swap(0, size - 1);
    28. size--;
    29. down(0);
    30. return top;
    31. }
    32. /**
    33. * 删除指定索引处元素
    34. *
    35. * @param index 索引
    36. * @return 被删除元素
    37. */
    38. public int poll(int index) {
    39. int deleted = array[index];
    40. up(Integer.MAX_VALUE, index);
    41. poll();
    42. return deleted;
    43. }
    44. /**
    45. * 替换堆顶元素
    46. *
    47. * @param replaced 新元素
    48. */
    49. public void replace(int replaced) {
    50. array[0] = replaced;
    51. down(0);
    52. }
    53. /**
    54. * 堆的尾部添加元素
    55. *
    56. * @param offered 新元素
    57. * @return 是否添加成功
    58. */
    59. public boolean offer(int offered) {
    60. if (size == array.length) {
    61. return false;
    62. }
    63. up(offered, size);
    64. size++;
    65. return true;
    66. }
    67. // 将 offered 元素上浮: 直至 offered 小于父元素或到堆顶
    68. private void up(int offered, int index) {
    69. int child = index;
    70. while (child > 0) {
    71. int parent = (child - 1) / 2;
    72. if (offered > array[parent]) {
    73. array[child] = array[parent];
    74. } else {
    75. break;
    76. }
    77. child = parent;
    78. }
    79. array[child] = offered;
    80. }
    81. // 建堆
    82. private void heapify() {
    83. // 如何找到最后这个非叶子节点 size / 2 - 1
    84. for (int i = size / 2 - 1; i >= 0; i--) {
    85. down(i);
    86. }
    87. }
    88. // 将 parent 索引处的元素下潜: 与两个孩子较大者交换, 直至没孩子或孩子没它大
    89. private void down(int parent) {
    90. int left = parent * 2 + 1;
    91. int right = left + 1;
    92. int max = parent;
    93. if (left < size && array[left] > array[max]) {
    94. max = left;
    95. }
    96. if (right < size && array[right] > array[max]) {
    97. max = right;
    98. }
    99. if (max != parent) { // 找到了更大的孩子
    100. swap(max, parent);
    101. down(max);
    102. }
    103. }
    104. // 交换两个索引处的元素
    105. private void swap(int i, int j) {
    106. int t = array[i];
    107. array[i] = array[j];
    108. array[j] = t;
    109. }
    110. }
  • 相关阅读:
    第58篇-京东滑块流程分析【2023-09-26】
    Mybatis 动态 SQL
    《视觉 SLAM 十四讲》V2 第 10 讲 后端优化2 简化BA 【位姿图】
    @SpringBootApplication注解的理解——如何排除自动装配 & 分布式情况下如何自动加载 & nacos是怎么被发现的
    【Redis】共同关注列表与基于Feed流的关注消息滚动分页推送的实现
    HLS入门
    为什么macbook不能删除u盘里东西?苹果电脑如何删除u盘文件
    初识manim
    mybatis在实际项目中常见的排坑配置
    [python和CSP的姻缘]202109-2 非零段划分
  • 原文地址:https://blog.csdn.net/zmbwcx/article/details/134483448