JS数据结构与算法 — 队列

前言

阅读本文前,建议阅读 数据结构与算法---JS与栈

队列数据结构

队列是遵循先进先出(FIFO)原则的一组有序的项。

队列在最尾添加元素,在顶部移除元素。

在日常生活中,排队买票、在计算机中,打印队列都是队列的例子。

创建队列

我们用对象来做队列类的数据存储类型。

class Queue {
    #_headKey=0;
    #_endKey=0;
    #_items={}
}

定义一些队列的方法

向队列添加元素

enqueue(ele) {
    this.#_items[this.#_endKey] = ele;
    this.#_endKey +=1;
}

返回队列长度

由上面的图可知

size() {
    return this.#_endKey - this.#_headKey
}

检验队列是否为空

isEmpty() {
    return this.size() === 0
}

从队列里移除元素并返回它

其实就是移除队列里第一个

unenqueue() {
    // 为空的话返回undefined
    if (this.isEmpty()) {
        return undefined    
    }
    const result  = this.#_items[this.#_headKey];
    delete this.#_items[this.#_headKey];
    // 起始指针向后移
    this.#_headKey +=1;
    return result
}

清空队列

clear() {
    while (!this.isEmpty()) {
        this.unenqueue()
    }
}

创建toString方法

toString() {
    if (this.isEmpty()) {return ''};
    let objString = '';
    for (let i = this.#_headKey;i<this.#_endKey;i++) {
        objString+=`[键名:${i}键值:${this.#_items[i]}]`
    }
    return objString
}

双端队列

双端队列是一种同时遵守了先进先出和后进先出原则,队列和栈相结合的数据结构。

定义

我们储存两个私参 双端队列第一个(最下面)元素的下标和队列的末尾空索引(也就是上文的endKey)

class Deque {
    // 队列头部下标
    #frontKey =0;
    #endKey=0;
    #items={};
}

取出双端队列的头部元素

peekFront(){
    if (this.isEmpty()) {
      return undefined;
    }
    return this.#items[this.#frontKey];
}

取出双端队列的尾部元素

  peekBack() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.#items[this.#endKey - 1];
  }

双端队列的长度

  size() {
    return this.#endKey- this.#frontKey;
  }

双端队列是否为空

isEmpty() {
    return this.size() === 0;
  }

尾部加入元素

 addEnd(element) {
    this.#items[this.#endKey] = element;
    this.#endKey++;
 }

头部出列

 remove_Front(){
     // 为空的话返回undefined
    if (this.isEmpty()) {
        return undefined    
    }
    const result  = this.#items[this.#frontKey];
    delete this.#items[this.#frontKey];
    this.#frontKey +=1;
    return result
}

尾部出列

remove_end(){
    if (this.isEmpty()) {
        return undefined
    }
    this.#endKey -=1;
    const result  = this.#items[this.#endKey];
    delete this.#items[this.#endKey];
    return result
}

清除队列

 clear() {
    this.#items = {};
    this.#frontKey = 0;
    this.#endKey = 0;
  }

头部加入元素

分几种情况:

①空的队列,调用addEnd方法

②#frontKey>=1(即发生过前出栈)的情况,此时要往frontKey前放置新入列的元素

③#frontKey为0,且队列长度不为空的情况,这个时候我们要往索引0前插入元素,就会产生负数的索引。这时需要所有下标往右移动。我们可以从最后一位开始迭代所有的值,每一个位置为其重新赋值(赋值为原本索引-1的值)、等所有的元素完成移动后,0位(第一位)将被空闲出来,此时我们再进行插入。

addFront(element) {
    if (this.isEmpty()) {
      this.addEnd(element);
    } else if (this.#frontKey > 0) {
      this.#frontKey--;
      this.#items[this.#frontKey] = element;
    } else {
      for (let i = this.#endKey; i > 0; i--) {
        this.#items[i] = this.#items[i - 1];
      }
      this.#endKey++;
      this.#items[0] = element;
    }
  }

toString

toString() {
    if (this.isEmpty()) {return ''};
    let objString = '';
    for (let i = this.#frontKey;i<this.#endKey;i++) {
        objString+=`[键名:${i}键值:${this.#items[i]}]`
    }
    return objString
}

实例化双端队列

