队列数据结构
队列是遵循先进先出原则的一组有序的项。队列在尾部添加新元素,并从顶部移除元素
class Queue{
constructor(){
this.count = 0;//控制队列大小
this.lowestCount = 0;//需要重队列前端删除,使用一个变量追踪第一个元素
this.items = {};//使用对象存储元素更高效
}
//向尾部添加一个元素
enqueue(element){
this.items[this.count] = element;//将count作为items对象中的键
this.count++;
}
//移除头部第一个元素
dequeue(){
if (this.isEmpty()){
return undefind;
}
const result = this.items[this.lowestCount];
delete this.items[lowestCount];
this.lowestCount++;
return result;
}
//返回队列第一个元素
peek(){
if (this.isEmpty()){
return undefind;
}
return this.items[this.lowestCount];
}
//判断队列是否为空
isEmpty(){
return this.count - this.lowestCount === 0;
}
//返回队列大小
size(){
return this.count - this.lowestCount;
}
//清空队列
clear(){
this.items = {};
this.count = 0;
this.lowestCount = 0;
}
//toString方法
toString(){
if (this.isEmpty()) {
return '';
}
let objString = `${this.items[this.lowestCount]}`;
for (let i = this.lowestCount + 1; i < this.count; i++) {
objString = `${objString},${this.items[i]}`;
}
return objString;
}
使用Queue类
const queue = new Queue();
console.log(queue.isEmpty());//输出true
queue.enqueue('John');
queue.enqueue('Jack');
console.log(queue.toString()); // John,Jack
console.log(queue.size()); // 输出 2
双端队列数据结构
允许同时从前端和后端添加和移除元素的特殊队列
应用:存储一系列的撤销操作
创建 Deque 类
相同的内部属性和以下方法:isEmpty、clear、size 和 toString。
class Deque{
constructor(){
this.count = 0;//控制队列大小
this.lowestCount = 0;//使用一个变量追踪第一个元素
this.items = {};//使用对象存储元素更高效
}
//尾部添加一个元素
addBack(element){
this.items[this.count] = element;//将count作为items对象中的键
this.count++;
}
//头部添加元素
addFront(element){
//情况一:这个双端队列是空的
if (this.isEmpty()){
this.addBack(element);
//情况二:一个元素已经被从双端队列的前端移除
}else if (this.lowestCount>0){
this.lowestCount--;
this.items[this.lowestCount] = element;
}else{ //情况三:lowestCount 为 0
for (let i = this.count; i>0; i--){
this.items[i]= this.item[i-1];
}//在所有的元素都完成移动后,第一位将是空闲状态,这样就可以用需要添加的新元素来覆盖它了
this.count++;
this.lowestCount = 0;
this.items[0] = element;
}
}
//移除尾部一个元素
removeBack{
if (this.isEmpty()){
return undefind;
}
this.count--;
const result = this.items[this.Count];
delete this.items[this.Count];
return result;
}
//移除头部第一个元素
removeFront(){
if (this.isEmpty()){
return undefind;
}
const result = this.items[this.lowestCount];
delete this.items[lowestCount];
this.lowestCount++;
return result;
}
//返回队列第一个元素
peekFront(){
if (this.isEmpty()){
return undefind;
}
return this.items[this.lowestCount];
}
//返回队列最后一个元素
peekBack(){
if (this.isEmpty()){
return undefind;
}
return this.items[this.Count-1];
}
//判断队列是否为空
isEmpty(){
return this.count - this.lowestCount === 0;
}
//返回队列大小
size(){
return this.count - this.lowestCount;
}
//清空队列
clear(){
this.items = {};
this.count = 0;
this.lowestCount = 0;
}
//toString方法
toString(){
if (this.isEmpty()) {
return '';
}
let objString = `${this.items[this.lowestCount]}`;
for (let i = this.lowestCount + 1; i < this.count; i++) {
objString = `${objString},${this.items[i]}`;
}
return objString;
}
使用 Deque 类
const deque = new Deque(); console.log(deque.isEmpty()); // 输出 true deque.addBack('John'); deque.addBack('Jack');
console.log(deque.toString()); // John, Jack deque.addBack('Camila');
console.log(deque.toString()); // John, Jack, Camila
console.log(deque.size()); // 输出 3
console.log(deque.isEmpty()); // 输出 false
deque.removeFront(); // 移除 John
console.log(deque.toString()); // Jack, Camila
deque.removeBack(); // Camila 决定离开
console.log(deque.toString()); // Jack
deque.addFront('John'); // John 回来询问一些信息
console.log(deque.toString()); // John, Jack
使用队列和双端队列来解决问题
循环队列——击鼓传花游戏(hot potato)
function hotPotato(elementsList, num) {
const queue = new Queue(); // {1}
const elimitatedList = [];
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()); // {3}
}
elimitatedList.push(queue.dequeue()); // {4}
}
return {
eliminated: elimitatedList, winner: queue.dequeue() // {5}
};
}
//从队列开头移 除一项,再将其添加到队列末尾(行{3}),模拟击鼓传花(如果你把花传给了旁边的人,你被 淘汰的威胁就立刻解除了)。一旦达到给定的传递次数,拿着花的那个人就被淘汰了(从队列中 移除——行{4})。最后只剩下一个人的时候,这个人就是胜者(行{5})。
双端队列——回文检查器
回文是正反都能读通的单词、词组、数或一系列字符的序列
function palindromeChecker(aString) {
if (aString === undefined || aString === null || (aString !== null && aString.length === 0)) { // {1}
return false;
}
const deque = new Deque(); // {2}
const lowerString = aString.toLocaleLowerCase().split(' ').join(''); // {3}
let isEqual = true;
let firstChar, lastChar;
for (let i = 0; i < lowerString.length; i++) { // {4}
deque.addBack(lowerString.charAt(i));
}
while (deque.size() > 1 && isEqual) { // {5}
firstChar = deque.removeFront(); // {6}
lastChar = deque.removeBack(); // {7}
if (firstChar !== lastChar) {
isEqual = false; // {8}
}
}
return isEqual;
}
思考:JavaScript 任务队列
当我们在浏览器中打开新标签时,就会创建一个任务队列。这是因为每个标签都是单线程处
理所有的任务,称为事件循环。浏览器要负责多个任务,如渲染HTML、执行 JavaScript代码、 处理用户交互(用户输入、鼠标点击等)、执行和处理异步请求。如果想更多地了解事件循环, 可以访问 https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/。
posted on
浙公网安备 33010602011771号