当前位置:   article > 正文

数据结构 -- 堆

数据结构 -- 堆

大顶堆定义:父节点要比任意两个孩子的值要大

heapify()建堆之后:

过程:威廉姆斯建堆算法  n*log(n)

这个时间复杂度如何估算呢?

得到这样一个式子以后我们就可以开始算时间复杂度了,但是这似乎有点为难数学不好的同学,但是没有关系!我们可以用这个网站 

Wolfram|Alpha:计算型智能 (wolframalpha.com)

输入:

Sum[\(40)Divide[Power[2,x],Power[2,i]]*\(40)i-1\(41)\(41),{i,1,x}]

高度为4  ==>2^4 - 4 -1 = 11 意思是交换11次就能建堆

算法实现:

这个建堆操作要非常熟练!

  1. import java.util.Arrays;
  2. /**
  3. * 大顶堆
  4. */
  5. public class MaxHeap {
  6. int[] array;
  7. int size;
  8. public MaxHeap(int[] array){
  9. this.array = array;
  10. this.size = array.length;
  11. heapify();
  12. }
  13. public MaxHeap(int capacity){
  14. this.array = new int[capacity];
  15. }
  16. //建堆
  17. private void heapify(){
  18. //如何找到最后这个非叶子节点 这个有公式:size>>1-1 or (size/2-1)
  19. for(int i = size/2-1;i>=0;i--){
  20. down(i);
  21. }
  22. }
  23. /**
  24. * 删除堆顶元素
  25. * @Returns:堆顶元素
  26. */
  27. public int poll(){
  28. return 0;
  29. }
  30. //将parent索引处的元素下潜:与两个孩子较大者交换,直到没孩子或孩子没它大
  31. private void down(int parent){
  32. int left = parent*2+1;
  33. int right = left+1;
  34. int max = parent;
  35. if(left<size && array[left]>array[max]){
  36. max = left;
  37. }
  38. if(right<size && array[right]>array[max]){
  39. max = right;
  40. }
  41. if(max!=parent){//找到更大的孩子
  42. swap(max,parent);
  43. down(max);
  44. }
  45. }
  46. //交换两个索引处的元素
  47. private void swap(int i,int j){
  48. int t = array[i];
  49. array[i] = array[j];
  50. array[j] = t;
  51. }
  52. public static void main(String[] args) {
  53. int[] array = {1,2,3,4,5,6,7};
  54. MaxHeap maxHeap = new MaxHeap(array);
  55. System.out.println(Arrays.toString(maxHeap.array));
  56. //[7, 5, 6, 4, 2, 1, 3]
  57. }
  58. }