class Deque {
    // 队列头部下标
    #frontKey =0;
    #endKey=0;
    #items={};
    peekFront(){
        if (this.isEmpty()) {
          return undefined;
        }
        return this.#items[this.#frontKey];
    }
    peekBack() {
        if (this.isEmpty()) {
          return undefined;
        }
        return this.#items[this.#endKey - 1];
    }
    size() {
        return this.#endKey- this.#frontKey;
    }
    isEmpty() {
        return this.size() === 0;
    }
    addEnd(element) {
        this.#items[this.#endKey] = element;
        this.#endKey++;
    }
     remove_Front(){
         // 为空的话返回undefined
        if (this.isEmpty()) {
            return undefined    
        }
        const result  = this.#items[this.#frontKey];
        delete this.#items[this.#frontKey];
        this.#frontKey +=1;
        return result
    }
    remove_end(){
        if (this.isEmpty()) {
            return undefined
        }
        this.#endKey -=1;
        const result  = this.#items[this.#endKey];
        delete this.#items[this.#endKey];
        return result
    }
    clear() {
        this.#items = {};
        this.#frontKey = 0;
        this.#endKey = 0;
    }
    addFront(element) {
        if (this.isEmpty()) {
          this.addEnd(element);
        } else if (this.#frontKey > 0) {
          this.#frontKey--;
          this.#items[this.#frontKey] = element;
        } else {
          for (let i = this.#endKey; i > 0; i--) {
            this.#items[i] = this.#items[i - 1];
          }
          this.#endKey++;
          this.#items[0] = element;
        }
      }
    toString() {
        if (this.isEmpty()) {return ''};
        let objString = '';
        for (let i = this.#frontKey;i<this.#endKey;i++) {
            objString+=`[键名:${i}键值:${this.#items[i]}]`
        }
        return objString
    }
}
var deque = new Deque()

用队列模拟击鼓传花游戏场景

我们要关注的是两个地方:

①学生数组

②拍手N次

因为击鼓传花会一直来回循环。我们用队列来模拟场景

class Queue {
    #_headKey=0;
    #_endKey=0;
    #_items={}
    enqueue(ele) {
        this.#_items[this.#_endKey] = ele;
        this.#_endKey +=1;
    }
    size() {
        return this.#_endKey - this.#_headKey
    }
    isEmpty() {
        return this.size() === 0
    }
    nenqueue() {
        // 为空的话返回undefined
        if (this.isEmpty()) {
            return undefined    
        }
        const result  = this.#_items[this.#_headKey];
        delete this.#_items[this.#_headKey];
        // 起始指针向后移
        this.#_headKey +=1;
        return result
    }
    peek() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.#_items[this.#_endKey - 1];
  }
}
const students = ['学生A','学生B','学生C','学生D'];
// 击鼓三下停止击鼓
const stopTimes = 3;
const game =(students,stopTimes)=>{
    const queueS = new Queue();
    // 创建学生队列
    for (var i = 0; i < students.length;i++){
        queueS.enqueue(students[i]);
    }
    // 淘汰到最后一个人即不进行击鼓
    while (queueS.size()>1) {
        // 开始击鼓
        for (var ii =0;ii<stopTimes;ii++){
            if (ii === stopTimes-1) {
                // 击鼓结束
                console.log('击鼓结束');
                const result = queueS.nenqueue();
                console.log('本轮被淘汰的是'+result);
            }else {
                 const result = queueS.nenqueue();
                // 击鼓继续
                console.log('花当前在' + result + '手里');
                queueS.enqueue(result);
            }
        }
    }
    return queueS.peek()
}

运行:

game(students,stopTimes )
VM2349:22花当前在学生A手里
VM2349:22 花当前在学生B手里
VM2349:16 击鼓结束
VM2349:18 本轮被淘汰的是学生C
VM2349:22 花当前在学生D手里
VM2349:22 花当前在学生A手里
VM2349:16 击鼓结束
VM2349:18 本轮被淘汰的是学生B
VM2349:22 花当前在学生D手里
VM2349:22 花当前在学生A手里
VM2349:16 击鼓结束
VM2349:18 本轮被淘汰的是学生D
=>'学生A'

用双端队列解决回文问题

什么是回文

回文指正读和反读都相同的字符序列。比如“abba”,“12321”等。

现在我们要写一个判断字符串是否为回文的方法

图解判断逻辑

代码

class Deque {
    // 队列头部下标
    #frontKey =0;
    #endKey=0;
    #items={};
    size() {
        return this.#endKey- this.#frontKey;
    }
    remove_Front(){
         // 为空的话返回undefined
        if (this.isEmpty()) {
            return undefined    
        }
        const result  = this.#items[this.#frontKey];
        delete this.#items[this.#frontKey];
        this.#frontKey +=1;
        return result
    }
    remove_end(){
        if (this.isEmpty()) {
            return undefined
        }
        this.#endKey -=1;
        const result  = this.#items[this.#endKey];
        delete this.#items[this.#endKey];
        return result
    }
    isEmpty() {
        return this.size() === 0;
    }
    addEnd(element) {
        this.#items[this.#endKey] = element;
        this.#endKey++;
    }
 
}
function isPalindrome(str) {
    if (!str) {return false}
    if (str.length === 1) {return true}
    const deque = new Deque();
    str = str.toLowerCase();
    const strArr = str.split('');
    for(var i = 0; i<strArr.length;i++){
        deque.addEnd(strArr[i])
    }
    var result = true;
    while(deque.size() > 1) {
        const comapreA = deque.remove_Front();
        const comapreB = deque.remove_end();
        console.log('开始比较')
        if (comapreA !== comapreB) {
            result = false;
            console.log('比较结束')
            break;
        }
    }
    return result;
}

猜你喜欢

转载自blog.csdn.net/weixin_42274805/article/details/129446170