您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

如何构建最小和最大堆

时间:2023-11-13 13:00:36  来源:今日头条  作者:微风01

数据结构在计算机编程中非常重要,可以快速有效地组织、管理和存储数据。数据结构对于任何开发人员来说都是其工具包中绝对必要的技能。

此篇文章重点关注堆,这是一种特殊的基于树的数据结构,它实现了完整的二叉树。

如何构建最小和最大堆

什么是堆?

堆是一种高级的基于树的数据结构,主要用于排序和实现优先级队列。它们是完全二叉树,具有以下特征:

  • 除了叶节点(没有子节点的节点称为叶节点)之外,每个级别都已填充。
  • 每个节点最多有 2 个子节点。
  • 所有节点都尽可能远离左侧,这意味着每个子节点都位于其父节点的左侧。

如何构建最小和最大堆

堆使用完全二叉树来避免数组中出现漏洞。完全二叉树是每个节点最多有两个子节点的树,除了叶节点可以为空之外,所有级别的节点都是满的。堆是根据堆属性构建的,它将父节点键与其子节点键进行比较。

在本文的后面部分,我们将详细讨论基于最小堆属性构建的最小堆和基于最大堆属性构建的最大堆。

需要注意的是,堆并不总是排序的,它们遵循的关键条件是最大或最小元素放置在根节点(顶部)上,具体取决于它是最大堆还是最小堆。堆数据结构与堆内存不同。

堆的优点和缺点

优点:

  • 垃圾收集在堆内存上运行以释放对象使用的内存。
  • 堆很灵活,因为可以按任何顺序分配或删除内存。
  • 变量可以全局访问。
  • 它有助于找到最小和最大数字。

缺点:

  • 与堆栈相比,堆需要更多的执行时间。
  • 堆内存中的内存管理更加复杂,因为它是全局使用的。
  • 堆通常需要更多时间来计算。

堆数据结构的应用

堆对于查找数组中的最小或最大元素非常有效,并且对于顺序统计和选择算法很有用。从堆中获取最小值/最大值的时间复杂度为O(1),(恒定时间复杂度)。

优先级队列是基于堆结构设计的。它需要氧O ( log ( n ) ) 有效地插入(insert())和删除(delete())优先级队列中每个元素的时间。

堆实现的优先级队列用于流行的算法,例如:

  • 普利姆(Prim’s)算法
  • 迪杰斯特拉算法
  • 堆排序算法

堆中的基本操作

以下是实现堆数据结构时可能使用的基本操作:

  • heapify:重新排列堆中的元素以保持堆属性。
  • insert:将项目添加到堆中,同时保持其堆属性。
  • delete:删除堆中的项目。
  • extract:返回一个项目的值,然后将其从堆中删除。
  • isEmpty: boolean,如果boolean为空则返回true,如果有节点则返回false。
  • size:返回堆的大小。
  • getMax():返回堆中的最大值

如何构建最大堆

最大堆中的元素遵循最大堆属性。这意味着父节点的键始终大于两个子节点的键。要构建最大堆:

  • 在堆的开头(根)创建一个新节点。
  • 为其指定一个值。
  • 将子节点的值与父节点的值进行比较。
  • 如果父节点的值小于任一子节点的值(向左或向右),则交换节点。
  • 重复此操作,直到最大元素位于根父节点(此时可以说堆属性成立)。

将新元素插入堆时也可以遵循这些步骤。这里的关键是,无论在最大堆上执行什么操作,都必须维护堆属性。

要移除/删除最大堆中的根节点:

  • 删除根节点。
  • 将最后一层的最后一个子节点移动到根。
  • 将父节点与其子节点进行比较。
  • 如果父节点的值小于子节点,则交换它们,并重复直到满足堆属性。

让我们看一下代码中的样子。我们将使用JAVAScript实现最大堆。

JavaScript 中实现最大堆

在我们开始构建最大堆之前,先看一下我们将实现的一些方法及其用途:

  • _percolateUp():将堆属性从子节点恢复到根节点。
  • _maxHeapify():将堆属性从特定节点恢复到叶节点。
  • insert():将给定值附加到堆数组并根据元素的堆属性重新排列元素。在每个新插入中,堆均匀增长,并且大小增加一。
  • getMax():返回堆(根节点)中的最大值,不修改堆。注意这里的时间复杂度是常数时间氧(1)欧(1 )
  • removeMax():返回并删除堆中的最大值(想想pop())。该函数的时间复杂度为O ( log ( n ) ) 。

