JavaScript实现最大堆(Max Heap)的完整指南 | 优先队列数据结构

2025/3/15
本文详细介绍了如何使用JavaScript实现最大堆(Max Heap),包括插入、删除、获取堆顶元素等操作,并提供了完整的代码示例和解释。
JavaScript代码示例展示最大堆的实现,包含插入、删除和获取堆顶元素的操作

最大堆(Max Heap)是一种特殊的二叉树结构,其中每个父节点的值都大于或等于其子节点的值。最大堆通常用于实现优先队列。下面是一个使用 JavaScript 实现最大堆的示例代码:

class MaxHeap {
    constructor() {
        this.heap = [];
    }

    // 获取父节点索引
    getParentIndex(index) {
        return Math.floor((index - 1) / 2);
    }

    // 获取左子节点索引
    getLeftChildIndex(index) {
        return 2 * index + 1;
    }

    // 获取右子节点索引
    getRightChildIndex(index) {
        return 2 * index + 2;
    }

    // 交换两个节点的值
    swap(index1, index2) {
        [this.heap[index1], this.heap[index2]] = [this.heap[index2], this.heap[index1]];
    }

    // 插入新元素
    insert(value) {
        this.heap.push(value);
        this.heapifyUp();
    }

    // 上浮操作,确保堆的性质
    heapifyUp() {
        let index = this.heap.length - 1;
        while (index > 0) {
            const parentIndex = this.getParentIndex(index);
            if (this.heap[parentIndex] >= this.heap[index]) break;
            this.swap(parentIndex, index);
            index = parentIndex;
        }
    }

    // 删除堆顶元素
    extractMax() {
        if (this.heap.length === 0) return null;
        const max = this.heap[0];
        const last = this.heap.pop();
        if (this.heap.length > 0) {
            this.heap[0] = last;
            this.heapifyDown();
        }
        return max;
    }

    // 下沉操作,确保堆的性质
    heapifyDown() {
        let index = 0;
        const length = this.heap.length;
        while (true) {
            const leftChildIndex = this.getLeftChildIndex(index);
            const rightChildIndex = this.getRightChildIndex(index);
            let largestIndex = index;

            if (leftChildIndex < length && this.heap[leftChildIndex] > this.heap[largestIndex]) {
                largestIndex = leftChildIndex;
            }

            if (rightChildIndex < length && this.heap[rightChildIndex] > this.heap[largestIndex]) {
                largestIndex = rightChildIndex;
            }

            if (largestIndex === index) break;

            this.swap(index, largestIndex);
            index = largestIndex;
        }
    }

    // 获取堆顶元素
    peek() {
        return this.heap.length > 0 ? this.heap[0] : null;
    }

    // 获取堆的大小
    size() {
        return this.heap.length;
    }

    // 判断堆是否为空
    isEmpty() {
        return this.heap.length === 0;
    }
}

// 示例用法
const maxHeap = new MaxHeap();
maxHeap.insert(10);
maxHeap.insert(5);
maxHeap.insert(15);
maxHeap.insert(3);
maxHeap.insert(7);

console.log(maxHeap.extractMax()); // 输出: 15
console.log(maxHeap.extractMax()); // 输出: 10
console.log(maxHeap.extractMax()); // 输出: 7

代码说明:

  1. MaxHeap:定义了最大堆的数据结构。
  2. getParentIndexgetLeftChildIndexgetRightChildIndex:用于获取父节点和子节点的索引。
  3. swap:交换两个节点的值。
  4. insert:插入新元素并调用 heapifyUp 来维护堆的性质。
  5. heapifyUp:上浮操作,确保新插入的元素不会破坏堆的性质。
  6. extractMax:删除并返回堆顶元素,然后调用 heapifyDown 来维护堆的性质。
  7. heapifyDown:下沉操作,确保堆顶元素被删除后,堆的性质仍然保持。
  8. peek:获取堆顶元素但不删除。
  9. size:获取堆的大小。
  10. isEmpty:判断堆是否为空。

时间复杂度:

  • 插入操作 (insert):O(log n)
  • 删除堆顶元素 (extractMax):O(log n)
  • 获取堆顶元素 (peek):O(1)

这个实现是一个基础的最大堆,适用于大多数需要优先队列的场景。你可以根据具体需求对其进行扩展或优化。

上次更新:

相关文章

npx完全指南:前端开发必备工具详解 | 20年架构师深度解析

本文由20年前端架构师深入解析npx工具,涵盖其核心功能、优势、高级用法、最佳实践及与npm/yarn的区别比较,帮助开发者掌握这一现代前端开发利器。

·前端开发

Astro 静态站点生成器:构建高性能网站的最佳选择

Astro 是一个专注于构建快速、轻量级网站的静态站点生成器,支持多种前端框架,采用岛屿架构减少 JavaScript 加载,提升性能。

·前端开发

MySQL JSON数据类型支持与使用指南 | 详细解析与示例

本文详细解析了MySQL从5.7版本开始支持的JSON数据类型,包括版本支持、创建JSON字段、插入与查询JSON数据、修改JSON数据、生成JSON、索引优化、性能与应用场景、注意事项及示例全流程。

·后端开发

Weex 跨平台移动开发框架:核心特性与使用指南

Weex 是由阿里巴巴开源的跨平台移动开发框架,支持使用 Vue.js 或 Rax 构建高性能的 iOS、Android 和 Web 应用。本文详细解析了 Weex 的核心特性、架构、工作流程、组件和模块、开发工具、优缺点、应用场景及未来发展。

·前端开发

ECharts 与 DataV 数据可视化工具对比分析 | 选择指南

本文详细对比了 ECharts 和 DataV 两个常用的数据可视化工具,包括它们的设计目标、优缺点、使用场景和技术栈,帮助读者根据具体需求选择合适的工具。

·前端开发

前端部署后通知用户刷新页面的常见方案 | 单页应用更新提示

本文介绍了在前端部署后通知用户刷新页面的几种常见方案,包括WebSocket实时通知、轮询检查版本、Service Worker版本控制、版本号对比、自动刷新、使用框架内置功能以及第三方库。每种方案的优缺点和示例代码均有详细说明。

·前端开发

TypeScript 映射类型常见问题与解决方案 | 提升代码维护性

本文探讨了在使用 TypeScript 时,映射类型的不当使用可能导致的问题,如代码难以维护、类型推断不准确或性能问题,并提供了相应的解决方案和最佳实践。

·编程语言

TypeScript 交叉类型与联合类型:区别与最佳实践

本文详细解释了 TypeScript 中交叉类型(Intersection Types)和联合类型(Union Types)的区别,提供了使用场景、类型守卫、避免过度使用交叉类型的建议,以及如何通过工具辅助解决混淆问题。

·编程语言

TypeScript 类继承中的常见类型问题及解决方案 | TypeScript 开发指南

本文详细探讨了在 TypeScript 中使用类继承时可能遇到的常见类型问题,包括类型兼容性、构造函数、方法重写、访问修饰符、泛型类继承、抽象类以及类型断言等问题,并提供了相应的解决方案和代码示例。

·编程语言

TypeScript 函数重载:常见问题与解决方案

本文探讨了 TypeScript 中函数重载的常见问题,包括签名与实际实现不匹配、重载签名过多、与泛型结合时的类型推断问题等,并提供了相应的解决方案。

·编程语言