队列数据结构
队列(queue)数据结构是一种受限的数据结构,符合是先进先出的原则。后端(末端)是负责增加,前端(前面)负责删除。就如同我们去食堂买饭,后来的同学需要在对列最后排队等候,前面买上饭的同学就可以离开买饭的对列中了。
队列的优先级
优先级队列就好比们生活中的一些事情,比如去做飞机,往往头等舱的乘客会比经济舱的乘客优先上飞机一样~。
队列的优先级封装
// 优先级队列封装function PriorityQueue() {// 在类内部在创建一个类,成为内部类function QueueElement(element, priority) {this.element = element; // 元素this.priority = priority // 优先级}this.items = [];// 插入方法PriorityQueue.prototype.enqueue = function (element, priority) {// 创建一个内部类的实例let queueElement = new QueueElement(element, priority)// 更具条件排列队列的顺序if (this.items.length === 0) {// 如果队列是空直接放进去this.items.push(queueElement)} else {let added = falsefor (let i = 0; i < this.items.length; i++) {// 如果不为空,判断优先级,顺序插入数据if (queueElement.priority < this.items[i].priority) {// 更近优先级的位置插入this.items.splice(i, 0, queueElement)added = true;break}}// 如果这个值优先级最小,放到最后面if (!added) {this.items.push(queueElement)}}}}let priorityQueue = new PriorityQueue();priorityQueue.enqueue('a', 1)priorityQueue.enqueue('a', 151)priorityQueue.enqueue('a', 11)priorityQueue.enqueue('a', 10)console.log(priorityQueue.items);
封装队列的方法
function Queue() {this.items = [];// push 增加队列Queue.prototype.enqueue = function (el) {console.log(el);return this.items.push(el)}// delQueue 删除队列Queue.prototype.delQueue = function () {return this.items.shift()}// front 查看队列的第一个元素Queue.prototype.front = function () {return this.items[0]}// isEmpty 查看队列是否有值 返回BooleanQueue.prototype.isEmpty = function () {return this.items.length === 0;}// size 返回队列长度Queue.prototype.size = function () {return this.items.length;}//}let q = new Queue();q.enqueue('abc')q.enqueue('bcd')q.enqueue('cde')console.log(q) // 需要注释掉下面内容才能看到,否则为之后一项q.delQueue()console.log(q)q.delQueue()console.log(q)console.log(q.front());console.log(q.isEmpty());console.log(q.size())
双端队列数据结构
双端队列数据结构是一种允许我们同时从前端和后端添加和移除元素的特殊队列。 由于双端队列同时遵守了先进先出和后进先出的原则,可以说他是把队列和栈结合的一种数据结构。举个例子:好比我们去电影院,一个刚买了票的人如果只是还需要在问一些问题,就可以直接回到队伍的头部。在队伍末尾的人如果赶时间,也可以直接离开队伍。
双端队列同时遵循 先进先出,后仅先出 的原则,可以说她是吧队列和栈相结合的一种数据结构。
class Deque {constructor() {this.count = 0;this.locwestCount = 0; // 记录队列前端第一位;this.items = {};}// 队列前端添加一个元素addFront(element) {// 队列为空if (this.isEmtry()) {this.addBack(element)} else if (this.locwestCount > 0) {// 一个元素已经被双端队列的前端移除;this.locwestCount -= 1;this.items[this.locwestCount] = element;} else {for (let i = this.count; i > 0; i--) {this.items[i] = this.items[i - 1];}this.count += 1;this.locwestCount = 0;this.items[0] = element;}}// 队列后端添加一个元素addBack(element) {this.items[this.count] = element;this.count += 1;}// 移除队列前端第一个元素removeFront() {if (this.isEmtry()) return undefined;const result = this.items[this.locwestCount];delete this.items[this.locwestCount]this.locwestCount += 1;return result;}// 移除队列后端一个元素removeBack() {if (this.isEmtry()) return undefined;this.count -= 1;const result = this.items[this.count];delete this.items[this.count]return result;}// 获取队列前端第一项peekFront() {if (this.isEmtry()) return undefined;return this.items[this.locwestCount]}// 获取队列后端第一项peekBack() {if (this.isEmtry()) return undefined;return this.items[this.items.length - 1]}isEmtry() {return this.count - this.locwestCount === 0;}size() {return this.count - this.locwestCount;}clear() {this.count = 0;this.locwestCount = 0;this.items = {};}toString() {if (this.isEmtry()) return '';let objString = `${this.items[this.locwestCount]}`; // 先把第一项放进去for (let i = this.locwestCount + 1; i < this.count; i++) {objString = `${objString},${this.items[i]}`; // 每一项依次放进去}return objString;}}const deque = new Deque();console.log(deque.isEmtry(), '真为空'); // true "真为空"deque.addBack('a')deque.addBack('b');console.log(deque.items); // {0: "a", 1: "b"}deque.addBack('c')console.log(deque.size(), '长度'); // 3 "长度"console.log(deque.isEmtry(), '假为不空'); // false "假为不空"console.log(deque.removeFront(), '移除掉的值'); // a 移除掉的值console.log(deque.items); // {1: "b", 2: "c"}console.log(deque.removeBack(), '被删除的值'); // c 被删除的值console.log(deque.items);deque.addBack('d')console.log(deque.items); // {1: "b"}console.log(deque.toString()); // b,d
击鼓传花案例
游戏规则:十几人或几十人围成圆圈坐下,其中一人拿花,一人背着大家或蒙眼击鼓,击鼓n次,就传n次,到一轮之后,花在谁手中,谁就淘汰,最后只剩一人
//击鼓传花算法 基于上面的封装方法实现function pasGame(nameList, num) {//创建一个队列结构let queue = new Queue();// 将所有的人都加到队列中for (let i = 0; i < nameList.length; i++) {queue.enqueue(nameList[i])}// 开始每次数数,直到剩下一个人while (queue.size() > 1) {// 点睛之笔,可以得出循环的这个值 是不是numfor (let i = 0; i < num - 1; i++) {// 这里其实是 栈的感觉,先执行完里面在执行外面。// 如果不等于num 删掉他重新放到最后面。queue.enqueue(queue.delQueue())}// 得到和num相等的值,直接删除queue.delQueue()}// 获取剩下的那个人alert('还剩' + queue.size() + '个人') // 剩下人数长度let name = queue.front() //得到剩下的那个人alert('身下的人为' + name);alert('剩下人的原来下标为' + nameList.indexOf(name))}pasGame(['a', 'b', 'c', 'd'], 3)
双端队列判断回文数
function palindromeChecker(palindrome) {if (palindrome === undefined || palindrome === null || (palindrome !== null && palindrome.length === 0)) {return false;}const deque = new Deque();// 只能校样字符串。不过这是一种思路const lowerString = palindrome.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){// 统一移除前端 后端各一项firstChar = deque.removeFront();lastChar = deque.removeBack();// 如果移除的两项相不等说明不是回文数if(firstChar !== lastChar){isEqual = false}}return isEqual;}console.log(palindromeChecker('aa1qwedaa'));
