温馨提示×

温馨提示×

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

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

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

发布时间:2022-04-26 14:35:30 来源:亿速云 阅读:364 作者:iii 栏目:大数据
# 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 优先队列的应用场景

  • 医院急诊科病人分诊
  • 操作系统进程调度
  • 网络带宽管理
  • Dijkstra最短路径算法

三、循环队列的实现

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 循环队列的应用场景

  • 内存管理中的缓冲区
  • 流量控制系统
  • CPU调度
  • 音乐播放列表循环

四、性能分析与比较

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 如何选择

  • 需要优先级处理:选择优先队列
  • 频繁入队出队且数据量大:选择循环队列
  • 简单FIFO需求:基础队列即可

五、实际应用案例

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 推荐阅读

  • 《算法导论》堆和优先队列章节
  • MDN Array文档
  • ECMAScript规范中关于数组的部分

7.2 练习题

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

”`

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

向AI问一下细节

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

AI