百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

如何构建最小和最大堆(如何构造最小堆)

toyiye 2024-07-08 00:31 15 浏览 0 评论

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

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

今天,我们将介绍:

  • 什么是堆?
  • 堆中的基本操作
  • 如何构建最大堆
  • 如何构建最小堆
  • 堆进阶(将最大堆转换为最小堆)
  • 常见的问题

什么是堆?

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

  • 除了叶节点(没有子节点的节点称为叶节点)之外,每个级别都已填充。
  • 每个节点最多有 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个可变长度的排序列表
  • 从每个给定列表中查找至少包含一个元素的最小范围

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

总结

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

延伸阅读:

堆栈与堆(Stack vs Heap):有什么区别?图文并茂拆解代码运行!

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码