IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 堆排序和Top-K问题 -> 正文阅读

[数据结构与算法]堆排序和Top-K问题

ced485cbb11e458d81a746890b32cf3f.gif

作者:渴望力量的土狗

博客主页:渴望力量的土狗的博客主页

专栏:数据结构与算法

工欲善其事必先利其器,给大家介绍一款超牛的斩获大厂offer利器——牛客网

点击免费注册和我一起刷题吧

目录

堆排序:?

步骤总结:?

建立思想:(以升序为例)

Top-K问题

问题描述:?

基本思路:?利用分布式思想处理海量数据

拓展:


堆排序:?

步骤总结:?

堆排序即利用堆的思想来进行排序,总共分为两个步骤

1、建堆(如果升序就建大根堆,降序就建小根堆)

2、利用堆删除的思想来进行排序

前面我们说到了建堆和堆删除的操作都是需要用到向下调整的思想的,所以当我们掌握了向下调整的思想就可以完成堆排序。

ps:不了解这部分知识的可以看一下博主的这篇博客内容:

【Java数据结构】集合PriorityQueue及其背后的数据结构堆(优先级队列)https://blog.csdn.net/m0_67995737/article/details/127246172?spm=1001.2014.3001.5502

建立思想:(以升序为例)

首先我们以大根堆的形式建堆,建堆完毕后堆顶元素为当前数组中的最大值,(注意说的是当前数组,因为我们的size一直在减小,这也是为了把最大的值放到原始数组的后面服务)将堆顶元素与堆尾元素进行互换,并向下调整,使其依然为大根堆,这样最大的值就放到了末尾,调整后的堆顶为原数组中的第二大的元素,经过上述过程,放到原数组的倒数第二个位置,依次类推,直至堆中只留一个元素,即可得到数组的升序排列。

特别注意:在进行这些操作的时候,我们只是定义了临时的变量来保存数组的长度,切不可改变原数组的长度!

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        int []arr={27,15,19,18,28,34,65,49,25,37};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));

    }

    public static void heapSort(int[]arr){
        creatHeap(arr);
        int length= arr.length-1;
        while (length>=0){
            int temp=arr[0];
            arr[0]=arr[length];
            arr[length]=temp;
            shiftDown(arr,0,length);
            length--;
        }

    }

    public static void creatHeap(int[]arr){
        int size= arr.length;
        for(int parent=(size-1-1)/2;parent>=0;parent--){

            shiftDown(arr,parent,size);

        }
    }


    public static void shiftDown(int[]arr,int parent,int len){

        int child=2*parent+1;

        while(child<len){
            if(child+1<len&&arr[child]<arr[child+1]){
                child++;
            }

            if(arr[child]>arr[parent]){
                int temp=arr[child];
                arr[child]=arr[parent];
                arr[parent]=temp;
                parent=child;
                child=2*parent+1;

            }else {
                break;
            }
        }

    }
}

我们在使用堆排序的时候,其默认排序方式就是升序排序。??

Top-K问题

Top-K问题是堆应用的一个非常经典的问题?

问题描述:?

TOP-K问题:即求数据集合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大(注意:切不可用简单的排序后取前k个值这种做法,这种方式在数据量不大的时候简单可行,但固然不是最优的方法。

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。
对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下

基本思路:?利用分布式思想处理海量数据

1. 用数据集合中前K个元素来建堆
前k个最大的元素,则建小堆
前k个最小的元素,则建大堆
2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素
将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素

class Solution {
    public int[] smallestK(int[] arr, int k) {
        if(k==0||arr==null){
            return new int[0];
        }
        //1、建大根堆
        PriorityQueue<Integer> minHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });
        //2、将前k个元素放到大根堆当中
        for(int i=0;i<k;i++){
            minHeap.offer(arr[i]);
        }
        //3、对从k+1个元素开始的数字与堆顶元素比较,如果比堆顶元素小就把堆顶弹出,让该小的元素作为新
        //的堆顶,并进行向下调整使之依然为大根堆
        for(int j=k;j<arr.length;j++){

            if(arr[j]<minHeap.peek()){
                minHeap.poll();
                minHeap.offer(arr[j]);
            }
        }
        //4、把大根堆中的k个元素放到数组中(此时已经为前k个最小的数)
        int[]temp=new int[k];
        for(int i=0;i<k;i++){
            temp[i]=minHeap.poll();
        }

        return temp;


    }
}

?Top-K问题与堆排序有类似之处,我们需要注意的是:

1、当k为0或者数组为空时什么都不返回,即返回[],就是return int[0];这个操作!?

2、由于我们在建大根堆时用到的优先级队列其底层是一个小根堆(默认),所以我们要重写comparator(比较器)接口中的compar方法,使之变成大根堆。这里我们可以用到几种方法:

(1)匿名内部类(我就是采用的这种方法)

(2)直接自己实现一个比较器重写comparator(比较器)接口中的compar方法

这两种都是可以的。

拓展:

那如果是要获取第k小的或者第k大的数(这里以第k小的数为例),我们已经求得了最小的k个数,那么我们只需要在这里面找到最大的那个数(也就是第k小的数即可)。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:59:49  更:2022-10-17 13:04:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:50:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码