填充剩余代码:

  1. /**
  2. * 删除堆顶元素
  3. * @Returns:堆顶元素
  4. */
  5. public int poll(){
  6. int top = array[0];
  7. swap(0,size-1);
  8. size--;
  9. down(0);
  10. return top;
  11. }

  1. /**
  2. * 替换堆顶元素
  3. * @param replaced - 新元素
  4. */
  5. public void replace(int replaced){
  6. array[0] = replaced;
  7. down(0);
  8. }

  1. import java.util.Arrays;
  2. /**
  3. * 大顶堆
  4. */
  5. public class MaxHeap {
  6. int[] array;
  7. int size;
  8. public MaxHeap(int[] array){
  9. this.array = array;
  10. this.size = array.length;
  11. heapify();
  12. }
  13. public MaxHeap(int capacity){
  14. this.array = new int[capacity];
  15. }
  16. //建堆
  17. private void heapify(){
  18. //如何找到最后这个非叶子节点 这个有公式:size>>1-1 or (size/2-1)
  19. for(int i = size/2-1;i>=0;i--){
  20. down(i);
  21. }
  22. }
  23. /**
  24. * 删除堆顶元素
  25. * @return:堆顶元素
  26. */
  27. public int peek(){
  28. //当然如果这个堆里面没有数据的话 会报错
  29. //这个可以抛异常
  30. return array[0];
  31. }
  32. /**
  33. * 删除堆顶元素
  34. * @Returns:堆顶元素
  35. */
  36. public int poll(){
  37. int top = array[0];
  38. swap(0,size-1);
  39. size--;
  40. down(0);
  41. return top;
  42. }
  43. /**
  44. * 删除指定索引处元素
  45. * @param:index - 索引
  46. * @return:被删除元素
  47. */
  48. public int poll(int index){
  49. //可以一下考虑 堆为空的时候,这里就先不写了
  50. int deleted = array[index];
  51. swap(index,size-1);
  52. size--;
  53. down(index);
  54. return deleted;
  55. }
  56. /**
  57. * 替换堆顶元素
  58. * @param replaced - 新元素
  59. */
  60. public void replace(int replaced){
  61. array[0] = replaced;
  62. down(0);
  63. }
  64. /**
  65. * 堆的尾部添加元素
  66. * @param:offered-新元素
  67. * @return:是否添加成功
  68. */
  69. public boolean offer(int offered){
  70. if(size==array.length){
  71. return false;
  72. }
  73. up(offered);
  74. size++;
  75. return true;
  76. }
  77. //将 offered元素上浮:直到offered小于父元素或到堆顶
  78. private void up(int offered){
  79. int child = size;
  80. while(child>0){
  81. int parent = (child-1)/2;
  82. if(offered>array[parent]){
  83. array[child] = array[parent];
  84. }else{
  85. break;
  86. }
  87. child = parent;
  88. }
  89. array[child]=offered;
  90. }
  91. //将parent索引处的元素下潜:与两个孩子较大者交换,直到没孩子或孩子没它大
  92. private void down(int parent){
  93. int left = parent*2+1;
  94. int right = left+1;
  95. int max = parent;
  96. if(left<size && array[left]>array[max]){
  97. max = left;
  98. }
  99. if(right<size && array[right]>array[max]){
  100. max = right;
  101. }
  102. if(max!=parent){//找到更大的孩子
  103. swap(max,parent);
  104. down(max);
  105. }
  106. }
  107. //交换两个索引处的元素
  108. private void swap(int i,int j){
  109. int t = array[i];
  110. array[i] = array[j];
  111. array[j] = t;
  112. }
  113. public static void main(String[] args) {
  114. int[] array = {1,2,3,4,5,6,7};
  115. MaxHeap maxHeap = new MaxHeap(array);
  116. System.out.println(Arrays.toString(maxHeap.array));
  117. //[7, 5, 6, 4, 2, 1, 3]
  118. }
  119. }

堆排序

1.heapify 建立大顶堆

2.将堆顶与堆底交换(最大元素被交换到堆底),缩小并下潜调整堆

3.重复第二步直至堆里剩一个元素

  1. public class MaxHeap {
  2. int[] array;
  3. int size;
  4. public MaxHeap(int[] array){
  5. this.array = array;
  6. this.size = array.length;
  7. heapify();
  8. }
  9. public MaxHeap(int capacity){
  10. this.array = new int[capacity];
  11. }
  12. //建堆
  13. private void heapify(){
  14. //如何找到最后这个非叶子节点 这个有公式:size>>1-1 or (size/2-1)
  15. for(int i = size/2-1;i>=0;i--){
  16. down(i);
  17. }
  18. }
  19. /**
  20. * 删除堆顶元素
  21. * @return:堆顶元素
  22. */
  23. public int peek(){
  24. //当然如果这个堆里面没有数据的话 会报错
  25. //这个可以抛异常
  26. return array[0];
  27. }
  28. /**
  29. * 删除堆顶元素
  30. * @Returns:堆顶元素
  31. */
  32. public int poll(){
  33. int top = array[0];
  34. swap(0,size-1);
  35. size--;
  36. down(0);
  37. return top;
  38. }
  39. /**
  40. * 删除指定索引处元素
  41. * @param:index - 索引
  42. * @return:被删除元素
  43. */
  44. public int poll(int index){
  45. //可以一下考虑 堆为空的时候,这里就先不写了
  46. int deleted = array[index];
  47. swap(index,size-1);
  48. size--;
  49. down(index);
  50. return deleted;
  51. }
  52. /**
  53. * 替换堆顶元素
  54. * @param replaced - 新元素
  55. */
  56. public void replace(int replaced){
  57. array[0] = replaced;
  58. down(0);
  59. }
  60. /**
  61. * 堆的尾部添加元素
  62. * @param:offered-新元素
  63. * @return:是否添加成功
  64. */
  65. public boolean offer(int offered){
  66. if(size==array.length){
  67. return false;
  68. }
  69. up(offered);
  70. size++;
  71. return true;
  72. }
  73. //将 offered元素上浮:直到offered小于父元素或到堆顶
  74. private void up(int offered){
  75. int child = size;
  76. while(child>0){
  77. int parent = (child-1)/2;
  78. if(offered>array[parent]){
  79. array[child] = array[parent];
  80. }else{
  81. break;
  82. }
  83. child = parent;
  84. }
  85. array[child]=offered;
  86. }
  87. //将parent索引处的元素下潜:与两个孩子较大者交换,直到没孩子或孩子没它大
  88. private void down(int parent){
  89. int left = parent*2+1;
  90. int right = left+1;
  91. int max = parent;
  92. if(left<size && array[left]>array[max]){
  93. max = left;
  94. }
  95. if(right<size && array[right]>array[max]){
  96. max = right;
  97. }
  98. if(max!=parent){//找到更大的孩子
  99. swap(max,parent);
  100. down(max);
  101. }
  102. }
  103. //交换两个索引处的元素
  104. private void swap(int i,int j){
  105. int t = array[i];
  106. array[i] = array[j];
  107. array[j] = t;
  108. }
  109. public static void main(String[] args) {
  110. int[] array = {2,3,1,7,6,4,5};
  111. MaxHeap heap = new MaxHeap(array);
  112. System.out.println(Arrays.toString(heap.array));//[7, 6, 5, 3, 2, 4, 1]
  113. while(heap.size>1){
  114. heap.swap(0,heap.size-1);
  115. heap.size--;
  116. heap.down(0);
  117. }
  118. System.out.println(Arrays.toString(heap.array));//
  119. //[1, 2, 3, 4, 5, 6, 7]
  120. }
  121. }

