堆:

    1、完全二叉树

    2、所有父节点 大于子节点

    基础公式:
    1、定位parent = (i - 1) /2
    2、定位左侧节点 c1 = 2i +1
    3、定位右侧节点 c2 = 2i +2

    image.png

    我们从 最开始的节点进行的heapify ,只能对单个完全二叉树节点进行堆调整 ,并不能对整个二叉树进行全面覆盖
    /解决方案:从最底层的节点,倒着做heapify 就ok了/


    观察一下特点:最后一个节点,然后针对 3 -> 2 -> 1 进行heapify
    最后一个节点的parent节点 就是我们开始进行倒着做heapify的开始节点

    image.png

    排序,最后一个节点 与 第一个节点互换,最大的值,砍掉也就是不进行堆重构
    image.png

    1、将数据 堆化后
    2、最后一个节点 与 第一个节点互换,最大的值,跑到了节点最后方(鉴定了顺序排序的结构)
    3、重新 堆重构 heapify是从上至下的 ,每次砍掉的 最大值不进行堆的重构

    1、堆重构(heapify) 递归
    2、堆倒叙 heapify 创建完整堆结构(完整二叉树)for
    3、首位互换,砍掉最后节点,重新堆重构 for

    1. public class TestMain {
    2. public static void main(String[] args) {
    3. //结果: 10,5,3,4,1,2
    4. // int tree[] = {4,10,3,5,1,2};
    5. // int n = tree.length;
    6. // heapify(tree,n,0);
    7. /*现在代码不够完善,因为我们从 最开始的节点进行的heapify ,只能对单个完全二叉树节点进行堆调整 ,并不能对整个二叉树进行全面覆盖*/
    8. /*解决方案:从最底层的节点,倒着做heapify 就ok了*/
    9. int tree[] = {4,10,3,5,1,2};
    10. int n = tree.length;
    11. //创建堆
    12. // heapify(tree,n,0);
    13. // buildHeap(tree,n);
    14. //堆的首个节点是最大的,那么 我们将位置 与 最后一个互换之后,剪出来,重新构建堆,然后重复执行
    15. heapSort(tree,n);
    16. Arrays.stream(tree).forEach(System.out::println);
    17. }
    18. public static void heapSort(int tree[],int n){
    19. //创建堆
    20. buildHeap(tree,n);
    21. for (int i = n - 1; i >=0 ; i--) {
    22. //最后一个节点 与 第一个节点更换,最大的值,跑到了节点最后方
    23. swap(tree,i,0);
    24. //因为heapify是从上至下的,并且i-- 所以,第一次是 最后一个节点 第二次是倒数两个节点 ,不进行堆的重构
    25. heapify(tree,i,0);
    26. }
    27. }
    28. /**
    29. * 创建完整的 【堆】
    30. * 树从最后一个节点开始倒叙做 heapify
    31. * @param tree 数组
    32. * @param n 数组长度
    33. */
    34. public static void buildHeap(int tree[],int n){
    35. //节点的索引位置 n - 1.因为parent结果 就是索引位置
    36. int last_node = n - 1;
    37. int parent = (last_node - 1) / 2;
    38. for (int i = parent; i >= 0 ; i--) {
    39. heapify(tree,n,i);
    40. }
    41. }
    42. /**
    43. *
    44. * 堆重构,顺序是从上至下
    45. * @param tree 数组
    46. * @param n 数组长度,防止越界
    47. * @param i 开始堆重构的父节点
    48. */
    49. public static void heapify(int tree[],int n , int i){
    50. if(i >= n){
    51. return;
    52. }
    53. //获取两个节点 ;左侧节点 c1 = 2i +1
    54. int c1 = 2 * i + 1;
    55. int c2 = 2 * i + 2;
    56. //假定 i是最大值
    57. int max = i;
    58. // 判断是否越界,堆节点进行重构
    59. if(c1 < n && tree[c1] > tree[max]){
    60. //节点位置
    61. max = c1;
    62. }
    63. if(c2 < n && tree[c2] > tree[max]){
    64. max = c2;
    65. }
    66. //如果max 不是最初假定的i为最大值,那么代表 下方节点 大于当前节点
    67. if(max != i){
    68. //进行数据交换
    69. swap(tree,max,i);
    70. //递归 将树完全排序
    71. heapify(tree,n,max);
    72. }
    73. }
    74. /**
    75. * 上沉下浮 数据替换
    76. * @param tree 数组
    77. * @param max 最大值
    78. * @param i 需要交换的小值
    79. */
    80. private static void swap(int[] tree, int max, int i) {
    81. //最大的值 临时存储
    82. int temp = tree[max];
    83. //数据上沉
    84. tree[max] = tree[i];
    85. //数据下浮
    86. tree[i] = temp;
    87. }
    88. }