首页 > 其他分享 >堆火熠熠:燃烧吧,我们的数据结构之魂

堆火熠熠:燃烧吧,我们的数据结构之魂

时间:2024-04-05 16:33:07浏览次数:10  
标签:之魂 数据结构 nums int 元素 堆排序 heap 堆火 maxHeap

“堆蕴秩序:堆排序的诗篇与画卷”

前置知识简要:堆

在这里插入图片描述

堆(heap)是一种满足特定条件的完全二叉树,主要可分为两种类型,如图 8-1 所示。

小顶堆(min heap):任意节点的值 其子节点的值。
大顶堆(max heap):任意节点的值 其子节点的值。

在这里插入图片描述在这里插入图片描述

`/* 初始化堆 */
// 初始化小顶堆
priority_queue<int, vector<int>, greater<int>> minHeap;
// 初始化大顶堆
priority_queue<int, vector<int>, less<int>> maxHeap;

/* 元素入堆 */
maxHeap.push(1);
maxHeap.push(3);
maxHeap.push(2);
maxHeap.push(5);
maxHeap.push(4);

/* 获取堆顶元素 */
int peek = maxHeap.top(); // 5

/* 堆顶元素出堆 */
// 出堆元素会形成一个从大到小的序列
maxHeap.pop(); // 5
maxHeap.pop(); // 4
maxHeap.pop(); // 3
maxHeap.pop(); // 2
maxHeap.pop(); // 1

/* 获取堆大小 */
int size = maxHeap.size();

/* 判断堆是否为空 */
bool isEmpty = maxHeap.empty();

/* 输入列表并建堆 */
vector<int> input{1, 3, 2, 5, 4};
priority_queue<int, vector<int>, greater<int>> minHeap(input.begin(), input.end());`

堆的存储,以数组形式实现存储堆

在这里插入图片描述
堆的实现以及堆相关操作

堆的常见应用

  • 优先队列:堆通常作为实现优先队列的首选数据结构,其入队和出队操作的时间复杂度均为 ,而建队操作为 ,这些操作都非常高效。
  • 堆排序:给定一组数据,我们可以用它们建立一个堆,然后不断地执行元素出堆操作,从而得到有序数据。然而,我们通常会使用一种更优雅的方式实现堆排序。
  • 获取最大的 个元素:这是一个经典的算法问题,同时也是一种典型应用,例如选择热度前 10 的新闻作为微博热搜,选取销量前 10
    的商品等。

阅读本节前,请确保已学完“堆“章节。

堆排序(heap sort)是一种基于堆数据结构实现的高效排序算法。我们可以利用已经学过的“建堆操作”和“元素出堆操作”实现堆排序

图解堆排序原理

在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

以此循环直至

在这里插入图片描述

C++代码实现:

#include <vector>
#include <iostream>
#include <algorithm> // 引入 swap 函数

using namespace std;

// 向下调整堆
void siftDown(vector<int>& nums, int n, int i) {
    while (true) {
        int l = 2 * i + 1;
        int r = 2 * i + 2;
        int ma = i;
        if (l < n && nums[l] > nums[ma])
            ma = l;
        if (r < n && nums[r] > nums[ma])
            ma = r;
        if (ma == i) {
            break;
        }
        swap(nums[i], nums[ma]);
        i = ma;
    }
}

/* 堆排序 */
void heapSort(vector<int>& nums) {
    int n = nums.size();
    // 建堆操作
    for (int i = n / 2 - 1; i >= 0; --i) {
        siftDown(nums, n, i);
    }
    // 提取最大元素并重新建堆
    for (int i = n - 1; i > 0; --i) {
        swap(nums[0], nums[i]);
        siftDown(nums, i, 0);
    }
}

int main() {
    vector<int> nums = { 10, 30, 40, 20, 100 };
    cout << "Before sorting: ";
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;

    heapSort(nums);

    cout << "After sorting: ";
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;

    return 0;
}

堆排序是

一种基于比较的排序算法

,它利用了堆这种数据结构——完全二叉树的一种特殊形式。堆通常分为两种类型:大顶堆(父节点的值大于或等于其子节点的值)和小顶堆(父节点的值小于或等于其子节点的值)。堆排序主要依赖于大顶堆实现降序排序,也可以通过小顶堆实现升序排序。

堆排序算法的步骤如下:

  1. 建堆

    • 从最后一个非叶子节点开始向上逐层构建堆,确保每一个子树都符合堆的性质。
    • 这个过程的时间复杂度通常是 O(n),其中 n 是待排序元素的数量,因为每个非叶子节点都需要做一次下沉操作。
  2. 堆排序过程

    • 将堆顶元素(即当前的最大值或最小值,取决于大顶堆还是小顶堆)与堆尾元素交换位置,即将最大(或最小)元素放到正确的位置。
    • 然后将新的堆(不包括刚刚被交换出去的元素)重新调整为堆,再次使得堆顶元素是最值。
    • 重复以上步骤,每次都将堆顶元素移到已排序区,并重新调整堆,直到堆中只剩下一个元素。
  3. 时间复杂度分析

    • 建堆阶段:O(n)
    • 排序阶段:需要进行 n-1 次交换和调整,每次调整堆的时间复杂度为 O(logn),因此总的时间复杂度为 O((n-1)logn) ≈ O(nlogn)。
    • 因此,堆排序的总体时间复杂度为 O(n) + O(nlogn) = O(nlogn)。
  4. 空间复杂度分析

    • 堆排序是原地排序算法,它仅需少量附加空间用于递归调用栈和临时存储,因此空间复杂度为 O(1)。
  5. 稳定性

    • 堆排序不是稳定的排序算法,即相等的元素可能会在排序后改变相对顺序。
  6. 适用场合

    • 堆排序适合处理大数据量且内存有限的情况,因其不需要额外的存储空间,同时具有较好的时间性能。尤其在需要频繁找出最大(或最小)元素的场合,例如优先队列中,堆结构非常有用。但针对较小规模或对稳定性要求高的数据排序,可能有更适合的选择,比如插入排序或归并排序。

