队列数据结构
队列(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 = false
for (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 查看队列是否有值 返回Boolean
Queue.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) {
// 点睛之笔,可以得出循环的这个值 是不是num
for (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'));