队列(Queue)

李艳生

湖北师范大学

物理与电子科学学院

2020年春季

目录

队列

双端队列

回文问题

队列


图1 排队

队列概念

  • 一组遵守先进先出(FIFO)的有序集合
  • 一个队列包含队头,队尾
  • 添加在队尾,删除在队头
  • 新元素在队尾,旧元素在队头
  • 生活实例:排队
  • 计算机实例:文档打印队列

队列操作

  • 建队列
  • 入队
  • 出队
  • 查看队头
  • 检查队空
  • 清空队列

算法演示


队列实现

  • 基于数组的队列
  • 基于对象的队列

数组队列

  • 创建一个类封装队列
  • 利用数组操作实现队列操作

class Queue{
    constructor(){
        this.items = [];
    }
    enqueue(element){}
    dequeque(){}
    peek(){}
    isEmpty(){}
    clear(){}
}

入队

  • 入队只能在队列添加元素
  • 利用数组push操作实现入队

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

出队

  • 出队只能在队头删除元素
  • 利用数组shift操作实现出队

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

查看队头元素

  • 查看队头只获取队头元素,不删除
  • 利用数组第一个元素

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

检查队空

  • 队空返回true,不空返回false
  • 利用数组length属性


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

清空队列

  • 将队列中所有元素清空

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

队列使用

  • 利用new创建队列对象

//建队列
let queue = new Queue();
//判队空
console.log(queue.isEmpty());
//入队
queue.enqueue(1);
queue.enqueue(2);
//查看队头
console.log(queue.peek());
//出队
console.log(queue.dequeue());
//清空队列
queue.clear();
console.log(queue.isEmpty());

对象队列

  • 创建一个类封装队列
  • 利用对象操作实现队列操作

class Queue{
    constructor(){
        this.tailCount = 0;
        this.headCount = 0;
        this.items = {};
    }
    enqueue(element){}
    dequeue(){}
    peek(){}
    isEmpty(){}
    clear(){}
}

入队

  • 入队只能在队尾添加元素
  • 利用对象键值对操作实现入队,this.tailCount作为键,插入元素作为值
  • 递增tailCount变量

enqueue(element){
    this.items[this.tailCount] = element;
    this.tailCount++;
}

检查队空

  • 队空返回true,不空返回false
  • 利用变量headCount,tailCount

isEmpty(){
    return this.tailCount - this.headCount === 0;
}

出队

  • 出队只能在队头删除元素
  • 利用变量headCount操作实现出栈

dequeue(){
    const ret = this.items[this.headCount];
    delete this.items[this.headCount];
    this.headCount++;
    return ret;
}

查看队头元素

  • 查看队头只获取队头元素,不删除
  • 利用变量headCount

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

清空队列

  • 将队列中所有元素清空

clear(){
    this.tailCount = 0;
    this.headCount = 0;
    this.items = {};
}

队列使用

  • 利用new创建队列对象

//建队列
let queue = new Queue();
//判队空
console.log(queue.isEmpty());
//入队
queue.enqueue(1);
queue.enqueue(2);
//查看队头
console.log(queue.peek());
//出队
console.log(queue.dequeue());
//清空队列
queue.clear();
console.log(queue.isEmpty());

双端队列概念

  • 遵守先进先出(FIFO)和后进先出(LIFO)的有序集合
  • 将队列和栈相结合
  • 一个双端队列包含队头,队尾
  • 可在队尾,队头添加删除元素
  • 生活实例:排队
  • 计算机实例:撤销操作队列

双端队列操作

  • 建队列
  • 队尾添加
  • 队头添加
  • 队尾删除
  • 队头删除
  • 查看队尾
  • 查看队头
  • 检查队空
  • 清空队列

双端队列实现

  • 基于数组的双端队列
  • 基于对象的双端队列

数组双端队列

  • 创建一个类封装双端队列
  • 利用数组操作实现双端队列操作

class Deque{
    constructor(){
        this.items = [];
    }
    addHead(element){}
    addTail(element){}
    removeHead(){}
    removeTail(){}
    peekHead(){}
    peekTail(){}
    isEmpty(){}
    clear(){}
}

对象双端队列

  • 创建一个类封装双端队列
  • 利用对象操作实现双端队列操作

class Deque{
    constructor(){
        this.tailCount = 0;
        this.headCount = 0;
        this.items = {};
    }
    addHead(element){}
    addTail(element){}
    removeHead(){}
    removeTail(){}
    peekHead(){}
    peekTail(){}
    isEmpty(){}
    clear(){}
}

检查队空

  • 队空返回true,不空返回false
  • 利用变量headCount,tailCount

isEmpty(){
    return this.tailCount - this.headCount === 0;
}

队尾添加元素

  • 利用变量tailCount

addTail(element){
    this.items[this.tailCount] = element;
    this.tailCount++;
}

队尾删除元素

  • 利用变量tailCount

removeTail(){
    this.tailCount--;
    let ret = this.items[this.tailCount];
    delete this.items[this.tailCount];
    return ret;
}

队头添加元素

  • 利用变量headCount
  • 分三种情况:空队列,headCount>0,headCount=0

队头添加元素