如果堆大小大于一,它将最大值存储到变量中,将该值与最后一个叶子交换,然后从堆中删除最大值。

如果堆只有一个元素,则删除并返回该元素的值,最后一个条件是如果堆为空,则返回 null。

该__percolateUp()方法在每个父节点上递归调用,直到到达根。对于要定位在 max-heap 属性之后的每个节点,我们__maxHeapify()从堆底部开始在该数组的每个索引处调用该方法。

class maxHeap {
    constructor() {
        this.heap = [];
        this.elements = 0;
    };

    insert(val) {
        if (this.elements >= this.heap.length) {
            this.elements = this.elements + 1;
            this.heap.push(val);
            this.__percolateUp(this.heap.length - 1);
        }
        else {
            this.heap[this.elements] = val;
            this.elements = this.elements + 1;
            this.__percolateUp(this.elements - 1);
        }
    };

    getMax() {
        if (this.elements !== 0)
            return this.heap[0];
        return null;
    };

    removeMax() {
        let max = this.heap[0];
        if (this.elements > 1) {
            this.heap[0] = this.heap[this.elements - 1];
            this.elements = this.elements - 1;
            this.__maxHeapify(0);
            return max
        } else if (this.elements === 1) {
            this.elements = this.elements - 1;
            return max;
        } else {
            return null;
        }
    };

    __percolateUp(index) {
        const parent = Math.floor((index - 1) / 2);
        if (index <= 0)
            return
        else if (this.heap[parent] < this.heap[index]) {
            let tmp = this.heap[parent];
            this.heap[parent] = this.heap[index];
            this.heap[index] = tmp;
            this.__percolateUp(parent);
        }
    };
    
    __maxHeapify(index) {
        let left = (index * 2) + 1;
        let right = (index * 2) + 2;
        let largest = index;
        if ((this.elements > left) && (this.heap[largest] < this.heap[left])) {
            largest = left
        }
        else if ((this.elements > right) && (this.heap[largest] < this.heap[right]))
            largest = right
        else if (largest !== index) {
            const tmp = this.heap[largest];
            this.heap[largest] = this.heap[index];
            this.heap[index] = tmp;
            this.__maxHeapify(largest);
        }
    };

    buildHeap(arr) {
        this.heap = arr;
        this.elements = this.heap.length;
        for (let i = this.heap.length - 1; i >= 0; i--) {
            this.__maxHeapify(i);
        }

    };
};
let heap = new maxHeap();

如何构建最小堆

直观上,我们可以说最小堆中的元素遵循最小堆属性,因为这与最大堆相反。父节点的键始终小于两个子节点的键。为了构建最小堆,我们:

  • 在堆的末尾(最后一层)创建一个新的子节点。
  • 将新键添加到该节点(将其附加到数组)。
  • 向上移动子节点,直到到达根节点并且满足堆属性。

要移除/删除最小堆中的根节点:

  • 删除根节点。
  • 将最后一个子项的密钥移至 root。
  • 将父节点与其子节点进行比较。
  • 如果父节点的值大于子节点,则交换它们,并重复直到满足堆属性。

在 JavaScript 中实现最小堆

在我们开始构建最小堆之前,请注意它的实现与最大堆类似。minHeapify()恢复堆属性。getMin()返回堆(根节点)中的最小值,而不修改堆。并removeMin()删除最小值并返回它。

class minHeap {
    constructor() {
        this.heap = []
        this.elements = 0;
    };

    insert(val) {
        if (this.elements >== this.heap.length) {
            this.elements = this.elements + 1
            this.heap.push(val);
            this.__percolateUp(this.heap.length - 1);
        }
        else {
            this.heap[this.elements] = val;
            this.elements = this.elements + 1;
            this.__percolateUp(this.elements - 1);
        }
    };
    
    getMin() {
        if (this.heap.length !== 0)
            return this.heap[0];
        return null;
    }

