数据结构之堆——算法与数据结构入门笔记(六)

这篇具有很好参考价值的文章主要介绍了数据结构之堆——算法与数据结构入门笔记(六)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

数据结构之堆——算法与数据结构入门笔记(六)数据结构之堆——算法与数据结构入门笔记(六)

本文是算法与数据结构的学习笔记第六篇,将持续更新,欢迎小伙伴们阅读学习。有不懂的或错误的地方,欢迎交流

引言

当涉及到高效的数据存储和检索时,堆(Heap)是一种常用的数据结构。上一篇文章中介绍了树和完全二叉树,堆就是一个完全二叉树,可以分为最大堆和最小堆两种类型。在这篇博客中,我们将深入探讨堆的概念、特点、常见应用、操作以及实现。

什么是堆?

在计算机科学中,堆是一种具有特殊属性的树形数据结构。堆通常被用来实现优先队列(Priority Queue),它允许快速地找到具有最高(或最低)优先级的元素。

数据结构之堆——算法与数据结构入门笔记(六)

堆的特点

堆的主要特点如下:

  1. 堆是一种完全二叉树结构,即除了最后一层外,其他层的节点都是满的,并且最后一层的节点从左到右依次填满,不能有间隔。
  2. 在最大堆中,每个节点的值都大于或等于其子节点的值。根节点的值是最大的。在最小堆中,每个节点的值都小于或等于其子节点的值。根节点的值是最小的。
  3. 堆通常被表示为一个数组,可以通过索引直接访问堆中的元素,堆的根节点通常是数组中的第一个元素。
  4. 堆的插入和删除操作的时间复杂度都为 O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是堆中元素的数量。

堆的应用

堆在计算机科学中有广泛的应用,其中一些主要应用包括:

  1. 堆排序
    堆排序是一种高效的排序算法,它利用堆的性质进行排序。它的时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn),并且具有原地排序的特性。
  2. 优先队列
    堆可以实现高效的优先级队列,允许以常数时间复杂度找到具有最高优先级的元素,并支持快速的插入和删除操作。
  3. Top K 问题
    在一组元素中,查找前 K 个最大(或最小)的元素是一个常见的问题。使用堆可以高效地解决这个问题,通过维护一个大小为 K 的最小堆或最大堆,可以快速地找到前 K 个元素。
  4. 图算法
    在图算法中,堆常用于实现最短路径算法(如Dijkstra算法)和最小生成树算法(如Prim和Kruskal算法)。
  5. 数据流中的中位数
    对于一个不断变化的数据流,查找其中的中位数也是一个常见的问题。使用两个堆(一个最大堆和一个最小堆),可以高效地实现对数据流中的中位数的查找。

为什么使用数组实现堆

用数组来实现树相关的数据结构也许看起来有点古怪,但是它在时间和空间上都是很高效的。

我们准备将上面图中的大根堆这样存储:

[ 50, 45, 40, 20, 25, 35, 30, 10, 15 ]

就这么多!我们除了一个简单的数组以外,不需要任何额外的空间。

如果我们不允许使用指针,那么我们怎么知道哪一个节点是父节点,哪一个节点是它的子节点呢?问得好!节点在数组中的位置 index 和它的父节点以及子节点的索引之间有一个映射关系。

如果 i 是节点的索引,那么下面的公式就给出了它的父节点和子节点在数组中的位置:

parent(i) = floor((i - 1)/2)
left(i)   = 2i + 1
right(i)  = 2i + 2

注意:right(i) 就是简单的 left(i) + 1。左右节点总是处于相邻的位置。

我们将这些公式放到前面的例子中验证一下。

Node Array index (i) Parent index Left child Right child
50 0 -1 1 2
45 1 0 3 4
40 2 0 5 6
20 3 1 7 8
25 4 1 9 10
35 5 2 11 12
30 6 2 13 14
10 7 3 15 16
15 8 3 17 18

注意:根节点(50)没有父节点,因为 -1 不是一个有效的数组索引。同样,节点(25),(35),(30),(10)和(15)没有子节点,因为这些索引已经超过了数组的大小,所以我们在使用这些索引值的时候需要保证是有效的索引值。

