数据结构之堆的应用

简介: 数据结构之堆的应用

前言


JDK1.8 中的 PriorityQueue底层使用了堆的数据结构,用堆作为底层结构 封装了优先级队列。

建堆(向下调整)的时间复杂度O(N):


1667918027821.jpg


向上调整建堆的时间复杂度为O(nlogn).


一、Top-k问题


示例:在给定的一个数组中求前K个最小的数


第一种思路:把给定的数组直接进行排序,然后前K个一定是最小的数;

public int[] getLeastNumbers(int[] arr, int k) {
           Arrays.sort(arr);
            int[] str = new int[k];
            for (int i = 0; i < k; i++) {
                 str[i] = arr[i];
            }
            return str;
    }

显然这种方式是不可取的,如果数据量非常大,排序就不太可取了(可能数据都


不能一下子全部加载到内存中 ) 。最佳的方式就是用堆来解决。

第二种思路:把整个数组整体建小根堆,然后依次弹出K个堆顶的数据。

public static int[] smallestK(int[] arr, int k) {
        //1. 建立一个小根堆
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        //2、取出数组当中的每个元素,存放到小跟堆当中
        for (int i = 0; i < arr.length; i++) {
            minHeap.offer(arr[i]);
        }
        //3.弹出K个元素,存放到数组当中,返回即可
        int[] tmp = new int[k];
        for (int i = 0; i < k; i++) {
            tmp[i] = minHeap.poll();
        }
        return tmp;
    }

但是你会发现,这种方式虽然可以,但是时间复杂度比较高,还是不可取得。整体建堆的时间复杂度为o(n),然后弹出K次时间复杂度为Klogn,则总体时间复杂度为 O(N + Klogn);


第三种思路:


1. 用数据集合中前 K个元素来建堆: 前 k 个最大的元素,则建小堆; 前 k 个最小的元素,则建大堆。

2. 用剩余的 N-K 个元素依次与堆顶元素来比较,不满足则替换堆顶元素

将剩余 N-K 个元素依次与堆顶元素比完之后,堆中剩余的 K 个元素就是所求的前 K 个最小或者最大的元素。

下面还是用上面求前K个最小的数为例:

 

public int[] getLeastNumbers(int[] arr, int k) {
           PriorityQueue<Integer> minHeap = new PriorityQueue<>(new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o2.compareTo(o1);
                }
            });
            if (arr == null || k == 0)return new int[0];
            //用K个元素,先建立一个大根堆
            for (int i = 0; i < k; i++) {
                minHeap.offer(arr[i]);
            }
            //剩余元素与堆元素进行比较
            for (int i = k; i < arr.length; i++) {
                if (arr[i] < minHeap.peek()){
                    minHeap.poll();
                    minHeap.offer(arr[i]);
                }
            }
            //返回前K个元素
            int[] str = new int[k];
            for (int i = 0; i < k; i++) {
                str[i] = minHeap.poll();
            }
            return str;
        }

此时时间复杂度为:k + (n-k)logk ,约等于nlogk。


那么现在有一个小问题,就是第K个最小的怎么求?


其实这一点非常简单,求第K个最小的,只需要弹出一次就好了,因为此时是大跟堆,那么第K个最小的肯定就是堆顶的元素。


二、堆排序


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

1. 建堆

升序:建大堆

降序:建小堆

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

建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。

 

/**
     * 时间复杂度:
     *  O(n) + O(n*logn) 约等于 O(nlogn)
     *  空间复杂度:O(1)
     */
public void heapSort() {
        //1.建立大根堆 O(n)
        createHeap();
        //2.然后排序
        int end = usedSize-1;
        while (end > 0) {
            int tmp = elem[0];
            elem[0] = elem[end];
            elem[end] = tmp;
            shiftDown(0,end);
            end--;
        }
    }
    private void shiftDown(int root,int len) {
        int child = root*2 + 1;
        while (elem[child] > elem[root]){
            if (child+1 < len && elem[child] < elem[child+1]){
                child++;
            }
            if (elem[child] > elem[root]){
                int temp = elem[child];
                elem[child] = elem[root];
                elem[root] = temp;
                child = root;
                root = (child-1)/2;
            }else {
                break;
            }
        }
    }

1667918092836.jpg

时间复杂度: O(n) + O(n*logn) 约等于 O(nlogn)

空间复杂度:O(1)


相关文章
|
1月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
197 86
|
3月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
88 1
|
3月前
|
存储 监控 算法
公司员工泄密防护体系中跳表数据结构及其 Go 语言算法的应用研究
在数字化办公中,企业面临员工泄密风险。本文探讨使用跳表(Skip List)数据结构优化泄密防护系统,提升敏感数据监测效率。跳表以其高效的动态数据处理能力,为企业信息安全管理提供了可靠技术支持。
88 0
|
12月前
|
存储 Java
Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。
【10月更文挑战第19天】本文详细介绍了Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。HashMap以其高效的插入、查找和删除操作著称,而TreeMap则擅长于保持元素的自然排序或自定义排序,两者各具优势,适用于不同的开发场景。
128 1
|
12月前
|
存储 算法 C语言
通义灵码在考研C语言和数据结构中的应用实践 1-5
通义灵码在考研C语言和数据结构中的应用实践,体验通义灵码的强大思路。《趣学C语言和数据结构100例》精选了五个经典问题及其解决方案,包括求最大公约数和最小公倍数、统计字符类型、求特殊数列和、计算阶乘和双阶乘、以及求斐波那契数列的前20项和。通过这些实例,帮助读者掌握C语言的基本语法和常用算法,提升编程能力。
272 4
|
8月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
12月前
|
机器学习/深度学习 存储 人工智能
数据结构在实际开发中的广泛应用
【10月更文挑战第20天】数据结构是软件开发的基础,它们贯穿于各种应用场景中,为解决实际问题提供了有力的支持。不同的数据结构具有不同的特点和优势,开发者需要根据具体需求选择合适的数据结构,以实现高效、可靠的程序设计。
605 63
|
11月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
317 5
|
11月前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
411 16
|
11月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
303 1

热门文章

最新文章