    removeMin() {
        const min = this.heap[0];
        if (this.elements > 1) {            
            this.heap[0] = this.heap[this.elements - 1];
            this.elements = this.elements - 1;
            this.__minHeapify(0);
            return min;
        } else if (this.elements == 1) {
            this.elements = this.elements - 1;
            return min;
        } else {
            return null;
        }
    };

    __percolateUp(index) {
        let parent = Math.floor((index - 1) / 2);
        if (index <= 0)
            return
        else if (this.heap[parent] > this.heap[index]) {
            let tmp = this.heap[parent];
            this.heap[parent] = this.heap[index];
            this.heap[index] = tmp;
            this.__percolateUp(parent);
        }
    };

    __minHeapify(index) {
        let left = (index * 2) + 1;
        let right = (index * 2) + 2;
        let smallest = index;
        if ((this.elements > left) && (this.heap[smallest] > this.heap[left])) {
            smallest = left;
        }
        if ((this.elements > right) && (this.heap[smallest] > this.heap[right]))
            smallest = right;
        if (smallest !== index) {
            let tmp = this.heap[smallest];
            this.heap[smallest] = this.heap[index];
            this.heap[index] = tmp;
            this.__minHeapify(smallest);
        }
    }

    buildHeap(arr) {
        this.heap = arr;
        this.elements = this.heap.length;
        for (let i = this.heap.length - 1; i >= 0; i--) {
            this.__minHeapify(i)
        }
    }
};

let heap = new minHeap();
heap.insert(12);
heap.insert(10);
heap.insert(-10);
heap.insert(100);

console.log(heap.getMin()); //你应该得到-10

let newheap = new minHeap();
let arr = [12, 6, 8, 3, 16, 4, 27];
newheap.buildHeap(arr) //使用数组中的元素构建这个堆
console.log(newheap.getMin()) //这里记录了 3

newheap.removeMin();

console.log(newheap.getMin())

堆进阶:将最大堆转换为最小堆

让我们通过实践挑战使我们的学习更进一步。我们的目标是将最大堆转换为最小堆。跟随我们的代码解决方案看看它是如何完成的。

问题描述:实现一个函数convertMax(maxHeap),将二进制最大堆转换为二进制最小堆,其中maxHeap是 格式的数组maxHeap(即父级大于子级)。您的输出应该是转换后的数组。

输入示例:

maxHeap = [9,4,7,1,-2,6,5]

示例输出:

result = [-2,1,5,9,4,6,7]

如何构建最小和最大堆

function convertMax(maxHeap) {
    return maxHeap
}

上面的代码解决方案可以运行。我们可以将给定视为maxHeap一个规则的元素数组,并将其重新排序,以便它准确地表示最小堆。该函数通过在每个节点上convertMax()调用该函数,从最低父节点开始恢复所有节点上的堆属性。minHeapify()

构建堆的时间复杂度为O ( n )。对于这个问题也是如此。

function minHeapify(heap, index) {
    var left = index * 2;
    var right = (index * 2) + 1;
    var smallest = index;

    if ((heap.length > left) && (heap[smallest] > heap[left])) {
        smallest = left
    }
    if ((heap.length > right) && (heap[smallest] > heap[right]))
        smallest = right
    if (smallest != index) {
        var tmp = heap[smallest]
        heap[smallest] = heap[index]
        heap[index] = tmp
        minHeapify(heap, smallest)
    }
    return heap;
}

function convertMax(maxHeap) {
    for (var i = Math.floor((maxHeap.length) / 2); i > -1; i--)
        maxHeap = minHeapify(maxHeap, i)
    return maxHeap
}

var maxHeap = [9,4,7,1,-2,6,5]
console.log(convertMax(maxHeap))

常见的问题

以下是一些常见的挑战,有助于测试您对堆数据结构的了解。可能会在编码面试中看到以下问题:

  • 将最大堆转换为最小堆
  • 查找数组中 k 个最小元素
  • 查找数组中第 k 个最大元素
  • 检查给定数组是否代表最小堆
  • 合并M个可变长度的排序列表
  • 从每个给定列表中查找至少包含一个元素的最小范围

尝试解决这些问题,对堆数据结构会有更深入的了解!

总结