addHead(element){
    if(this.isEmpty()){
        this.addTail(element);
    }
    else if(this.headCount > 0){
        this.headCount--;
        this.items[this.headCount] = element;
    }
    else {
        for(let i = this.tailCount; i > 0; i--){
            this.items[i] = this.items[i - 1];
        }
        this.tailCount++;
        this.headCount = 0;
        this.items[this.headCount] = element;
    }
}

队头删除元素

  • 利用变量headCount操作实现出队

removeHead(){
    const ret = this.items[this.headCount];
    delete this.items[this.headCount];
    this.headCount++;
    return ret;
}

查看队尾元素

  • 查看队尾只获取队尾元素,不删除
  • 利用变量tailCount

peekTail(){
    return this.items[this.tailCounti - 1];
}

查看队头元素

  • 查看队头只获取队头元素,不删除
  • 利用变量headCount

peekHead(){
    return this.items[this.headCount];
}

清空队列

  • 将队列中所有元素清空

clear(){
    this.tailCount = 0;
    this.headCount = 0;
    this.items = {};
}

双端队列使用

  • 利用new创建双端队列对象

//建队列
let queue = new Deque();
//判队空
console.log(queue.isEmpty());
//入队
queue.addTail(1);
queue.addTail(2);
queue.addTail(3);
queue.addHead(4);
//查队
console.log(queue.peekHead());
console.log(queue.peekTail());

//出队
console.log(queue.removeHead());
console.log(queue.removeTail());
//清空队列
queue.clear();
console.log(queue.isEmpty());

回文问题

  • 正反都能读通的单词、词组、数或一系列字符的序列
  • 单个字符即是回文
  • 例如:madam,racecar,a,b

循环检测回文

  • 分别从头尾两个方向i,j遍历
  • 若i<=j每个字符都相同,则为回文

function isPalindrome(str) {   
    for(let i = 0, j = str.length - 1; i <= j;i++,j--){
        if(str.charAt(i) !== str.charAt(j)) return false;
    }
    return true;
} 
alert(isPalindrome('madam'));
alert(isPalindrome1('a'));
alert(isPalindrome1('aa'));
alert(isPalindrome1('客上天然居;居然天上客'))
alert(isPalindrome1('ab'))

数组检测回文

  • 先字符串1转成数组
  • 利用数组reverse()方法反转
  • 再将数组转成字符串2
  • 若字符串1和2一样,则为回文

数组检测回文


function isPalindrome(str) {   
    let a = str.split('');
    let b = a.reverse().join('');
    if(str === b){
        return true;
    }
    return false;
} 
alert(isPalindrome('madam'));

栈检测回文

  • 先将每个字符进栈
  • 再依次出栈形成新字符串
  • 比较两个字符串,若相同则为回文

栈检测回文


function isPalindrome(str) {   
    let stack = new Stack();
    let temp = '';
    for(let i = 0; i < str.length; i++){
        stack.push(str.charAt(i));
    }
    while(!stack.isEmpty()){
           temp += `${stack.pop()}`;
    }
    if(str === temp) return true;
    return false;
} 
alert(isPalindrome('madam'));

队列检测回文

  • 先将每个字符入队
  • 再分别从队列两端出队
  • 比较出队字符,若相同则继续,直到队列长度大于1

队列检测回文


function isPalindrome(str) {   
    let deque = new Deque();
    let s,e;
    for(let i = 0; i < str.length; i++){
        deque.addTail(str.charAt(i));
    }
    while(deque.size() > 1){
        s = deque.removeHead();
        e = deque.removeTail();
        if(s !== e) return false;
    }
    return true;
} 
alert(isPalindrome('madam'));

任务

二选一

1.利用数组设计双端队列数据结构,并利用该种队列设计检测回文算法。

2.设计一个消息队列,用setInterval分别模拟发送与接收任务,发送任务每500ms发送一个消息到队列,接收任务每1000ms接收一个消息,模拟异步通信。

## 牛二定律 $$ F = ma $$ ## 质能方程 $$ E = mc^2 $$ ## 万有引力 $$ F = \frac{GMm}{r^2} $$
## 矩阵 $$ \left[ \begin{matrix} 1 & 2 & 3 \\\\ 4 & 5 & 6 \\\\ 7 & 8 & 9 \end{matrix} \right] $$ $$ \begin{vmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\\\ a_{21} & a_{22} & \cdots & a_{2n} \\\\ \vdots & \vdots & \ddots & \vdots \\\\ a_{m1} & a_{m2} & \cdots & a_{mn} \end{vmatrix} $$
## 分段函数 $$ f(n)= \begin{cases} n/2,& \text{if $n$ is even}\\\\ 3n+1,& \text{if $n$ is odd} \end{cases} $$
## 表格 $$ \begin{array}{c|lcr} n & \text{Left} & \text{Center} & \text{Right} \\\\ \hline 1 & 0.24 & 1 & 125 \\\\ 2 & -1 & 189 & -8 \\\\ 3 & -20 & 2000 & 1+10i \end{array} $$ | no | lang | | :-: | :- | | 1| C/C++ | | 2|Java/JavaScript |
## 方程组 $$ \begin{cases} a_1x+b_1y+c_1z=d_1 \\\\ a_2x+b_2y+c_2z=d_2 \\\\ a_3x+b_3y+c_3z=d_3 \\\\ \end{cases} $$