复习一下,在最大堆中,父节点的值总是要大于(或者等于)其子节点的值。这意味下面的公式对数组中任意一个索引 i 都成立:

array[parent(i)] >= array[i]

可以用上面的例子来验证一下这个堆属性。

如你所见,这些公式允许我们不使用指针就可以找到任何一个节点的父节点或者子节点。

堆的基本操作

以下是堆的一些基本操作:

  1. 插入:将一个元素插入到堆中,并保持堆的特性。
  2. 删除根节点:删除堆的根节点,并保持堆的特性。
  3. 获取根节点:获取堆的根节点的值,通常是堆中最大或最小的值。
  4. 堆化(Heapify):对一个无序的数组进行堆化操作,将其转换为一个堆。

C语言

以下是使用C语言实现堆(包括创建堆、插入数据、删除根结点、获取根节点和堆化等基础操作)的示例代码:

#include <stdio.h>

#define MAX_HEAP_SIZE 100

typedef struct {
    int heap[MAX_HEAP_SIZE];
    int size;
} Heap;

void initializeHeap(Heap *h) {
    h->size = 0;
}

void insert(Heap *h, int value) {
    if (h->size >= MAX_HEAP_SIZE) {
        printf("Heap is full.\n");
        return;
    }

    int i = h->size;
    h->heap[i] = value;
    h->size++;

    // 调整堆的结构
    while (i > 0 && h->heap[(i - 1) / 2] < h->heap[i]) {
        int temp = h->heap[i];
        h->heap[i] = h->heap[(i - 1) / 2];
        h->heap[(i - 1) / 2] = temp;

        i = (i - 1) / 2;
    }
}

int removeRoot(Heap *h) {
    if (h->size <= 0) {
        printf("Heap is empty.\n");
        return -1;
    }

    int root = h->heap[0];
    h->size--;
    h->heap[0] = h->heap[h->size];

    // 调整堆的结构
    int i = 0;
    while (2 * i + 1 < h->size) {
        int leftChild = 2 * i + 1;
        int rightChild = 2 * i + 2;
        int largerChild = leftChild;

        if (rightChild < h->size && h->heap[rightChild] > h->heap[leftChild]) {
            largerChild = rightChild;
        }

        if (h->heap[i] >= h->heap[largerChild]) {
            break;
        }

        int temp = h->heap[i];
        h->heap[i] = h->heap[largerChild];
        h->heap[largerChild] = temp;

        i = largerChild;
    }

    return root;
}

void heapify(Heap *h, int arr[], int n) {
    initializeHeap(h);

    // 将数组元素逐个插入堆中
    for (int i = 0; i < n; i++) {
        insert(h, arr[i]);
    }
}

int getRoot(Heap *h) {
    if (h->size <= 0) {
        printf("Heap is empty.\n");
        return -1;
    }

    return h->heap[0];
}

int main() {
    Heap h;
    initializeHeap(&h);

    insert(&h, 5);
    insert(&h, 2);
    insert(&h, 10);
    insert(&h, 8);

    int root = removeRoot(&h);
    printf("Root: %d\n", root);

    int arr[] = {9, 4, 7, 1, 3};
    int arrSize = sizeof(arr) / sizeof(arr[0]);

    heapify(&h, arr, arrSize);

    printf("Root: %d\n", getRoot(&h));

    return 0;
}

结论

堆是一种重要的数据结构,它提供了高效的数据存储和检索方式。我们可以使用数组来实现堆,并实现插入、删除和堆化等操作。堆在排序、优先队列、Top K 问题、图算法以及中位数查找等方面具有广泛的应用。

希望这篇博客能够帮助你理解堆的概念、应用和实现。文章来源地址https://www.toymoban.com/news/detail-508060.html