总结来说,构建最小堆和最大堆的步骤都是逐个插入元素,并通过与父节点的比较来调整元素的位置,以满足堆的性质。这样可以构建一个高效的数据结构,用于高效地插入、删除和访问优先级顺序的元素。



Tags:   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
百亿私募持仓曝光,扎堆ETF有何玄机?
随着公募基金年报披露,最新机构ETF持仓中的私募ETF持仓,颇为值得关注。据私募排排网统计,截至2023年末,共368只私募基金现身290只上市公募基金的前十大持有人名单,其中包含223只E...【详细内容】
2024-04-06  Search:   点击:(4)  评论:(0)  加入收藏
AI时代三大核心曝光,数据要素重要性凸显,机构扎堆看好这些超跌概念股
数据要素重要性持续凸显。上周末,AI大模型消息火爆,阿里通义千问、百度文心一言、360智脑等AI大模型纷纷宣布推出或预计推出自身长文本模型。AI三大核心要素(算法、算力、数据),...【详细内容】
2024-03-25  Search:   点击:(10)  评论:(0)  加入收藏
券商开年扎堆调研人工智能 多只“+AI”个股被调高评级
春节假期后,A股人工智能板块形成一片“热火朝天”的景象。截至2月28日,最近8个交易日,Wind AIGC指数涨逾22%,Sora指数的涨幅接近20%。券商也在紧锣密鼓地调研人工智能概念股。据...【详细内容】
2024-03-01  Search:   点击:(37)  评论:(0)  加入收藏
 2024年考研成绩公布,高分频现400+“扎堆”,考生担忧国家线上涨
因为各大院校的扩招,大学生早就已经变得不再吃香,很多大学生面临的就业情况都是特别严峻的,和大学生在就业市场严重饱和有着脱不开的关系。如今的大学生和以前大学生的含金量是...【详细内容】
2024-02-26  Search:   点击:(56)  评论:(0)  加入收藏
数据资产“入表”倒计时,机构扎堆持仓概念股出炉
数据资产“入表”进入倒计时按照今年8月财政部印发的《企业数据资源相关会计处理暂行规定》(以下简称《暂行规定》),从2024年1月1日起,数据资源将被视为一种资产纳入财务报表。...【详细内容】
2023-12-29  Search:   点击:(69)  评论:(0)  加入收藏
巨人网络、三七互娱等出手,游戏公司扎堆抛回购计划
12月25日,游戏股再度下挫,恺英网络(002517.SZ)、巨人网络(002558.SZ)均连续两日跌停,机构继续多空分歧。当日,8家游戏公司抛出回购或增持计划。巨人网络公告,实际控制人、董事长史玉...【详细内容】
2023-12-26  Search:   点击:(74)  评论:(0)  加入收藏
如何应对 RocketMQ 消息堆积
这篇文章,我们聊聊如何应对 RocketMQ 消息堆积。图片1 基础概念消费者在消费的过程中,消费的速度跟不上服务端的发送速度,未处理的消息会越来越多,消息出现堆积进而会造成消息消...【详细内容】
2023-12-21  Search:   点击:(71)  评论:(0)  加入收藏
如何构建最小和最大堆
数据结构在计算机编程中非常重要,可以快速有效地组织、管理和存储数据。数据结构对于任何开发人员来说都是其工具包中绝对必要的技能。此篇文章重点关注堆,这是一种特殊的基于...【详细内容】
2023-11-13  Search:   点击:(232)  评论:(0)  加入收藏
如何构建六层大数据堆栈架构
面对大数据挑战而扩展其传统基础设施的企业应考虑使用专门构建的软件产品和服务来构建大数据堆栈架构。大数据堆栈是一套互补的软件技术,用于管理和分析对于传统技术来说太大...【详细内容】
2023-11-10  Search:   点击:(203)  评论:(0)  加入收藏
C#开发三个重要的内存区域:托管堆内存、非托管堆内存和栈内存
对内存的管理和操作大部分都是由 .NET 运行时处理的。开发者无需过多关注内存管理的细节,因为托管堆内存的垃圾回收机制可以自动处理对象的分配和释放。然而,在特定情况下,如与...【详细内容】
2023-11-01  Search:   点击:(291)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(5)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(12)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(8)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(10)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(8)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(5)  评论:(0)  加入收藏
站内最新
站内热门
站内头条