JavaScript和数据结构---栈和队列

参考教材《数据结构考研复习指导》

文章目录

      • 队列
      • 循环队列
      • 优先队列
      • 栈的应用---括号匹配算法

栈和队列是操作受限的线性表, 比如: 不可以随便读取栈和队列中间的某个数据

栈是一个先进后出的数据结构, 只允许一端进行插入或者删除操作的线性表
进栈顺序依次为: 1, 2, 3, 4
出栈顺序依次为: 4, 3, 2, 1
例如: 往箱子里面放书(箱子和书一样大小), 要想拿出其中一本书, 是不是需要把这本书上面的所有的书都拿出来

JavaScript和数据结构---栈和队列_第1张图片

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

    /**
     * 往栈添加数据
     *
     * @param {*} element
     * @memberof Stack
     */
    push(element) {
        this.items.push(element);
    }

    /**
     * 弹出数据同时返回弹出的值
     * 
     * @returns 弹出的元素值
     * @memberof Stack
     */
    pop() {
        return this.items.pop();
    }


    /**
     *查看栈顶元素返回栈顶元素
     *
     * @returns
     * @memberof Stack
     */
    peek() {
        return this.items[this.items.length - 1];
    }

    /**
     * 判断栈是否为空
     * 
     * @returns 队列是否为空
     * @memberof Stack
     */
    isEmpty() {
        return this.items.length === 0;
    }

    /**
     * 清空栈所有内容
     *
     * @memberof Stack
     */
    clear() {
        this.items = [];
    }


    /**
     * 返回队列的长度
     *
     * @returns 返回队列的长度
     * @memberof Stack
     */
    size() {
        return this.items.length;
    }


    /**
     * 将栈内容以字符串内容输出
     *
     * @memberof Stack
     */
    print() {
        console.log(this.items.toString());
    }
}

相关题目

队列

队列, 先进先出, 只允许在表的一端进行插入, 而在表的另一端进行删除.
例如: 排队买票, 先排队的人先买到票

JavaScript和数据结构---栈和队列_第2张图片

JavaScript和数据结构---栈和队列_第3张图片


class Queue {
    constructor() {
        this.items = [];
    }
    /**
     * 将元素推入队列尾部
     *
     * @param {*} element
     * @memberof Queue
     */
    enqueue(element) {
        this.items.push(element);
    }

    /**
     * 将队列中第一个元素弹出
     *
     * @returns
     * @memberof Queue
     */
    dequeue() {
        return this.items.shift();
    }

    /**
     * 查看队列第一个元素
     * 
     * @returns 返回队列第一个元素
     * @memberof Queue
     */
    front() {
        return this.items[0];
    }

    /**
     *判断队列是否为空
     *
     * @returns 返回是否为空
     * @memberof Queue
     */
    isEmpty() {
        return this.items.length === 0;
    }

    /**
     *打印队列元素
     *
     * @memberof Queue
     */
    print() {
        console.log(this.items.toString());
    }

    /**
     *返回队列的长度
     *
     * @returns 返回队列的长度
     * @memberof Queue
     */
    size(){
        return this.items.length;
    }
}

循环队列

出自王道考研
JavaScript和数据结构---栈和队列_第4张图片
JavaScript和数据结构---栈和队列_第5张图片

在循环队列中, 头指针和尾指针的变化
head = (head + 1) % array.length
rear= (rear+ 1) % array.length

取模的目的: 因为是是一个循环队列, 但是实质上是一个普通数组, 要想循环, 那就需要无限取出数组下标, 下标的范围永远都是
0 ~ (array.length - 1), +1后对数组长度取模,其实就相当于求出了经过一次循环后的下标.


/**
 * 循环队列
 */
class CircularQueue {
    constructor(k) {
        // 长度需要限制, 来达到空间的利用, k代表空间的长度
        this.size = k;
        this.items = [];
        
        // 当然可以用数组索引来做, 那么就可以不需要front, read
        // 指向首元素
        this.front = 0;
        // 指向尾元素
        this.rear = 0;
    }

    /**
     *判断循环队列是否为空
     *
     * @returns 判断循环队列是否为空
     * @memberof CircularQueue
     */
    isEmpty() {
        return this.front === this.rear;
    }


    /**
     *判断循环队列是否满
     *
     * @returns
     * @memberof CircularQueue
     */
    isFull() {
        // 尾指针指向的是最后一个元素的后面一位
        // 取模的目的就是可以无限取出 0 ~ this.size之间的数
        return (this.rear + 1) % this.size === this.front;
    }


    /**
     *元素入队
     *
     * @param {*} element
     * @returns 是否入队成功
     * @memberof CircularQueue
     */
    enQueue(element) {
        if (this.isFull()) {
            return false;
        }
        if (this.isEmpty()) {
            this.front = 0;
        }

        // 入队
        this.items[this.rear] = element;

        /**
         * 尾指针加1, 
         * 取模的目的就是可以无限取出 0 ~ this.size - 1之间的数
         */
        this.rear = (this.rear + 1) % this.size;

        return true;
    }


