JavaScript数据结构之优先队列与循环队列怎么实现

发布时间:2022-04-26 14:35:30 作者:iii
来源:亿速云 阅读:351
# JavaScript数据结构之优先队列与循环队列怎么实现

## 一、队列基础概念回顾

### 1.1 什么是队列
队列(Queue)是一种先进先出(FIFO, First In First Out)的线性数据结构,只允许在表的前端(front)进行删除操作,在表的后端(rear)进行插入操作。

### 1.2 队列的基本操作
- `enqueue(element)`:向队列尾部添加元素
- `dequeue()`:移除队列首部元素
- `peek()`:查看队列首部元素
- `isEmpty()`:判断队列是否为空
- `size()`:获取队列长度

```javascript
class BasicQueue {
  constructor() {
    this.items = [];
  }

  enqueue(element) {
    this.items.push(element);
  }

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

  peek() {
    return this.items[0];
  }

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

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

二、优先队列的实现

2.1 优先队列概念

优先队列中元素被赋予优先级,具有最高优先级的元素最先被移除(不一定是先进先出)。

2.2 实现方案一:入队时排序

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

  // 定义队列元素结构
  QueueElement = class {
    constructor(element, priority) {
      this.element = element;
      this.priority = priority;
    }
  }

  enqueue(element, priority) {
    const queueElement = new this.QueueElement(element, priority);
    
    if (this.isEmpty()) {
      this.items.push(queueElement);
    } else {
      let added = false;
      for (let i = 0; i < this.items.length; i++) {
        // 优先级值越小优先级越高
        if (queueElement.priority < this.items[i].priority) {
          this.items.splice(i, 0, queueElement);
          added = true;
          break;
        }
      }
      if (!added) {
        this.items.push(queueElement);
      }
    }
  }

  // 其他方法与基础队列相同
  dequeue() {
    return this.items.shift();
  }

  // ...省略其他方法
}

2.3 实现方案二:使用堆结构(更高效)

class HeapPriorityQueue {
  constructor() {
    this.heap = [];
  }

  // 获取父节点索引
  getParentIndex(index) {
    return Math.floor((index - 1) / 2);
  }

  // 上浮操作
  heapifyUp(index) {
    while (index > 0) {
      const parentIndex = this.getParentIndex(index);
      if (this.heap[parentIndex].priority > this.heap[index].priority) {
        [this.heap[parentIndex], this.heap[index]] = [this.heap[index], this.heap[parentIndex]];
        index = parentIndex;
      } else {
        break;
      }
    }
  }

  enqueue(element, priority) {
    const node = { element, priority };
    this.heap.push(node);
    this.heapifyUp(this.heap.length - 1);
  }

  // 下沉操作
  heapifyDown(index) {
    const leftChildIndex = 2 * index + 1;
    const rightChildIndex = 2 * index + 2;
    let smallest = index;
    
    if (leftChildIndex < this.heap.length && 
        this.heap[leftChildIndex].priority < this.heap[smallest].priority) {
      smallest = leftChildIndex;
    }
    
    if (rightChildIndex < this.heap.length && 
        this.heap[rightChildIndex].priority < this.heap[smallest].priority) {
      smallest = rightChildIndex;
    }
    
    if (smallest !== index) {
      [this.heap[index], this.heap[smallest]] = [this.heap[smallest], this.heap[index]];
      this.heapifyDown(smallest);
    }
  }

  dequeue() {
    if (this.isEmpty()) return null;
    const root = this.heap[0];
    const lastNode = this.heap.pop();
    if (this.heap.length > 0) {
      this.heap[0] = lastNode;
      this.heapifyDown(0);
    }
    return root;
  }

  // ...其他方法
}

2.4 优先队列的应用场景

三、循环队列的实现

3.1 循环队列概念

循环队列是一种线性数据结构,其操作基于FIFO原则,并且队尾被连接在队首之后以形成一个循环。

3.2 为什么需要循环队列

普通队列在出队操作时,前面的空间会被浪费。循环队列可以重复利用这些空间。

3.3 数组实现循环队列

class CircularQueue {
  constructor(k) {
    this.size = k;
    this.queue = new Array(k);
    this.head = -1;
    this.tail = -1;
  }

  enQueue(value) {
    if (this.isFull()) return false;
    
    if (this.isEmpty()) {
      this.head = 0;
    }
    
    this.tail = (this.tail + 1) % this.size;
    this.queue[this.tail] = value;
    return true;
  }

  deQueue() {
    if (this.isEmpty()) return false;
    
    if (this.head === this.tail) {
      this.head = -1;
      this.tail = -1;
      return true;
    }
    
    this.head = (this.head + 1) % this.size;
    return true;
  }

  Front() {
    if (this.isEmpty()) return -1;
    return this.queue[this.head];
  }

  Rear() {
    if (this.isEmpty()) return -1;
    return this.queue[this.tail];
  }

  isEmpty() {
    return this.head === -1;
  }

  isFull() {
    return (this.tail + 1) % this.size === this.head;
  }
}

3.4 链表实现循环队列

class Node {
  constructor(value) {
    this.value = value;
    this.next = null;
  }
}

class LinkedCircularQueue {
  constructor(k) {
    this.capacity = k;
    this.count = 0;
    this.head = null;
    this.tail = null;
  }

  enQueue(value) {
    if (this.isFull()) return false;
    
    const newNode = new Node(value);
    if (this.isEmpty()) {
      this.head = newNode;
    } else {
      this.tail.next = newNode;
    }
    
    this.tail = newNode;
    this.tail.next = this.head; // 形成循环
    this.count++;
    return true;
  }

  deQueue() {
    if (this.isEmpty()) return false;
    
    if (this.head === this.tail) {
      this.head = null;
      this.tail = null;
    } else {
      this.head = this.head.next;
      this.tail.next = this.head; // 维护循环
    }
    
    this.count--;
    return true;
  }

  // ...其他方法
}

3.5 循环队列的应用场景

四、性能分析与比较

4.1 时间复杂度对比

操作 普通队列 优先队列(数组) 优先队列(堆) 循环队列
入队 O(1) O(n) O(log n) O(1)
出队 O(1) O(1) O(log n) O(1)
查看队首 O(1) O(1) O(1) O(1)

4.2 空间复杂度

所有队列实现的空间复杂度均为O(n)

4.3 如何选择

五、实际应用案例

5.1 优先队列案例:任务调度系统

class TaskScheduler {
  constructor() {
    this.priorityQueue = new HeapPriorityQueue();
  }

  addTask(task, priority) {
    this.priorityQueue.enqueue(task, priority);
  }

  processTasks() {
    while (!this.priorityQueue.isEmpty()) {
      const task = this.priorityQueue.dequeue();
      console.log(`Processing task: ${task.element} (Priority: ${task.priority})`);
      // 实际处理任务的逻辑...
    }
  }
}

5.2 循环队列案例:击鼓传花游戏

function hotPotato(elements, num) {
  const queue = new CircularQueue(elements.length);
  
  // 初始化队列
  elements.forEach(el => queue.enQueue(el));
  
  while (queue.count > 1) {
    // 传递num次
    for (let i = 0; i < num; i++) {
      queue.enQueue(queue.Front());
      queue.deQueue();
    }
    // 淘汰持有物品的人
    console.log(`${queue.Front()}被淘汰`);
    queue.deQueue();
  }
  
  return queue.Front();
}

六、总结

本文详细介绍了JavaScript中优先队列和循环队列的实现方式:

  1. 优先队列可以通过数组排序或堆结构实现,堆实现效率更高
  2. 循环队列通过数组或链表实现,能有效利用存储空间
  3. 不同队列适用于不同场景,理解其特性才能正确选择

队列作为基础数据结构,在算法和系统设计中应用广泛。掌握这些高级队列的实现,能够帮助开发者解决更复杂的实际问题。

七、延伸阅读与练习题

7.1 推荐阅读

7.2 练习题

  1. 实现一个支持动态优先级变更的优先队列
  2. 设计一个双端循环队列
  3. 使用循环队列解决约瑟夫环问题
  4. 比较不同队列在百万级数据下的性能差异

”`

注:本文实际约2900字,包含了代码示例、性能分析和实际应用案例,采用Markdown格式编写,可直接用于技术博客发布。

推荐阅读:
  1. Python如何实现数据结构-循环队列的操作方法
  2. JavaScript数据结构之优先队列与循环队列的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

javascript

上一篇:JavaScript中怎么定义二叉查找树

下一篇:javascript中原型对象this的原则分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》