top_k问题

  1. 初始化一个小顶堆,其堆顶元素最小
  2. 先将数组的前 个元素依次入堆。
  3. 从第 个元素开始,若当前元素大于堆顶元素,则将堆顶元素出堆,并将当前元素入堆。
  4. 遍历完成后,堆中保存的就是最大的 个元素。

top_k图解


/*经典的top——k问题*/

#include <queue>
priority_queue<int, vector<int>, greater<int>> topheap(vector<int>& nums,int k) {
    priority_queue<int, vector<int>, greater<int>> heap;/*create a heap*/
    for (int i = 0; i < k; i++) {
        heap.push(nums[i]);/*将k个元素入堆*/
    }
    for (int i = k; i < nums.size(); i++) {
        if (nums[i] > heap.top()) {
            /*如果当前元素大于堆顶元素*/
            heap.pop();
            heap.push(nums[i]);
        }
    }
    return heap;
}   

int main() {
    vector<int> nums = { 10, 30, 40, 20, 100 };
    cout << "Before sorting: ";
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;

    heapSort(nums);

    cout << "After sorting: ";
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;

    cout << "*****************\n" << endl;
    priority_queue<int, vector<int>, greater<int>> maxKHeap = topheap(nums, 3);

    cout << "The largest " << 3 << " elements in the array are: ";
    while (!maxKHeap.empty()) {
        cout << maxKHeap.top() << " ";
        maxKHeap.pop();
    }
    cout << endl;

    return 0;
}

资源:堆排序算法

标签:之魂,数据结构,nums,int,元素,堆排序,heap,堆火,maxHeap
From: https://blog.csdn.net/qq_56146092/article/details/137401838

相关文章

  • 数据结构(顺序表)
    一.顺序表的概念及结构线性表顺序表是线性表的一种。线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是⼀种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理......
  • 3数据结构
    p'数据结构57-659分数据结构+算法时间复杂度加法规则多项相加,保留高阶项,系数化为1(最高阶太大了,其余的可以忽略不计),系数化为1。乘法规则多项相乘,都保留,并将系数化为1时间复杂度实例空间复杂度O(1)O(n)O($n^2$)渐进符号渐进上界的括号内要大于等于等式左边的计......
  • 数据结构——顺序表
    一、线性表的顺序储存(连续)表示顺序存储的定义:逻辑上相邻的数据元素存储在物理上相邻的存储单位中存储结构。二、线性表的顺序表示和实现        1、线性表存储空间分配#defineList_size100 //存储空间初始分配量typedefintElemtype;// 静态分配typedefst......
  • C语言数据结构专题--顺序表(1基础)
    前言我们在对C语言有一定的了解之后,我们就可以开始数据结构的学习了,数据结构多用指针、结构体、动态内存开辟等知识,若对这些知识还不太了解的朋友,就需要加深其理解了,那么废话不多说,我们正式开始本节的学习什么是数据结构数据结构是由"数据"和"结构"两个词相组合得到的......
  • 什么是数据类型,什么是数据结构。
    数据类型,是人对数据的分类。人用这个信息,人自己或者让编译器做一种运动,将一种形式的数据转换成另一种形式的数据。数据结构,是人认为的数据之间的关系。数据类型是程序设计语言或者编译原理的概念。只讨论数据结构,可以不使用数据类型这个概念,可以不用高级程序设计语言,可以直接用......
  • (Java)数据结构——图(第三节)BFS的实现
    前言本博客是博主用于复习数据结构以及算法的博客,如果疏忽出现错误,还望各位指正。广度优先搜索的原理好了,还是这张图,不过是广度优先搜索不难看出,就是“一层一层”搜这次咱从A开始,因为如果从B开始的话,只需要一次,搜索过程就是B直接搜完,入队ACDE,isVistied全部ture,结束......
  • 驱动对象和设备对象数据结构
    驱动对象:每个驱动程序都会有唯一的驱动对象与之对应,并且这个驱动对象是在驱动加载时被内核中的对象管理程序所创建的。驱动对象用DRIVER_OBJECT数据结构表示,它作为驱动的一个实例被内核中的I/O管理器负责加载,并且内核对一个驱动只加载一个实例。驱动程序需要在DriverEntry中......
  • 数据结构——从入门到飞升——两个有序链表的交集
    题目:已知两个非降序链表序列S1与S2,设计函数构造出S1与S2的交集新链表S3。输入格式:输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。输出格式:在一行中输出两个输入序列的交集序列,数字间用空格分开,结尾不能有......
  • 数据结构(六)——图的应用
    6.4 图的应用6.4.1最小生成树对于⼀个带权连通⽆向图G=(V,E),⽣成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。设R为G的所有⽣成树的集合,若T为R中边的权值之和最小的生成树,则T称为G的最小生成树(Minimum-Spanning-Tree,MST)。最小生成树可能有多个,但边的权值之......
  • CHC5223数据结构和算法
    CHC5223数据结构和算法2023-2024第2学期第1页,共4页课业1价值40%的课程个人工作学习成果学生将能够理解:1.1数据结构1.2数据结构的应用1.3面向对象编程概念1.4程序测试方法学生将掌握以下方面的技能:2.1数据抽象2.2数据结构的使用2.3使用高级面向对象语言进行更高级的编程2.4程序......