2.JavaScript数据结构与算法(队列)

1.队列数据结构

队列是遵循先进先出(FIFO,也称为先来先服务)原则的一组有序的项。队列在尾部添加元素,并从顶部移除元素。

1.创建队列

class Queue {
  constructor() {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
}

声明一个count属性来控制队列的大小,由于需要将从队列前端移除元素,同样需要一个变量来追踪第一个元素lowestCount

·enqueue(element(s)) 向队列尾部添加一个(或多个)新的项
·dequeue() 移除队列中第一项并返回被移除的元素
·peek() 返回队列的第一个元素
·isEmpty() 如果队列中不包含任何元素,返回true,否则返回false
·size() 返回队列包含的元素个数

(1).向队列添加元素

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

(2).从队列中移除元素
遵循先入先出的原则,先添加的项也是最先被移除的

  dequeue() {
    if(this.isEmpty()) {
      return undefined
    }
    const result = this.items[this.lowestCount];
    delete this.items[this.lowestCount];
    this.lowestCount ++;
    return result;
  }

首先需要检验队列是否为空,如果为空,则返回undefined值,如果队列不为空,则删除队列头部元素,并修改lowessCount来重新记录头部元素位置,并返回删除元素。
(3).查看队列头元素

  peek() {
    if(this.isEmpty()) {
      return undefined;
    }
    return this.items[this.lowestCount]
  }

(4).检查队列是否为空并获取它的长度

 isEmpty() {
    return this.count - this.lowestCount === 0
  }

要计算队列中的元素,计算count与lowestCount差值即可

  size() {
    return this.count - this.lowestCount
  }

(5).清空队列
清空队列可以调用dequeue方法直到返回undefined,或者直接将队列中的属性值重设为和构造函数中的一样

  clear() {
    this.count = 0;
    this.items = {};
    this.lowestCount = 0;
  }

(6).创建toString方法

