关于最小堆的问题[Java]

最小堆的定义

一般情况下,最小堆是指:父亲节点堆值大于其所有子节点堆值;
在这里插入图片描述
下面来通过举例来说明最小堆:
设有数组:{75,96,2,7,102,81,43,27,96,112,704}

建立最小堆

下述中用到的交换函数swap

 private static void swap(int i, int j, int[] data) {
        int te = data[i];
        data[i] = data[j];
        data[j] = te;
    }

对于数组来建立最小堆
在这里插入图片描述-w150

//此处N=data.length;data为要处理数组
 buildHeap(data,N);
 private static void buildHeap(int[] data, int N) {
       for (int i=N/2-1;i>=0;i--){
           adjust(data,i,N);
       }
   }

建立堆后,满足上述最小堆堆条件,需要堆进行调整:
堆的调整从上忘下进行
在这里插入图片描述
此处按照第一步,第二步,第三步处理;(第一步选取的位置为最后一个叶子节点存在的堆,公式为:data.length/2-1)

//调整的代码为,arr为目标数组,i为父节点位置,n为堆的大小
private static void adjust(int[] arr, int i, int n) {
        int j = i * 2 + 1;//子节点
        while (j<n)
        {
            if (j+1<n && arr[j] > arr[j + 1]) {//因为是最小堆的调整,所以找到堆中子节点的最小值
                j++;
            }
            if (arr[i] <arr[j]) {//将此最小值与父节点进行比较,如果父节点小,则结束,否则,将节点的值进行交换
                break;
            }
            swap(i,j,arr);//调整索引中的值,将两值进行交换
            i = j;修改父节点位置
            j = i * 2 + 1;//针对该节点下的数据进行调整
        }
    }

调整完后可认为,该堆已经是一个最小堆,如图:
在这里插入图片描述
至此最小堆的建立与调整完成;

最小堆排序

对于上图,我们可以看出,调整完后,最小堆也是无序的,如上式其数组表示为:
{2,7,43,27,102,81,75,96,96,112,704}

针对此堆进行排序;

我们发现,最小堆的根节点的数一直是最小的:因此,我们可以对此线现象找出调整

  1. 将第一个数与最后一个数进行调整
  2. 然后将最小堆中除了最后一个数外的堆进行调整
  3. 调整完堆最小堆中,跟节点是除了最后一个数外最小堆数
  4. 重复1~3过程,直到排除到堆外的数为总数减1,则可认为此时已经调整完毕
 //堆排序代码如下所示
 private static void HeapSort(int[] data, int n) {
        for(int i = n-1;i>0;i--){
            swap(i,0,data);
            adjust(data,0,i);
        }
    }

在这里插入图片描述
在这里插入图片描述调整完毕后,可得到倒序到数组数据
{704, 112, 102, 96, 96, 81, 75, 43, 27, 7, 2}
用图形表示,即为
在这里插入图片描述
至此对排序完成。

TopK问题

如上述问题,我们得到排序。但是有时我们会遇到一些求数组中前K大的数据。此类问题被称为TopK问题
针对上述问题,假设:{75,96,2,7,102,81,43,27,96,112,704},求出最大的五个数(或者倒数第5大的数)

  1. 还是像第一部分一样建立一个堆中元素个数为K=5的堆并调整堆
  2. 将第六个元素(后续数组)中的数与堆的根节点(数组中第一个位置)元素进行比较,若比第一个元素小,则说明,他不在前五大的数里面,直接排除,进行下一个元素的比较。
  3. 重复上述整个过程完成后续所有元素对堆中数堆调整
    代码为:
//此处的N为你想求出的前N个数
private static void findTop(int[] data, int N) {
        for(int i=N;i<data.length;i++){
            if(data[i]>data[0]){
                swap(i, 0,data);
                adjust(data, 0,N);
            }
        }
    }

在这里插入图片描述 将数组后续堆数**{81,43,27,96,112,704}**,依次与根节点比较,来寻找比根节点大的数。
重复此过程,将求出
在这里插入图片描述
自此可以求出前K大,或者第K大的数。

大根堆与小根堆

大根堆与小根堆代码的区别:
1.建立并调整的堆中,区别为

小根堆中
在这里插入图片描述
大根堆中
在这里插入图片描述
2.TopK问题中中,区别为
小根堆
在这里插入图片描述
大根堆
在这里插入图片描述

总结

  1. 小根堆可以求出TopK问题。
  2. 可推出,大根堆可以求出前几个最小值的问题问题。
  3. 小根堆可以排序,但是倒序
  4. 可推出:大根堆也可以排序,但是是正序
  5. 堆排序的时间复杂度为O(nlogn)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值