美文网首页
数据结构 - 循环队列

数据结构 - 循环队列

作者: Super曲江龙Kimi | 来源:发表于2020-03-03 21:37 被阅读0次
image.png

单向循环队列

可以使用数组来实现队列,并且各项接口也可以优化到 O(1) 的时间复杂度--这就是循环队列

// 环形队列 使用动态数组来实现队列 实现复杂度O(1)
const DEFAULT_CAPATICY = 10;
class CircleQueue {
    constructor(capaticy = DEFAULT_CAPATICY) {
        this.elements = new Array(capaticy);
        this.size = 0;
        // 头部指针
        this.front = 0;
    }

    // 清空队列
    clear() {
        this.elements = new Array(DEFAULT_CAPATICY);
        this.size = 0;
        this.front = 0;
    }

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

    // 获取队列size
    getSize() {
        return this.size;
    }

    // 入队列 入队列时不需要置front位置 复杂度O(1) 因为是循环的,所以不需要挪位置,使用front头部指针来定位
    enQueue(ele) {
        this.expandCapacity(this.size + 1);

        // 入队列是从最后入队列,不需要重置front的位置,就是没有元素的时候,只要在删除的时候重置front即可。
        this.elements[this.getRealIndex(this.size)] = ele;
        this.size++
    }

    // 出队列 复杂度 O(1)
    deQueue() {
        // 缓存头部元素
        let old = this.elements[this.front];
        // 删除头部元素
        this.elements[this.front] = null;
        // 重置头部指针到下一位
        this.front = this.getRealIndex(1);
        this.size--;
        return old;
    }

    // 获取队列头 复杂度 O(1)
    getFront() {
        return this.elements[this.front];
    }

    // 获取真正的index下标,因为循环下标会有差异
    getRealIndex(index) {
        let real = this.front + index;
        let capaticy = this.elements.length;
        return real % capaticy;
    }

    // 扩容 -- 如果已使用的容量已经大于等于容量需要扩容
    expandCapacity(capaticy) {
        let oldCapaticy = this.elements.length;
        if (capaticy <= oldCapaticy) return false;

        let newCapaticy = oldCapaticy + (oldCapaticy >> 1);
        let elements = new Array(newCapaticy);

        for (let i = 0; i < this.size; i++) {
            elements[i] = this.elements[this.getRealIndex(i)];
        }
        this.elements = elements;
        this.front = 0;
        console.log(`${oldCapaticy} -->扩容为--> ${newCapaticy}`);
    }

    toString() {
        return this.elements;
    }
}

循环双端队列

可以进行两端添加、删除操作的循环队列

// 双端环形队列
const DEFAULT_CAPATICY = 10;
class CircleDeQueue {
    constructor(capaticy = DEFAULT_CAPATICY) {
        this.elements = new Array(capaticy);
        this.size = 0;
        this.front = 0;
    }

    // 清空队列
    clear() {
        this.elements = new Array(DEFAULT_CAPATICY);
        this.size = 0;
        this.front = 0;
    }

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

    // 获取队列size
    getSize() {
        return this.size;
    }

    // 从头部插入元素 复杂度O(1)
    enQueueFront(ele) {
        this.expandCapacity(this.size + 1);

        // 获取头部前一个元素的下标 重置给头部指针front,再赋值
        this.elements[this.front = this.getRealIndex(-1)] = ele;
        this.size++
    }

    // 从尾部插入元素 复杂度 O(1)
    enQueueRear(ele) {
        this.expandCapacity(this.size + 1);

        // 获取尾部下一个插入位置的下标,再赋值,此时由于头部没有变化,所以不需要改变头部指针front,就是没有元素,front仍然是0或者之前的front位置,还是对的
        this.elements[this.getRealIndex(this.size)] = ele;
        this.size++
    }

    // 从头部出队列 复杂度 O(1)
    deQueueFront() {
        // 获取头部元素
        let old = this.elements[this.front];
        // 删除头部元素
        this.elements[this.front] = null;
        // 重置头部指针为下一个元素
        this.front = this.getRealIndex(1);
        this.size--;
        return old;
    }

    // 从尾部出队列, 复杂度 O(1)
    deQueueRear() {
        // 获取最后一个元素
        let realIndex = this.getRealIndex(this.size - 1);
        let old = this.elements[realIndex];
        // 删除最后一个元素,此时不需要更新头部指针,因为头部没有改变,就是如果剩一个元素时,删除后front仍然是之前的front位置,下次插入仍然插入在这个头部位置。
        this.elements[realIndex] = null;
        this.size--;
        return old;
    }

    // 获取队列头 复杂度 O(1)
    getFront() {
        return this.elements[this.front];
    }
    // 获取队列尾 复杂度 O(1)
    getRear() {
        return this.elements[this.getRealIndex(this.size - 1)]
    }

    // 获取真实的下标,支持负数
    getRealIndex(index) {
        let real = this.front + index;
        let capaticy = this.elements.length;
        return (real < 0 ? capaticy + real : real) % capaticy;
    }

    // 扩容 -- 如果已使用的容量已经大于等于容量需要扩容
    expandCapacity(capaticy) {
        let oldCapaticy = this.elements.length;
        if (capaticy <= oldCapaticy) return false;

        let newCapaticy = oldCapaticy + (oldCapaticy >> 1);
        let elements = new Array(newCapaticy);

        for (let i = 0; i < this.size; i++) {
            elements[i] = this.elements[this.getRealIndex(i)];
        }
        this.elements = elements;
        this.front = 0;
        console.log(`${oldCapaticy} -->扩容为--> ${newCapaticy}`);
    }

    toString() {
        return this.elements;
    }
}

相关文章

  • 数据结构-队列(Queue)-FIFO

    数据结构-队列(Queue)-FIFO 队列的接口设计 双端队列-Deque 循环队列-CircleQueue 双...

  • LeetCode 622. 设计循环队列

    622. 设计循环队列 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原...

  • leetcode622.设计循环队列

    题目链接 题解: 在我的文章数据结构之——队列与循环队列 中,有关于循环队列的设计,包括本题没有考虑过的resiz...

  • java.util.ArrayDeque源码解析

    准备知识 因为ArrayDeque使用了循环队列,所以首先要了解循环队列数据结构的原理。https://www.j...

  • 常见的数据结构

    常见的数据结构有: 数组 链表单链表、双向链表、循环链表、双向循环链表、静态链表 栈顺序栈、链式栈 队列普通队列、...

  • C语言数据结构——线性表链式循环队列(链表实现方式)

    队列相关知识及操作请参看上一章 C语言数据结构——线性表循环队列(动态数组实现方式) 一、链式队列 链式队列 : ...

  • 622 设计循环队列

    题目描述: 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被...

  • LeetCode 622——设计循环队列

    1. 题目 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被...

  • Leetcode622. 设计循环队列

    题目 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在...

  • 数据结构----静态队列(循环队列)

    静态循环队列几个问题 1.静态队列为什么必须是循环队列? 因为不管是入队还是出队,front和rear都是增长的,...

网友评论

      本文标题:数据结构 - 循环队列

      本文链接:https://www.haomeiwen.com/subject/uwmllhtx.html