  toString() {
    if(this.isEmpty()) {
      return ''
    }
    let str = `${this.items[this.lowestCount]}`
    for(let i = this.lowestCount + 1; i < this.count; i++) {
      str = `${str}${this.items[i]}`
    }
    return str
  }

2.双端队列数据结构

双端队列是一种允许同时从前端和后端添加和移除元素的特殊队列
在计算机科学中,双端队列一个常见的应用就是存储一系列的撤销操作。每当用户在软件中进行了一个操作,该操作会被存在一个双端队列中(就像在一个栈里)。当用户点击撤销按钮时,该操作会被从双端队列中弹出,标识它被从后面移除了。在进行了预先定义的一定数量的操作后,最先进行的操作会被从双端队列的前端移除。由于双端队列同时遵守了先进先出和后进先出原则,可以说它是把队列和栈结合的一种数据结构

1.创建Deque类

class Deque {
 constructor() {
   this.count = 0;
   this.lowestCount = 0;
   this.items = {};
 }
}

·addFront(elemet) 该方法在双端队列的前端添加新的元素
·addBack(element) 该方法在双端队列的后端添加新的元素
·removeFront() 该方法会从双端队列了的前端移除一个元素
·removeBack() 该方法会从双端队列后端移除一个元素
·peekFront() 该方法返回双端队列前端的第一个元素
·peekBack() 该方法返回双端队列后端的第一个元素

class Deque {
 constructor() {
   this.count = 0;
   this.lowestCount = 0;
   this.items = {};
 }
 addBack(element) {
   this.items[this.count] = element;
   this.count ++;
 }
 isEmpty() {
   return this.count - this.lowestCount === 0
 }
 size() {
   return this.count - this.lowestCount
 }
 peekFront() {
   if(this.isEmpty()) return undefined;
   return this.items[this.count - 1];
 }
 peekBack() {
   if(this.isEmpty()) return undefined;
   return this.items[this.lowestCount]
 }
 removeBack() {
   if(this.isEmpty()) return undefined;
   const res = this.items[this.count - 1];
   delete this.items[this.count - 1];
   this.count --
   return res;
 }
 removeFront() {
   if(this.isEmpty()) return undefined;
   const res = this.items[this.lowestCount];
   delete this.items[this.lowestCount];
   this.lowestCount ++;
   return res;
 }
 addFront(element) {
   if(this.isEmpty()) this.addBack(element);
   if(this.lowestCount > 0) {
     this.lowestCount --;
     this.items[this.lowestCount] = element;
   } else {
     for(let i = this.count;i>0;i--) {
       this.items[i] = this.items[i - 1]
     }
     this.count ++;
     this.lowestCount = 0;
     this.items[0] = element
   }
 }
 toString() {
   if(this.isEmpty()) return '';
   let res = `${this.items[this.lowestCount]}`;
   for(let i = this.lowestCount + 1; i< this.count; i++) {
     res = `${res}-${this.items[i]}`;
   }
   return res;
 }
}
const deque = new Deque();
deque.addBack('first');
deque.addBack('second');
deque.addBack('third');
console.log(deque.peekFront(), 'peekFront');
console.log(deque.peekBack(), 'peekBack')
console.log(deque.removeBack(), 'removeBack')
console.log(deque.removeFront(), 'removeFront')
console.log(deque.count, deque.lowestCount)
deque.addFront('beforeFirst');
deque.addFront('before');
console.log(deque.toString());

要将一个元素添加到双端队列的前端,存在三种场景。当这个双端队列为空时,执行addBack,元素被添加到双端队列的后端,当这个双端队列中已经有元素被从前端移除,即lowerCount大于0,此时只需要将lowerCount - 1并将元素放到这个位置即可,若lowerCount为零,此时需要将该双端队列所有元素后移一位,将该元素添加到双端队列的前端(也可设置负值的键,同时更新计算双端队列长度的逻辑即可)

2.使用队列和双端队列解决问题

1.循环队列—击鼓传花游戏

击鼓传花游戏规则:首先需要一份名称,把里面的名字全部加入队列,给定一个数字,然后迭代队列。从队列开头移除一项,再将其添加到队列末尾(如果把花传给旁边的人,解除自身被淘汰的威胁),一旦打到给定的传递次数,拿着花的人就会被淘汰,最终只剩一人的时候,此人就是胜利者

const Queue = require('./1.queue');
function hotPotato(elementsList, num) {
  const queue = new Queue();
  const eliminateList = [];
  for(let i = 0; i< elementsList.length; i++) {
    queue.enqueue(elementsList[i])
  }
  while(queue.size() > 1) {
    for(let i =0; i < num; i++) {
      queue.enqueue(queue.dequeue());
    }
    eliminateList.push(queue.dequeue())
  } 
  return {
    eliminateList,
    winner: queue.dequeue()
  }
}
const personList = ['张三','李四', '王五', '赵六','徐七','韩八'];
const res = hotPotato(personList, 11);
res.eliminateList.forEach(item => console.log(item+'被淘汰'))
console.log(res.winner+'是最终胜利者')

2.回文检查器

const Deque = require('./2.deque');
// 回文检查器
function palindromeChecker(str) {
  if(!str) return false;
  const deque = new Deque();
  // 将所有字符转换为小写,并去除空格
  const lowerString = str.toLocaleLowerCase().split(' ').join('');
  let isEqual = true;
  let firtsChar, lastChar;
  for(let i = 0; i < str.length; i++) {
    deque.addBack(lowerString.charAt(i));
  }
  while(deque.size() > 1 && isEqual) {
    firtsChar = deque.removeFront();
    lastChar = deque.removeBack();
    if(firtsChar !== lastChar) {
      isEqual = false
    }
  }
  return isEqual
}
console.log(palindromeChecker('abcddcba'));
console.log(palindromeChecker('123321cbad'));
console.log(palindromeChecker('123abccba321'));

3.JavaScript任务队列

`
用户在浏览器打开新标签时,就会创建一个任务队列。这是因为每个标签都是单线程处理所有的任务,称为事件循环。浏览器要负责多个任务,如渲染HTML、执行JavaScript代码、处理用户交互(用户输入、鼠标点击等)、执行和处理一部请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值