215. 数组中的第K个最大元素 - 力扣(LeetCode)

先来看看思路:

这里使用小顶堆来解决这个问题,为什么不是大顶堆 咱们往后看

示例一:求第k大 我们可以先把数组前两个放进小顶堆中

实例二:求第k=4大,我们可以先把数组前四个小顶堆中(当然了大顶堆也可以 但是这里用小顶堆)

如果新加进来的元素比堆中的元素逗都小,那么我们什么也不做

如果进来的元素大就替换掉堆顶元素

例子:比如实例1中第三个元素是1 所以咱们什么也不做 接着看下一个数字5,发现5比堆顶元素2大,那么就要进行替换,然后重新调整小顶堆

经过这些运算,小顶堆中就是两个最大的元素 最终返回堆顶元素即可.

  1. public class MinHeap {
  2. int[] array;
  3. int size;
  4. public MinHeap(int[] array){
  5. this.array = array;
  6. this.size = array.length;
  7. heapify();
  8. }
  9. public MinHeap(int capacity){
  10. this.array = new int[capacity];
  11. }
  12. //建堆
  13. private void heapify(){
  14. //如何找到最后这个非叶子节点 这个有公式:size>>1-1 or (size/2-1)
  15. for(int i = size/2-1;i>=0;i--){
  16. down(i);
  17. }
  18. }
  19. /**
  20. * 删除堆顶元素
  21. * @return:堆顶元素
  22. */
  23. public int peek(){
  24. //当然如果这个堆里面没有数据的话 会报错
  25. //这个可以抛异常
  26. return array[0];
  27. }
  28. /**
  29. * 删除堆顶元素
  30. * @Returns:堆顶元素
  31. */
  32. public int poll(){
  33. int top = array[0];
  34. swap(0,size-1);
  35. size--;
  36. down(0);
  37. return top;
  38. }
  39. /**
  40. * 删除指定索引处元素
  41. * @param:index - 索引
  42. * @return:被删除元素
  43. */
  44. public int poll(int index){
  45. //可以一下考虑 堆为空的时候,这里就先不写了
  46. int deleted = array[index];
  47. swap(index,size-1);
  48. size--;
  49. down(index);
  50. return deleted;
  51. }
  52. /**
  53. * 替换堆顶元素
  54. * @param replaced - 新元素
  55. */
  56. public void replace(int replaced){
  57. array[0] = replaced;
  58. down(0);
  59. }
  60. /**
  61. * 堆的尾部添加元素
  62. * @param:offered-新元素
  63. * @return:是否添加成功
  64. */
  65. public boolean offer(int offered){
  66. if(size==array.length){
  67. return false;
  68. }
  69. up(offered);
  70. size++;
  71. return true;
  72. }
  73. //将 offered元素上浮:直到offered小于父元素或到堆顶
  74. private void up(int offered){
  75. int child = size;
  76. while(child>0){
  77. int parent = (child-1)/2;
  78. if(offered<array[parent]){
  79. array[child] = array[parent];
  80. }else{
  81. break;
  82. }
  83. child = parent;
  84. }
  85. array[child]=offered;
  86. }
  87. //将parent索引处的元素下潜:与两个孩子较大者交换,直到没孩子或孩子没它大
  88. private void down(int parent){
  89. int left = parent*2+1;
  90. int right = left+1;
  91. int min = parent;
  92. if(left<size && array[left]<array[min]){
  93. min = left;
  94. }
  95. if(right<size && array[right]<array[min]){
  96. min = right;
  97. }
  98. if(min!=parent){//找到更大的孩子
  99. swap(min,parent);
  100. down(min);
  101. }
  102. }
  103. //交换两个索引处的元素
  104. private void swap(int i,int j){
  105. int t = array[i];
  106. array[i] = array[j];
  107. array[j] = t;
  108. }
  109. }
  1. /**
  2. * 求数组中第K大的元素
  3. * 解题思路:
  4. * 1.向小顶堆放入前k个元素
  5. * 2.剩余元素
  6. *
  7. * 若<=堆顶元素,则略过
  8. * 若>堆顶元素,则替换堆顶元素
  9. *
  10. * 3.这样小顶堆始终保留的是到目前为止,第K大的元素
  11. * 4.循环结束,堆顶元素即为第K大元素
  12. */
  13. public class E02Leetcode215 {
  14. public int findthLargest(int[] numbers,int k){
  15. MinHeap heap = new MinHeap(k);
  16. for (int i = 0; i < k; i++) {
  17. heap.offer(numbers[i]);
  18. }
  19. for (int i = k; i < numbers.length; i++) {
  20. if(numbers[i] > heap.peek()){
  21. heap.replace(numbers[i]);
  22. }
  23. }
  24. return heap.peek();
  25. }
  26. public static void main(String[] args){
  27. //应为5
  28. System.out.println(new E02Leetcode215().findthLargest(new int[]{3,2,1,5,6,4},2));
  29. //应为4
  30. System.out.println(new E02Leetcode215().findthLargest(new int[]{3,2,3,1,2,4,5,5,6},4));
  31. }
  32. }

