数据结构-队列

风流意气都作罢 提交于 2019-11-28 05:03:54

1.实现队列(enqueue 入队, dequeue 出队, head 返回头, tail 返回尾 size, clear, isEmpty)

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

    enQueue(data) {
        this.items.push(data)
    }

    deQueue() {
        let deItem = this.items.shift()
        return deItem
    }

    head() {
        return this.items[0]
    }

    tail() {
        return this.items[this.items.length - 1]
    }

    size() {
        return this.items.length
    }

    clear() {
        this.items = []
    }

    isEmpty() {
        return this.items.length === 0
    }
}

2. 队列常见算法

(1).约瑟夫环

思路:每隔两个删一个,那就是个数%3余数为0的话出队列,否则出队然后入队,即对头变队尾,直到剩下最后一个

// 约瑟夫环 [100 个数每隔两个删一个, 删到末尾继续从头开始, 求最后一个被删除的数是多少?]
function delRing (ringArrs) {
    let queue = new Queue()
    ringArrs.forEach(item => {
        queue.enQueue(item)
    })

    let index = 0
    while (queue.size() > 1) {
        // 出队
        let deItem = queue.deQueue()
        index = index + 1
        // 如果不是隔两个则入队
        if (index % 3 !== 0) {
            queue.enQueue(deItem)
        }
    }

    return queue.head()
}

let ringArrs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let lastOne = delRing(ringArrs)

console.log(lastOne)

(2).斐波那契数列:1、1、2、3、5、8、13、21、34、……

函数实现:

思路:递归,前两个数为1, 其他F(n) = F(n-1) + F(n-2)

function Fibonacci (n , ac1 = 1 , ac2 = 1) {
    if( n <= 1 ) {return ac2};
    return Fibonacci (n - 1, ac2, ac1 + ac2);
}

队列实现:

思路:前两个数为1, 其他:首先将前两个数1,1入队,然后循环(索引小于n - 2, 因为默认比2大),队列始终有两个数,队头加队尾再入队操作,最后循环完,返回队尾就可

function Fibonacci(n) {
    if (n === 1 || n === 2) return 1

    let index = 0
    let queue = new Queue()
    queue.enQueue(1)
    queue.enQueue(1)

    while (index < n - 2) {
        let headItem = queue.deQueue()
        let nextItem = queue.head()
        let result = headItem + nextItem
        queue.enQueue(result)

        index = index + 1
    }

    return queue.tail()
}

(3). 两个队列实现一个栈:

思路:两个指针,dataQueue始终指向有数据的队列,emptyQueue指向空队列。此时top栈顶就是数据队列的队尾;

push就是数据队列的入队;pop数据队列出队到空队列,直到数据队列的长度是1,此时数据队列队尾出队即可

// 两个队列实现一个栈
class QueueToStack {
    constructor() {
        this.firstQueue = new Queue()
        this.secondQueue = new Queue()
        this.emptyQueue = null
        this.dataQuee = null
    }

    /**
     * 初始化队列,初始化数据队列和空队列的指向
     */
    initQueue () {
        // 使得数据队列始终指向有数据的队列
        if (this.firstQueue.isEmpty()) {
            this.dataQuee = this.secondQueue
            this.emptyQueue = this.firstQueue
        } else {
            this.dataQuee = this.firstQueue
            this.emptyQueue = this.secondQueue
        }
    }

    pop () {
        this.initQueue()
        // 弹出栈顶, 在这里其实就是数据栈dataQuee队尾出队
        while (this.dataQuee.size() > 1) {
            // 数据队列出队到空队列中
            this.emptyQueue.enQueue(this.dataQuee.deQueue())
        }
        
        // 数据栈dataQuee队尾出队
        return this.dataQuee.deQueue()
    }

    push (data) {
        this.initQueue()
        this.dataQuee.enQueue(data)
    }

    top () {
        this.initQueue()
        return this.dataQuee.tail()
    }
}

let queueToStack = new QueueToStack()

queueToStack.push(1)
queueToStack.push(2)
queueToStack.push(3)
queueToStack.push(4)

queueToStack.pop()
queueToStack.pop()
console.log(queueToStack.top())

(4).思考两个栈如何实现一个队列?

思路:根据两个队列实现一个栈

// 两个栈实现一个队列
class StackToQueue {
    constructor() {
       this.firstStack = new Stack()
       this.secondStack = new Stack()
       this.dataStack = null
       this.emptyStack = null
    }

    /**
     * 初始化栈指向
     */
    initStack () {
        if (this.firstStack.isEmpty()) {
            this.dataStack = this.secondStack
            this.emptyStack = this.firstStack
        } else {
            this.dataStack = this.firstStack
            this.emptyStack = this.secondStack
        }
    }

    enQueue (data) {
        this.initStack()
        // 入队,此处就是向数据栈进栈操作
        this.dataStack.push(data)
    }

    deQueue() {
        this.initStack()
        // 出队,就是数据栈底
        // 1. 数据栈出栈, 空栈入栈
        while (this.dataStack.size() > 1) {
            //栈从 1, 2, 3  -> 到 3 ,2, 1 转换后,数据栈的栈顶其实就是队列的队头
            this.emptyStack.push(this.dataStack.pop())
        }

        // 2. 循环完毕后, 数据栈只剩栈底,其实就是对头,出栈即可, 1出栈
        let popItem = this.dataStack.pop()

        // 3. 恢复数据栈,目的是 栈从 3, 2  -> 恢复到 2, 3
        while (this.emptyStack.size()) {
            this.dataStack.push(this.emptyStack.pop())
        }

        return popItem
    }

    head() {
        this.initStack()
        // 对头其实就是数据栈底
        // 1. 数据栈出栈, 空栈入栈
        while (this.dataStack.size()) {
            //栈从 1, 2, 3  -> 到 3 ,2, 1 转换后,数据栈的栈顶其实就是队列的队头
            this.emptyStack.push(this.dataStack.pop())
        }
        // 2.此时空栈有数据 3 ,2, 1, 返回栈顶1即可
        let topItem = this.emptyStack.top()

        // 3. 恢复数据栈,目的是 栈从 3, 2, 1  -> 恢复到 1, 2, 3
        while (this.emptyStack.size()) {
            this.dataStack.push(this.emptyStack.pop())
        }

        return topItem
    }

    tail() {
        this.initStack()
        // 队尾即数据栈顶,直接返回即可
        return this.dataStack.top()
    }
}

let queueToStack = new StackToQueue()

queueToStack.enQueue(1)
queueToStack.enQueue(2)
queueToStack.enQueue(3)
queueToStack.enQueue(4)
queueToStack.deQueue()
queueToStack.deQueue()

console.log(queueToStack.head())
console.log(queueToStack.tail())

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!