js(JavaScript)数据结构之队列(Queue)

发布时间:2024年01月10日

什么是数据结构?

下面是维基百科的解释:

数据结构是计算机存储、组织数据的方式。数据结构意味着接口或封装:一个数据结构可被视为两个函数之间的接口,或者是由数据类型联合组成的存储内容的访问方法封装。

我们每天的编码中都会用到数据结构,下面是常见的数据结构:

  • 数组(Array)
  • 栈(Stack)
  • 队列(Queue)
  • 链表(Linked List)
  • 散列表(Hash)
  • 字典
  • 树(Tree)
  • 图(Graph)
  • 堆(Heap)

队列(Queue)

队列是一种数据结构,它遵循先进先出(FIFO)的原则,即最先进入队列的元素最先被移除。在日常生活中,我们可以将队列比喻为排队等待服务的人群,如在银行排队或者日常购物排队。

队列的特点:

  1. 只能在队尾添加元素,在队首删除元素。
  2. 先进先出的原则。
  3. 适用于需要按照时间顺序处理的场景。

队列的常用方法:

  • enqueue(item): 向队列尾部添加一个或多个新的项。
  • dequeue(): 移除队列的第一个项,并返回被移除的元素。
  • head(): 返回队列第一个元素,队列不做任何变动。
  • tail(): 返回队列最后一个元素,队列不做任何变动。
  • isEmpty(): 队列内无元素返回 true,否则返回 false。
  • size(): 返回队列内元素个数。
  • clear(): 清空队列。

队列的实现:

下面是使用 JavaScript 实现的队列类:

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

  enqueue(item) {
    this._items.push(item);
  }

  dequeue() {
    return this._items.shift();
  }

  head() {
    return this._items[0];
  }

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

  isEmpty() {
    return !this._items.length;
  }

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

  clear() {
    this._items = [];
  }
}

队列的应用:

1. 约瑟夫环(Josephus Problem)

当涉及到JS队列的应用,Josephus问题是一个很好的例子。该问题描述了一群人(或者其他实体)站成一个圆圈,从某个人开始,每次数到第k个人,就将该人从圆圈中删除,然后从下一个人开始继续这个过程,直到只剩下一个人为止。

以下是一个JavaScript的解决方案:

function josephus(n, k) {
    let queue = [];
    for (let i = 1; i <= n; i++) {
        queue.push(i);
    }
    
    let result = [];
    while (queue.length > 0) {
        for (let j = 0; j < k - 1; j++) {
            queue.push(queue.shift());
        }
        result.push(queue.shift());
    }
    
    return result;
}

console.log(josephus(7, 3)); // 输出[3, 6, 2, 7, 5, 1, 4]

思路过程和详细备注:

  1. 首先创建一个队列,其中包含1到n的所有人(编号)。
  2. 创建一个结果数组来存储被删除的人的顺序。
  3. 使用while循环,直到队列为空为止。
  4. 在内部循环中,每次将队首元素移动到队尾,模拟数到第k个人的过程。
  5. 当数到第k个人时,将其从队列中移除,并添加到结果数组中。
  6. 最终返回结果数组,即为最后留下的人的顺序。

这段代码使用了队列的先进先出特性来模拟Josephus问题。

2. 菲波那切数列(Fibonacci Sequence)

以下是一个使用JavaScript实现菲波那切数列的代码:

function fibonacci(n) {
    let queue = [];
    queue.push(0);
    queue.push(1);

    for (let i = 2; i <= n; i++) {
        let first = queue.shift();
        let second = queue[0];
        queue.push(first + second);
    }

    return queue[1];
}

console.log(fibonacci(10)); // 输出55

思路过程和详细备注:

  1. 创建一个队列,并将0和1分别放入队列中,这是菲波那切数列的起始点。
  2. 使用循环从2开始直到n,每次取出队首的元素(第一个数字),然后取出当前队首的元素(第二个数字)。
  3. 将这两个数字相加得到新的数字,将其放入队列的末尾。
  4. 继续循环,重复上述步骤,直到计算到第n个菲波那切数。
  5. 返回队列中第二个元素,即为第n个菲波那切数。

这段代码利用队列的先进先出特性来按顺序计算菲波那切数列。

3. 用队列实现一个栈

以下是使用队列实现栈的JavaScript代码:

class QueueStack {
    constructor() {
        this.queue = [];
    }

    push(x) {
        const tempQueue = [x];
        while (this.queue.length) {
            tempQueue.push(this.queue.shift());
        }
        this.queue = tempQueue;
    }

    pop() {
        return this.queue.shift();
    }

    top() {
        return this.queue[0];
    }

    empty() {
        return this.queue.length === 0;
    }
}

