用链表实现双端队列python_JS中队列和双端队列实现及应用

队列

  • 队列
  • 双端队列数据结构
  • 应用用击鼓传花游戏模拟循环队列用双端对列检查一个词是否构成回文生成 1 到 n 的二进制数
1f33fea4067b5c0832d2bb13c80787b4.png

队列和双端队列

队列遵循先进后出(FIFO, 也称为先来先服务) 原则的. 日常有很多这样场景: 排队购票、银行排队等.

由对列的特性,银行排队为例, 队列应该包含如下基本操作:

  • 加入队列(取号) enqueue
  • 从队列中移除(办理业务离开) dequeue
  • 当前排队号码(呼叫下一个人) peek
  • 当前队列长度(当前排队人数) size
  • 判断队列是不是空 isEmpty
class Queue {    constructor() {        // 队列长度, 类数组 length        this.count = 0        // 队列中所有项        this.items = {}        // 记录对列头, 类数组 index        this.lowestCount = 0    }    enqueue(ele) {        this.items[this.count++] = ele    }    dequeue() {        if (this.isEnpty()) {            return undefined        }        const ele = this.items[this.lowestCount]        delete this.items[this.lowestCount]        this.lowestCount++        return ele    }    peek() {        if (this.isEnpty()) {            return        }        return this.items[this.lowestCount]    }    size() {        /**        * 当队列为非空时:        * 1. count 是长度        * 2. lowestCount 是下标        * 两者关系应该 lowestCount = count - 1        */        return this.count - this.lowestCount    }    isEnpty() {        return this.size() == 0    }    clear() {        this.items = {}        this.lowestCount = 0        this.count = 0    }    toString() {        if (this.isEnpty()) {            return ''        }        let objString = `${this.items[this.lowestCount]}`        for (let i = this.lowestCount + 1; i < this.count; i++) {        objString = `${objString}, ${this.items[i]}`        }        return objString   }}

双端队列(deque 或 double-ended queue)

什么是双端队列?

允许从前端(front)和后端(rear)添加元素, 遵循的原则先进先出或后进先出.

双端队列可以理解为就是栈(后进先出)和队列(先进先出)的一种结合体. 既然是结合那么相应的操作也支持队列,栈的操作. 下面我们定义一个 Deque