    /**
     *元素出队
     *
     * @returns 返回出队的元素
     * @memberof CircularQueue
     */
    deQueue() {
        if (this.isEmpty()) {
            return false;
        }
        // 删除队列头元素
        this.items.splice(this.front, 1);

        // 头指针加一
        this.front = (this.front + 1) % this.size;

        return true;
    }

    /**
     *获取队列头元素
     *
     * @returns
     * @memberof CircularQueue
     */
    peek() {
        if (this.isEmpty()) {
            return false;
        }
        return this.items[this.front];
    }

    /**
     *获取队列尾元素
     *
     * @returns
     * @memberof CircularQueue
     */
    tail() {
        if (this.isEmpty()) {
            return false;
        }
        return this.items[this.rear - 1];
    }

    /**
     *打印队内元素
     *
     * @memberof CircularQueue
     */
    print() {
        console.log(this.items.toString());
    }
}

let circularQueue = new CircularQueue(5);
circularQueue.enQueue(5);
circularQueue.enQueue(6);
circularQueue.enQueue(7);
circularQueue.deQueue();
circularQueue.print();

优先队列

第一种


/**
 * 根据优先级,进行入队操作
 * 例如: 医院看病, 病情严重的优先诊断
 */
class PriorityQueue extends Queue {

    /**
     * ****************第一种做法****************
     * 
     * 在插入的时候通过优先级排好位置
     *
     * @param {*} element 要插入的元素
     * @param {*} priority 优先级
     * @memberof PriorityQueue
     */
    enqueue(element, priority) {

        if (this.isEmpty()) {
            this.items.push({
                element,
                priority
            });
        } else {
            // 这里一定要加else, 如果不加的话, 第一次队列为空, 会经过if添加一次
            // 然后!added 又会添加一次
            let added = false;

            // 越小优先级越高
            for (let i = 0; i < this.items.length; i++) {

                // 说明待插入的优先级高, 因此进行插入
                if (priority < this.items[i].priority) {
                    this.items.splice(i, 0, {
                        element,
                        priority
                    });
                    added = true;
                    break;
                }
            }
            //如果要添加的priority的值大于item的所有元素,直接添加在末尾即可
            if (!added) {
                this.items.push({
                    element,
                    priority
                })
            }
        }
    }
}
let priorityQueue = new PriorityQueue();
priorityQueue.enqueue("chenjiang", 2);
priorityQueue.enqueue("chengmengting", 1);
priorityQueue.print();

第二种

class PriorityQueue2 extends Queue {

    enqueue(element, priority) {
        this.items.push({
            element,
            priority
        })
    }
    /**
     * ****************第二种做法****************
     *不管入队排序, 出队的时候看看哪个元素优先级高, 就想出来
     *
     * @returns
     * @memberof PriorityQueue
     */
    dequeue() {
        let dequeueItemIndex = 0;
        for (let i = 0; i < this.items.length; i++) {
            if (this.items[dequeueItemIndex].priority > this.items[i].priority) {
                dequeueItemIndex = i;
            }
        }
        return this.items.splice(dequeueItemIndex, 1)[0];
    }
}
let priorityQueue2 = new PriorityQueue2();
priorityQueue2.enqueue("chenjiang", 2);
priorityQueue2.enqueue("chengmengting", 1);
console.log(priorityQueue2.dequeue());

栈的应用—括号匹配算法

参考: https://www.cnblogs.com/xiabaoying/p/6559180.html

遇到左括号‘{’、‘[’、’(‘压入栈,栈的特点是后入先出,所以当遇到右括号‘}’、‘]’、’)'的时候,取出栈顶元素,是否满足读取的右括号,栈顶是与之相匹配的左括号。最后判断栈是否为空,为空证明该表达式没有问题,否则则说明这个表达式存在括号不匹配问题。

/**
 *
 *'{ [ ] }' => 输出:true
 * '( [ ) ]' => 输出:false
 * 
 * @param {*} str
 */
function check(str) {
    let stack = new Stack();
    let success = true;
    for (v of str) {
        switch (v) {
            case '(':
            case '[':
            case '{':
                stack.push(v);
                break;
            case ')':
            case ']':
            case '}':
                let temp = stack.pop();
                if (!((temp === '(' && v === ')') || (temp === '[' && v === ']') || (temp === '{' && v === '}'))) {
                    console.log("括号不匹配");
                    success = false;
                    return false;
                }
                break;
        }
    }
    if (success) {
        console.log("匹配成功了");
    }
    if (!stack.isEmpty()) {
        console.info('兄弟都匹配完了, 我还留在栈里面, 没有人匹配我吗?');
    }
}

check('{[]()}');

你可能感兴趣的:(#,JavaScript和数据结构,数据结构,javascript,栈,stack)