const stack = new QueueStack();
stack.push(1);
stack.push(2);
console.log(stack.top()); // 输出2
console.log(stack.pop()); // 输出2
console.log(stack.empty()); // 输出false

思路过程和详细备注:

  1. 创建一个名为QueueStack的类,该类使用一个数组作为队列。
  2. push方法将元素添加到栈中。它创建一个临时队列,将新元素放在队列的最前面,然后将原队列中的元素逐个取出并放入临时队列,以此来模拟栈的“先进后出”行为。
  3. pop方法从队列中移除并返回位于队首的元素,模拟栈的弹出操作。
  4. top方法返回栈顶元素,即队列的第一个元素。
  5. empty方法检查栈是否为空,如果队列的长度为0,则为空。

这段代码展示了如何使用队列来模拟栈的行为,实现了栈的基本功能。

用两个队列实现一个栈。
以下是使用两个队列实现栈的JavaScript代码:

class QueueStack {
    constructor() {
        this.queue1 = [];
        this.queue2 = [];
    }

    push(x) {
        this.queue2.push(x);
        while (this.queue1.length > 0) {
            this.queue2.push(this.queue1.shift());
        }
        [this.queue1, this.queue2] = [this.queue2, this.queue1];
    }

    pop() {
        return this.queue1.shift();
    }

    top() {
        return this.queue1[0];
    }

    empty() {
        return this.queue1.length === 0;
    }
}

const stack = new QueueStack();
stack.push(1);
stack.push(2);
console.log(stack.top()); // 输出2
console.log(stack.pop()); // 输出2
console.log(stack.empty()); // 输出false

思路过程和详细备注:

  1. 创建一个名为QueueStack的类,该类使用两个数组作为队列。
  2. push方法将元素添加到栈中。它首先将新元素放入queue2队列,然后将queue1队列中的所有元素逐个取出并放入queue2队列,以此来模拟栈的“先进后出”行为。
  3. push方法中,交换queue1queue2的引用,以便下一次push操作可以在不同的队列上执行。
  4. pop方法从queue1队列中移除并返回位于队首的元素,模拟栈的弹出操作。
  5. top方法返回栈顶元素,即queue1队列的第一个元素。
  6. empty方法检查栈是否为空,如果queue1队列的长度为0,则为空。

这段代码展示了如何使用两个队列来模拟栈的行为,实现了栈的基本功能。

总结

当使用JavaScript中的队列时的注意事项:

  1. 先进先出(FIFO): 队列是一种先进先出的数据结构,这意味着最先进入队列的元素将会最先被移除。

  2. 数组和链表: 在JavaScript中,队列可以使用数组或者自定义的链表来实现。使用数组可能更为简单,但在频繁的插入和删除操作中,链表可能更高效。

  3. 队列方法: JavaScript的Array类提供了用于模拟队列行为的方法,如push(入队),shift(出队),unshift(在队首添加元素)等。

  4. 性能考虑: 在处理大量数据时,需要谨慎选择数据结构和相应的操作,以避免性能问题。

  5. 并发操作: 在多线程或异步编程中,队列经常用于控制任务执行的顺序,需要注意线程安全和同步问题。

  6. 应用场景: 队列常用于广度优先搜索、缓存、消息传递等场景,因此需要根据具体的应用需求来选择合适的队列实现方式。

  7. 内存管理: 使用队列时需要留意内存管理,避免出现内存泄漏或不必要的资源占用问题。

  8. 错误处理: 在队列操作时,需要考虑边界条件和异常情况,确保代码能够正确处理各种情况下的输入。

总的来说,队列在JavaScript中有着广泛的应用,但在使用时需要考虑算法复杂度、数据规模、并发操作等方面的因素,以确保代码的性能和可靠性。

持续学习总结记录中,回顾一下上面的内容:
队列(Queue):队列是一种数据结构,它遵循先进先出(FIFO)的原则,即最先进入队列的元素最先被移除。在日常生活中,我们可以将队列比喻为排队等待服务的人群,如在银行排队或者日常购物排队。
队列的特点:
只能在队尾添加元素,在队首删除元素。
先进先出的原则。
适用于需要按照时间顺序处理的场景。
队列的常用方法:
enqueue(item): 向队列尾部添加一个或多个新的项。
dequeue(): 移除队列的第一个项,并返回被移除的元素。
head(): 返回队列第一个元素,队列不做任何变动。
tail(): 返回队列最后一个元素,队列不做任何变动。
isEmpty(): 队列内无元素返回 true,否则返回 false。
size(): 返回队列内元素个数。
clear(): 清空队列。
队列的应用:约瑟夫环(Josephus Problem)、菲波那切数列(Fibonacci Sequence)、用队列实现一个栈。
当使用JavaScript中的队列时,队列的注意事项。

文章来源:https://blog.csdn.net/qq_37255976/article/details/134461932
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。