  • addFront
  • removeFront
  • addBack
  • removeBack
  • clear
  • isEmpty
  • peekFront
  • prekBack
  • size
  • toString
class Deque {    constructor() {        this.items = {}        this.count = 0        this.lowestCount = 0    }    addFront(ele) {        if (this.isEmpty()) {            this.items[this.count] = ele        } else if (this.lowestCount > 0) {            this.lowestCount -= 1            this.items[this.lowestCount] = ele        } else {            for (let i = this.count; i > 0; i--) {                this.items[i] = this.items[i - 1]            }            this.items[0] = ele        }            this.count++            return ele        }    removeFront() {        if (this.isEmpty()) {            return        }        const delEle = this.items[this.lowestCount]        delete this.items[this.lowestCount]        this.lowestCount++        return delEle    }    addBack(ele) {        this.items[this.count] = ele        this.count++    }    removeBack() {        if (this.isEmpty()) {            return        }        const delEle = this.items[this.count - 1]        delete this.items[this.count - 1]        this.count--        return delEle    }    peekFront() {        if (this.isEmpty()) {            return        }        return this.items[this.lowestCount]    }    peekBack() {        if (this.isEmpty()) {            return        }        return this.items[this.count - 1]    }    size() {        return this.count - this.lowestCount    }    isEmpty() {        return this.size() === 0    }    clear() {        this.items = {}        this.count = 0        this.lowestCount = 0    }    toString() {        if (this.isEmpty()) {            return ''        }        let objString = `${this.items[this.lowestCount]}`        for (let i = this.lowestCount + 1; i < this.count; i++){            objString = `${objString}, ${this.items[i]}`        }        return objString    }}

队列的应用

击鼓传花游戏

击鼓传花游戏: 简单描述就是一群人围成一个圈传递花,喊停的时花在谁手上就将被淘汰(每个人都可能在前端,每个参与者在队列位置会不断变化),最后只剩下一个时就是赢者. 更加详细可以自行查阅.

下面通过代码实现:

function hotPotato(elementsList, num) {    // 创建一个容器    const queue = new Queue()    const elimitatedList = []    // 把元素(参赛者)加入队列中    for (let i = 0, len = elementsList.length; i < len; i++) {        queue.enqueue(elementsList[i])    }    /**    * 击鼓传花    * 首先队列规则: 先进先出    * 那么在传花过程中,任何一个元素都可能是前端, 在传花的过程中应该就是前端位置不断变化.    * 当喊停的时(num 循环完), 也就是花落在谁手(谁在前端)则会被淘汰*(移除队列)    */    while (queue.size() > 1) {        for (let j = 0; j < num; j++) {            queue.enqueue(queue.dequeue())        }        elimitatedList.push(queue.dequeue())    }    return {        winer: queue.dequeue(),        elimitatedList    }}

代码运行如下:

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]console.log(hotPotato(arr, Math.ceil(Math.random() * 10))) // { winer: 5, elimitatedList: [4, 8, 2, 7, 3,10, 9, 1, 6]}console.log(hotPotato(arr, Math.ceil(Math.random() * 10))) // { winer: 5, elimitatedList: [4, 8, 2, 7, 3,10, 9, 1, 6]}console.log(hotPotato(arr, Math.ceil(Math.random() * 10))) // { winer: 8, elimitatedList: [10, 1, 3, 6, 2,9, 5, 7, 4]}

判断回文

上一篇栈中也有涉及回文的实现, 下面我们通过双端队列来实现同样的功能.

function palindromeChecker(aString) {    if (!aString || typeof aString !== 'string' || !aString.trim().length) {        return false    }    const deque = new Deque()    const lowerString = aString.toLowerCase().split(' ').join('')    // 加入队列    for (let i = 0; i < lowerString.length; i++) {        deque.addBack(lowerString[i])    }    let isEqual = true    let firstChar = ''    let lastChar = ''    while (deque.size() > 1 && isEqual) {        firstChar = deque.removeFront()        lastChar = deque.removeBack()        if (firstChar != lastChar) {            isEqual = false        }    }    return isEqual}

下面通过代码演示下:

console.log(palindromeChecker('abcba')) // true 当前为回文
31faa1d1a317ece4d564f0d4e1a457b9.png

生成 1 到 n 的二进制数

function generatePrintBinary(n) {    var q = new Queue()    q.enqueue('1')    while (n-- > 0) {        var s1 = q.peek()        q.dequeue()        console.log(s1)        var s2 = s1        q.enqueue(s1 + '0')        q.enqueue(s2 + '1')    }}generatePrintBinary(5) // => 1 10 11 100 101
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* * 基于双向链表实现双端队列结构 */ package dsa; public class Deque_DLNode implements Deque { protected DLNode header;//指向头节点(哨兵) protected DLNode trailer;//指向尾节点(哨兵) protected int size;//队列元素的数目 //构造函数 public Deque_DLNode() { header = new DLNode(); trailer = new DLNode(); header.setNext(trailer); trailer.setPrev(header); size = 0; } //返回队列元素数目 public int getSize() { return size; } //判断队列是否为空 public boolean isEmpty() { return (0 == size) ? true : false; } //取首元素(但不删除) public Object first() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return header.getNext().getElem(); } //取末元素(但不删除) public Object last() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return trailer.getPrev().getElem(); } //在队列前端插入新节点 public void insertFirst(Object obj) { DLNode second = header.getNext(); DLNode first = new DLNode(obj, header, second); second.setPrev(first); header.setNext(first); size++; } //在队列后端插入新节点 public void insertLast(Object obj) { DLNode second = trailer.getPrev(); DLNode first = new DLNode(obj, second, trailer); second.setNext(first); trailer.setPrev(first); size++; } //删除首节点 public Object removeFirst() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = header.getNext(); DLNode second = first.getNext(); Object obj = first.getElem(); header.setNext(second); second.setPrev(header); size--; return(obj); } //删除末节点 public Object removeLast() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = trailer.getPrev(); DLNode second = first.getPrev(); Object obj = first.getElem(); trailer.setPrev(second); second.setNext(trailer); size--; return(obj); } //遍历 public void Traversal() { DLNode p = header.getNext(); while (p != trailer) { System.out.print(p.getElem()+" "); p = p.getNex

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值