浅谈 堆、栈、队列

堆、栈和队列是计算机科学中常见的数据结构和概念,它们在内存管理、算法设计和程序执行中扮演着不同的角色。它们各自有不同的实现方式和用途,彼此之间并没有直接的关系,但在某些场景下可以相互配合使用。

一、概念

1. 栈(Stack)

  • 定义: 栈是一种后进先出(LIFO, Last In First Out)的数据结构。栈中的元素只能从一端(称为栈顶)插入或删除。
  • 特点:
    • 只能从栈顶添加或移除元素。
    • 常见操作:push(压栈,插入元素)、pop(出栈,移除元素)、peek(查看栈顶元素)。
  • 用途:
    • 函数调用管理(调用栈)。
    • 表达式求值(例如逆波兰表达式)。
    • 撤销操作(如文本编辑器中的撤销操作)。

2. 队列(Queue)

  • 定义: 队列是一种先进先出(FIFO, First In First Out)的数据结构。队列中的元素只能从一端(称为队尾)插入,从另一端(称为队头)删除。
  • 特点:
    • 只能从队尾添加元素,从队头移除元素。
    • 常见操作:enqueue(入队,插入元素)、dequeue(出队,移除元素)、peek(查看队头元素)。
  • 用途:
    • 任务调度(例如操作系统中的进程调度)。
    • 广度优先搜索(BFS)算法。
    • 数据流处理(如缓冲区管理)。

3. 堆(Heap)

  • 定义: 堆是一种树形数据结构,通常用于实现优先队列。堆分为最大堆和最小堆:
    • 最大堆:每个节点的值都大于或等于其子节点的值。
    • 最小堆:每个节点的值都小于或等于其子节点的值。
  • 特点:
    • 堆是一种完全二叉树。
    • 通过堆顶元素来快速获取最大值或最小值。
    • 常见操作:insert(插入元素)、extract(移除堆顶元素)、heapify(堆化操作)。
  • 用途:
    • 优先队列的实现。
    • 堆排序。
    • 图的算法(如Dijkstra算法)。

4. 总结和关系

  • 栈和队列 都是线性数据结构,但它们的操作规则不同:栈是后进先出,而队列是先进先出。
  • 则是一种树形结构,用于快速访问优先级最高(或最低)的元素,可以看作是更复杂的队列实现。

虽然堆、栈、队列的用途和实现各异,但它们在不同的算法和数据处理场景中可能会相互配合。例如,堆可以用来实现优先队列,而栈和队列可以用来管理算法中的数据流。

二、问题

在js中,栈里面的元素在内存中是连续分布的么?

在 JavaScript 中,栈、队列和堆的数据结构并不像在某些低级语言(如 C 或 C++)中那样直接操作内存,因此它们在内存中的存储方式并不是完全连续的。

JavaScript 中的数组可以用于实现栈。虽然从逻辑上讲,栈的操作是对数组的“栈顶”进行操作,但在内存中,数组的元素并不保证是连续分布的。JavaScript 数组是对象,它们的元素可以存储在内存的不同位置,并且根据数组的增长和缩小,JavaScript 引擎可能会在后台进行内存重分配。

三、创建

栈(Stack)

栈可以使用 JavaScript 的数组来实现,因为数组自带的 pushpop 方法正好符合栈的“后进先出”(LIFO)特性。

class Stack {
    constructor() {
        this.items = [];
    }

    push(element) {
        this.items.push(element); // 入栈
    }

    pop() {
        return this.items.pop(); // 出栈
    }

    peek() {
        return this.items[this.items.length - 1]; // 查看栈顶元素
    }

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

    size() {
        return this.items.length; // 返回栈的大小
    }
}

队列(Queue)

队列也可以使用数组来实现,利用数组的 pushshift 方法来分别实现入队和出队操作。

class Queue {
    constructor() {
        this.items = [];
    }

    enqueue(element) {
        this.items.push(element); // 入队
    }

    dequeue() {
        return this.items.shift(); // 出队
    }

    front() {
        return this.items[0]; // 查看队头元素
    }

    isEmpty() {
        return this.items.length === 0; // 判断队列是否为空
    }

    size() {
        return this.items.length; // 返回队列的大小
    }
}

堆(Heap)

堆是一个完全二叉树结构,可以使用数组来表示树结构。下面是一个最小堆的简单实现:

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

    insert(value) {
        this.heap.push(value);
        this.bubbleUp();
    }

    bubbleUp() {
        let index = this.heap.length - 1;
        while (index > 0) {
            let parentIndex = Math.floor((index - 1) / 2);
            if (this.heap[index] >= this.heap[parentIndex]) break;

            [this.heap[index], this.heap[parentIndex]] = [this.heap[parentIndex], this.heap[index]];
            index = parentIndex;
        }
    }

    extractMin() {
        const min = this.heap[0];
        const end = this.heap.pop();
        if (this.heap.length > 0) {
            this.heap[0] = end;
            this.sinkDown(0);
        }
        return min;
    }

    sinkDown(index) {
        const length = this.heap.length;
        const element = this.heap[index];
        while (true) {
            let leftChildIdx = 2 * index + 1;
            let rightChildIdx = 2 * index + 2;
            let leftChild, rightChild;
            let swap = null;

            if (leftChildIdx < length) {
                leftChild = this.heap[leftChildIdx];
                if (leftChild < element) {
                    swap = leftChildIdx;
                }
            }

            if (rightChildIdx < length) {
                rightChild = this.heap[rightChildIdx];
                if (
                    (swap === null && rightChild < element) ||
                    (swap !== null && rightChild < leftChild)
                ) {
                    swap = rightChildIdx;
                }
            }

            if (swap === null) break;

            [this.heap[index], this.heap[swap]] = [this.heap[swap], this.heap[index]];
            index = swap;
        }
    }

    getMin() {
        return this.heap[0];
    }

    size() {
        return this.heap.length;
    }
}

总结

  • 栈和队列 使用数组来实现,因为它们的操作方式(push/poppush/shift)很符合数组的方法。
  • 使用数组来模拟树结构,实现优先队列。

在这些数据结构中,JavaScript 的内存管理由引擎自动处理,你无需关心元素在内存中的具体位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值