JavaScripts数据结构 队列


前言


一、队列数据结构

与栈的先进后出原则相反, 队列遵循的是先进先出(FIFO), 在队尾入队, 在队首出队, 新增者必须被添加至队尾.

1.创建队列

如果基于对象来实现队列, 那么获取元素操作的时间复杂度会更低.
item对象作为队列本体, count属性描述队列的大小, lowestCount辅助描述第一个元素.

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

直接操作这个队列总是不安全的, 还需要一些方法来规范队列的操作标准.

2.设置操作方法

  1. 增加元素, 按照队列的原则, 必须加到队尾, 由enqueqe实现.
class Queue {
  consructor () {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
  enqueqe (element) { // 由队尾添加元素
    this.items[this.count] = element;
    this.count++;
  }
}

由于itemsObject类型, 增加元素需要使用count作为键, 每次新增元素完毕count加1, 预备下一次元素增加.

  1. 移除元素, 参考栈模型出栈, 必须从队首移除, 越早加入队列的元素将越早遭到移除.
    不能使用数组pop方法的情况下依靠lowestCount枚举属性并delete来移除.
class Queue {
  consructor () {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
  dequeqe() { // 由队首移除元素
    if (this.isEmpty()) { // 判定队列当前是否为空, 防止报错;
      return undefined;
    }
    const result = this.items[this.lowestCount]; // 获取队首元素
    delete this.items[this.lowestCount]; // 删除队首元素
    this.lowestCount++;
    return result;
  }
}
  1. 检查队首元素
    返回位于队首的元素.
class Queue {
  consructor () {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
  peek() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.items[this.lowestCount];
  }
}
  1. 检查队列是否为空
class Queue {
  consructor () {
    this.count = 0;
    this.losestCount = 0;
    this.items = {};
  }
  isEmpty() {
    return this.count = this.lowestCount === 0;
  }
}
  1. 获取队列长度
class Queue {
  consructor () {
    this.count = 0;
    this.losestCount = 0;
    this.items = {};
  }
  size () {
    return this.count - this.lowestCount;
  }
}
  1. 清空队列
    构造函数数据全部重置为初始值.
class Queue {
  consructor () {
    this.count = 0;
    this.losestCount = 0;
    this.items = {};
  }
  clear () {
    this.items = {};
    this.count = 0;
    this.lowestCount = 0;
  }
}

使用就不说了, 看得明白方法就能用.


二、双端队列

双端队列是一种特殊的队列, 它允许队尾队首的添加和撤销操作, 而非普通队列的队尾进队首出.
双端队列同时遵守先进后出和后进先出原则, 可以说是栈和队列的结合数据结构.

1.创建双端队列

老样子, 双端队列和普通队列看起来没什么不同, 只是操作原则上更自由.

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

2.设置双端队列方法

情况会比普通队列复杂一些:

  1. 由队首增加元素
    排队, 但是直接插到队首.
class Deque {
  constructor () {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
  addFront (element) {
    if (this.isEmpty()) { // 空队列, 不考虑队首尾, 直接添加
      this.addBack(element)
    } else if (this.lowestCount > 0) { // 见解释2
      this.lowestCount--;
      thid.items[this.lowestCount] = element;
    } else { // 见解释3
      for (let i = this.count; i > 0; i--) {
        this.items[i] = this.items[i - 1];
      }
      this.count++;
      this.lowestCount = 0;
      this.items[0] = element;
    }
  }
}

解释2:
lowestCount作为最小键已不为0, 说明调用addFront前队首移除过元素, lowestCount作为目前最小key应当减1后作为新的最小key加到队首

items = {
  3: 'hello',
  4: 'baiX'
}

此时lowestCount为3, 说明012已遭到移除, 那么增加新的元素于队首, 新key应当为2, 故lowestCount需要减1.

解释3:
队首从0开始的队列, 在队首增加元素, 可以直接使lowestCount继续减1, 队首key进入负数范围, 但本处希望key依旧从0开始, 那么需要将所有队列元素向队尾移动1位, 为新元素腾出位置.

  1. 由队末增加元素
    排队, 规规矩矩排到队尾.
class Deque {
  constructor () {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
  addBack(element) {
    this.count++;
    this.items[this.count] = element;
  }
}
  1. 由队首移除
    排队打饭, 打到了, 走人了.
class Deque {
  constructor () {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
  removeFront() {
    if (this.isEmpty()) { // 判空防止报错
      return undefined;
    }
    const result = this.items[this.lowestCount];
    delete this.items[this.lowestCount]; // 删除队首元素
    this.lowestCount++; // 更新最小key为曾经倒数第二元素的key.
    return result;
  }
}
  1. 由队尾移除
    排了半年, 等烦了, 跑了.
class Deque {
  constructor () {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
  removeBack() {
    if (this.isEmpty()) {
      return undefined;
    }
    this.count--;
    const result = this.items[this.count];
    delete this.items[this.count];
    return result;
  }
}
  1. 获取大小&判空
class Deque {
  constructor () {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
  isEmpty() {
    return this.size() === 0;
  }
  size() {
    return this.count - this.lowestCount;
  }
}

三、基于双端队列实现回文检查器

回文: 正反都能读通的单词, 词组, 数, 或一系列字符的序列, 例如madam.
function palindromeChecker(aString) {
  if (aString === undefined ||
    aString === null ||
   (aString !== null && 
    aString.length === 0)) {
      return false;
  }
  const deque = new Deque(); // 实例化双端队列, 上面声明过的.
  const lowerString = astring.toLocaleLowerCase().split('').join(''); // 全小写字符串
  let isEqual = true;
  let firstChar, lastChar;
  for (let i = 0; i < lowerString.length; i++) {
    deque.addBack(lowerString.charAt(i)); // 拆解字符串逐个加入队列
  }
  while (deque.size() > 1 && isEqual) { 
  // 首尾同时取, 对称性检查, 一旦不对称isEqual改为flase跳出循环.
  // 该循环会在达到队列中央元素/不再存在元素时停止
    firstChar = deaue.removeFront();
    lastChar = deaue.removeBack();
    if (firstChar !== lastChar) {
      isEqual = false;
    }
  }
  return isEqual;
}


总结

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值