703. 数据流中的第 K 大元素 - 力扣(LeetCode)

跟上面那倒题目的区别是:上面的数据是固定的 而这题反之

在数组中用堆排序并不是最优的选择因为有更优秀的算法.但是对于这道题目,最好的选择就是使用堆了.

  1. public class MinHeap {
  2. int[] array;
  3. int size;
  4. public MinHeap(int[] array){
  5. this.array = array;
  6. this.size = array.length;
  7. heapify();
  8. }
  9. public MinHeap(int capacity){
  10. this.array = new int[capacity];
  11. }
  12. //建堆
  13. private void heapify(){
  14. //如何找到最后这个非叶子节点 这个有公式:size>>1-1 or (size/2-1)
  15. for(int i = size/2-1;i>=0;i--){
  16. down(i);
  17. }
  18. }
  19. /**
  20. * 删除堆顶元素
  21. * @return:堆顶元素
  22. */
  23. public int peek(){
  24. //当然如果这个堆里面没有数据的话 会报错
  25. //这个可以抛异常
  26. return array[0];
  27. }
  28. /**
  29. * 删除堆顶元素
  30. * @Returns:堆顶元素
  31. */
  32. public int poll(){
  33. int top = array[0];
  34. swap(0,size-1);
  35. size--;
  36. down(0);
  37. return top;
  38. }
  39. /**
  40. * 删除指定索引处元素
  41. * @param:index - 索引
  42. * @return:被删除元素
  43. */
  44. public int poll(int index){
  45. //可以一下考虑 堆为空的时候,这里就先不写了
  46. int deleted = array[index];
  47. swap(index,size-1);
  48. size--;
  49. down(index);
  50. return deleted;
  51. }
  52. /**
  53. * 替换堆顶元素
  54. * @param replaced - 新元素
  55. */
  56. public void replace(int replaced){
  57. array[0] = replaced;
  58. down(0);
  59. }
  60. /**
  61. * 堆的尾部添加元素
  62. * @param:offered-新元素
  63. * @return:是否添加成功
  64. */
  65. public boolean offer(int offered){
  66. if(size==array.length){
  67. return false;
  68. }
  69. up(offered);
  70. size++;
  71. return true;
  72. }
  73. //将 offered元素上浮:直到offered小于父元素或到堆顶
  74. private void up(int offered){
  75. int child = size;
  76. while(child>0){
  77. int parent = (child-1)/2;
  78. if(offered<array[parent]){
  79. array[child] = array[parent];
  80. }else{
  81. break;
  82. }
  83. child = parent;
  84. }
  85. array[child]=offered;
  86. }
  87. //将parent索引处的元素下潜:与两个孩子较大者交换,直到没孩子或孩子没它大
  88. private void down(int parent){
  89. int left = parent*2+1;
  90. int right = left+1;
  91. int min = parent;
  92. if(left<size && array[left]<array[min]){
  93. min = left;
  94. }
  95. if(right<size && array[right]<array[min]){
  96. min = right;
  97. }
  98. if(min!=parent){//找到更大的孩子
  99. swap(min,parent);
  100. down(min);
  101. }
  102. }
  103. public boolean isFull(){
  104. return size==array.length;
  105. }
  106. //交换两个索引处的元素
  107. private void swap(int i,int j){
  108. int t = array[i];
  109. array[i] = array[j];
  110. array[j] = t;
  111. }
  112. }
  1. public class E03Leetcode703 {
  2. //将小顶堆MinHeap作为成员变量
  3. private MinHeap heap;
  4. public E03Leetcode703(int k,int[] nums){
  5. heap = new MinHeap(k);
  6. for(int num:nums){
  7. add(num);
  8. }
  9. }
  10. //此方法会被不断调用,模拟数据流中新来的元素
  11. public int add(int val){
  12. if(!heap.isFull()){
  13. heap.offer(val);
  14. }
  15. //这样写有些测试样例过不了 因为这是一个流 有可能数组中刚刚开始凑不满三个
  16. //所以我们可以在小顶堆实现ifFull()
  17. else if(val>heap.peek()){
  18. heap.replace(val);
  19. }
  20. return heap.peek();
  21. }
  22. public static void main(String[] args){
  23. E03Leetcode703 test = new E03Leetcode703(3,new int[]{4,5,8,2});
  24. //小顶堆 4 5 8
  25. //跟上一题思路类似
  26. //因为k = 3 所以 4 5 8添加
  27. System.out.println(test.add(3));//[4 5 8] ==>4
  28. System.out.println(test.add(5));//[5,5,8] ==> 5
  29. System.out.println(test.add(10));//[5,8,10] ==> 5
  30. System.out.println(test.add(9));// [8 9 10] ==> 8
  31. System.out.println(test.add(4));// [8 9 10] ==> 8
  32. }
  33. }