到了这里,关于数据结构之堆——算法与数据结构入门笔记(六)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构之堆

    目录 前言 堆的概念与结构 堆的实现  堆的初始化 堆的销毁 堆的显示 堆的插入 堆的向上调整算法 堆的删除 堆的向下调整算法 堆的判空 获取堆顶元素  堆的数据个数 堆的创建 二叉树的顺序结构存储即使用数组存储,而 数组存储适用于完全二叉树 , 完全二叉树不会存在空

    2024年02月07日
    浏览(20)
  • 数据结构之堆的结构与实现

    目录 一、堆的概念及结构 1.1堆的概念  1.2堆的性质 1.3堆的结构 二、堆的实现 2.1堆向下调整算法(父亲与孩子做比较)  2.2堆的向上调整算法(孩子与父亲做比较) 2.3堆的创建(向下建堆)  2.4向下建堆的时间复杂度 2.5堆的插入 2.6堆的删除 2.7堆的完整代码实现 三、堆的应

    2024年02月08日
    浏览(31)
  • 【数据结构之堆的实现】

    前言: 前篇学习了 数据结构之树和二叉树的基本概念知识,那么这篇继续学习怎么实现基本的操作。所以先建议看完上篇知识点,才有助于消化知识和理解。 / 知识点汇总 / 概念 :堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。堆通常是一个可以被看

    2024年01月19日
    浏览(30)
  • 数据结构之堆的应用

    在我们学习了堆之后我们知道,无论是大堆还是小堆,堆顶的元素要么最大,要么最小。 对于堆插入的时间复杂度为O(logn)也就是向上调整算法的复杂度,删除一个堆中的元素为O(logn),堆在我们日常生活中还是常用到的。 目录 1.top k问题(优质筛选问题) 2.堆排序 1.向

    2024年02月08日
    浏览(35)
  • 【数据结构--八大排序】之堆排序

    💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃 个人主页 :阿然成长日记 👈点击可跳转 📆 个人专栏: 🔹数据结构与算法🔹C语言进阶 🚩 不能则学,不知则问,耻于问人,决无长进 🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍 口诀:排降序,建小

    2024年02月08日
    浏览(29)
  • 数据结构初阶--二叉树的顺序结构之堆

    目录 一.堆的概念及结构 1.1.堆的概念 1.2.堆的存储结构 二.堆的功能实现 2.1.堆的定义 2.2.堆的初始化 2.3.堆的销毁 2.4.堆的打印 2.5.堆的插入 向上调整算法 堆的插入 2.6.堆的删除 向下调整算法 堆的删除 2.7.堆的取堆顶元素 2.8.堆的判空 2.9.堆的求堆的大小 三.堆的创建 3.1.向上调

    2024年02月14日
    浏览(31)
  • 【数据结构初阶】之堆(C语言实现)

    前言 :在二叉树基础篇我们提到了二叉树的顺序实现,今天让我们来学习一下特殊的二叉树———堆的相关知识。 📃 博客主页: 小镇敲码人 💞 热门专栏:数据结构与算法 🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏 🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月

    2024年04月09日
    浏览(71)
  • 数据结构之堆的实现(图解➕源代码)

            首先明确堆是一种特殊的完全二叉树,分为大根堆和小根堆,接下来我们就分别介绍一下这两种不同的堆。         在大堆里面: 父节点的值  ≥  孩子节点的值          我们的兄弟节点没有限制,只要保证 每个父节点都≥孩子节点 就行。         在小堆

    2024年02月06日
    浏览(34)
  • 数据结构学习分享之堆的详解以及TopK问题

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:数据结构学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你了解更多数据结构的知识   🔝🔝 本章就给大家带来久违的堆的知识,如果你还不知道数的相关知识,或者什么是完全二叉树,请跳转 树的介绍, 本章的堆结

    2024年02月05日
    浏览(70)
  • 数据结构之堆排序以及Top-k问题详细解析

    个人主页:点我进入主页 专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶 C语言刷题       数据结构初阶 欢迎大家点赞,评论,收藏。 一起努力 目录 1.前言 2.堆排序 2.1降序排序 2.2时间复杂度 3.Top-k问题 4.总结         在上一篇文

    2024年02月05日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包