295. 数据流的中位数 - 力扣(LeetCode)

可能你会想把数据排序然后就可以求中位数了,但是这是数据流,数据不断变化,这样效率很低

1   2   3   7   8   9
思路:
我们不是说非要把所有的数据收集起来然后重头到尾排个序,我们可以把所有数据分成两部分
一部分是较小的数据 大概占一半 一部分是较大的数据  从小的里面挑大的 大的里面挑小的
s   s   s  g   g   g
        3   7
    大顶堆   小顶堆   所以可以用两个堆来解决

  1. import java.util.Arrays;
  2. /**
  3. * <h3>数据流的中位数</h3>
  4. */
  5. public class E04Leetcode295_1 {
  6. /**
  7. * 为了保证两边数据量的平衡
  8. * <ul>
  9. * <li>两边个数一样时,左边个数加一</li>
  10. * <li>两边个数不一样时,右边个数加一</li>
  11. * </ul>
  12. * 但是, 随便一个数能直接加入吗?
  13. * <ul>
  14. * <li>左边个数加一时, 把新元素加在右边,弹出右边最小的加入左边</li>
  15. * <li>右边个数加一时, 把新元素加在左边,弹出左边最小的加入右边</li>
  16. * </ul>
  17. */
  18. public void addNum(int num) {
  19. if (left.size() == right.size()) {
  20. right.offer(num);
  21. left.offer(right.poll());
  22. } else {
  23. left.offer(num);
  24. right.offer(left.poll());
  25. }
  26. }
  27. private Heap left = new Heap(10, true);
  28. private Heap right = new Heap(10, false);
  29. @Override
  30. public String toString() {
  31. int size = left.size;
  32. int[] left = new int[size];
  33. for (int i = 0; i < left.length; i++) {
  34. left[size - 1 - i] = this.left.array[i];
  35. }
  36. int[] right = Arrays.copyOf(this.right.array, this.right.size);
  37. return Arrays.toString(left) + " <-> " + Arrays.toString(right);
  38. }
  39. /**
  40. * <ul>
  41. * <li>两边数据一致, 左右各取堆顶元素求平均</li>
  42. * <li>左边多一个, 取左边堆顶元素</li>
  43. * </ul>
  44. */
  45. public double findMedian() {
  46. if (left.size() == right.size()) {
  47. return (left.peek() + right.peek()) / 2.0;
  48. } else {
  49. return left.peek();
  50. }
  51. }
  52. public static void main(String[] args) {
  53. E04Leetcode295_1 test = new E04Leetcode295_1();
  54. test.addNum(1);
  55. test.addNum(2);
  56. test.addNum(3);
  57. test.addNum(7);
  58. test.addNum(8);
  59. test.addNum(9);
  60. System.out.println(test);
  61. System.out.println(test.findMedian());
  62. test.addNum(10);
  63. System.out.println(test);
  64. System.out.println(test.findMedian());
  65. test.addNum(4);
  66. System.out.println(test);
  67. System.out.println(test.findMedian());
  68. }
  69. }
  1. /**
  2. * 可以扩容的heap max用于指定是大顶堆还是小顶堆
  3. */
  4. public class Heap {
  5. int[] array;
  6. int size;
  7. boolean max;
  8. public int size() {
  9. return size;
  10. }
  11. public Heap(int capacity, boolean max) {
  12. this.array = new int[capacity];
  13. this.max = max;
  14. }
  15. /**
  16. * 获取堆顶元素
  17. *
  18. * @return 堆顶元素
  19. */
  20. public int peek() {
  21. return array[0];
  22. }
  23. /**
  24. * 删除堆顶元素
  25. *
  26. * @return 堆顶元素
  27. */
  28. public int poll() {
  29. int top = array[0];
  30. swap(0, size - 1);
  31. size--;
  32. down(0);
  33. return top;
  34. }
  35. /**
  36. * 删除指定索引处元素
  37. *
  38. * @param index 索引
  39. * @return 被删除元素
  40. */
  41. public int poll(int index) {
  42. int deleted = array[index];
  43. swap(index, size - 1);
  44. size--;
  45. down(index);
  46. return deleted;
  47. }
  48. /**
  49. * 替换堆顶元素
  50. *
  51. * @param replaced 新元素
  52. */
  53. public void replace(int replaced) {
  54. array[0] = replaced;
  55. down(0);
  56. }
  57. /**
  58. * 堆的尾部添加元素
  59. *
  60. * @param offered 新元素
  61. */
  62. public void offer(int offered) {
  63. if (size == array.length) {
  64. grow();
  65. }
  66. up(offered);
  67. size++;
  68. }
  69. private void grow() {
  70. int capacity = size + (size >> 1);
  71. int[] newArray = new int[capacity];
  72. System.arraycopy(array, 0,
  73. newArray, 0, size);
  74. array = newArray;
  75. }
  76. // 将 offered 元素上浮: 直至 offered 小于父元素或到堆顶
  77. private void up(int offered) {
  78. int child = size;
  79. while (child > 0) {
  80. int parent = (child - 1) / 2;
  81. boolean cmp = max ? offered > array[parent] : offered < array[parent];
  82. if (cmp) {
  83. array[child] = array[parent];
  84. } else {
  85. break;
  86. }
  87. child = parent;
  88. }
  89. array[child] = offered;
  90. }
  91. public Heap(int[] array, boolean max) {
  92. this.array = array;
  93. this.size = array.length;
  94. this.max = max;
  95. heapify();
  96. }
  97. // 建堆
  98. private void heapify() {
  99. // 如何找到最后这个非叶子节点 size / 2 - 1
  100. for (int i = size / 2 - 1; i >= 0; i--) {
  101. down(i);
  102. }
  103. }
  104. // 将 parent 索引处的元素下潜: 与两个孩子较大者交换, 直至没孩子或孩子没它大
  105. private void down(int parent) {
  106. int left = parent * 2 + 1;
  107. int right = left + 1;
  108. int min = parent;
  109. if (left < size && (max ? array[left] > array[min] : array[left] < array[min])) {
  110. min = left;
  111. }
  112. if (right < size && (max ? array[right] > array[min] : array[right] < array[min])) {
  113. min = right;
  114. }
  115. if (min != parent) { // 找到了更大的孩子
  116. swap(min, parent);
  117. down(min);
  118. }
  119. }
  120. // 交换两个索引处的元素
  121. private void swap(int i, int j) {
  122. int t = array[i];
  123. array[i] = array[j];
  124. array[j] = t;
  125. }
  126. public Object getSize() {
  127. return size;
  128. }
  129. }

-----

  1. import java.util.Comparator;
  2. import java.util.PriorityQueue;
  3. /*
  4. 当然我们也可以不用自己定义的heap 在java中也有一个功能类似的类PriorityQueue 优先级队列
  5. */
  6. public class E04Leetcode295 {
  7. /**
  8. * 为了保证两边数据量的平衡
  9. *
  10. * 两边个数一样时,左边个数+1
  11. * 两边个数不一样时,右边个数+1
  12. *
  13. * 但是,随便一个数直接加入吗?
  14. *
  15. * 左边个数+1时,应该挑右边最小的加入
  16. * 右边个数+1时,应该挑左边最大的加入
  17. *
  18. */
  19. public void addNum(int num){
  20. if(left.size()==right.size()){
  21. right.offer(num);
  22. left.offer(right.poll());
  23. }else{
  24. left.offer(num);
  25. right.offer(left.poll());
  26. }
  27. }
  28. /**
  29. * 两边数据一致,左右各取堆顶元素平均
  30. * 左边多一个,取左边堆顶元素
  31. */
  32. public double findMedian(){
  33. if(left.size()== right.size()){
  34. return (left.peek()+right.peek())/2.0;
  35. }
  36. else {
  37. return left.peek();
  38. }
  39. }
  40. //大顶堆
  41. private PriorityQueue<Integer> left =new PriorityQueue<>(
  42. (a,b)->Integer.compare(b,a)//-1 b<a 0 a==b 1 b>a
  43. );
  44. //比较器
  45. //小顶堆
  46. private PriorityQueue<Integer> right =new PriorityQueue<>(
  47. (a,b)->Integer.compare(a,b)//省略不写也一样 compare
  48. //-1 a<b 0 a==b 1 a>b
  49. );
  50. public static void main(String[] args) {
  51. //这里就不去看源码了 以上浮为例,大概的实现逻辑
  52. Comparator<Integer>cmp = (a,b)->Integer.compare(a,b);//小顶堆比较器compare -1 a<b,0 a==b,1 a>b
  53. // Comparator<Integer>cmp = (a,b)->Integer.compare(b,a);//小顶堆比较器compare -1 b<a,0 a==b,1 b>a
  54. int a = 10;//父元素值
  55. int b =5;//新增元素值
  56. if(cmp.compare(a,b)>0){
  57. System.out.println("上浮");
  58. }else{
  59. System.out.println("停止上浮");
  60. }
  61. }
  62. }
  1. class MedianFinder {
  2. PriorityQueue<Integer> queMin;
  3. PriorityQueue<Integer> queMax;
  4. public MedianFinder() {
  5. queMin = new PriorityQueue<Integer>((a, b) -> (b - a));
  6. queMax = new PriorityQueue<Integer>((a, b) -> (a - b));
  7. }
  8. public void addNum(int num) {
  9. if (queMin.isEmpty() || num <= queMin.peek()) {
  10. queMin.offer(num);
  11. if (queMax.size() + 1 < queMin.size()) {
  12. queMax.offer(queMin.poll());
  13. }
  14. } else {
  15. queMax.offer(num);
  16. if (queMax.size() > queMin.size()) {
  17. queMin.offer(queMax.poll());
  18. }
  19. }
  20. }
  21. public double findMedian() {
  22. if (queMin.size() > queMax.size()) {
  23. return queMin.peek();
  24. }
  25. return (queMin.peek() + queMax.peek()) / 2.0;
  26. }
  27. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/387294
推荐阅读
相关标签
  

闽ICP备14008679号