class Queue {
constructor() {
this.count = 0; // 控制队列大小
this.lowestCount = 0; // 追踪第一个元素
this.items = {
}; // 使用对象来存储元素
}
// 方法
}
声明方法:
新的项只能添加到队列末尾。
enqueue(element){
this.items[this.count] = element;
this.count++;
}
最先移除的项是最先添加的。
dequeue() {
if(this.isEmpty()) {
return undefined;
}
// 暂存队列头部的值
const result = this.items[this.lowestCount];
delete this.items[this.lowestCount];
this.lowestCount++;
return result;
}
返回队列最前面的项。
peek() {
if(this.isEmpty) {
return undefined;
}
return this.items[this.lowestCount];
}
如果队列为空,返回true,否则返回false。
isEmpty() {
return this.count - this.lowestCount === 0;
}
计算队列中有多少元素,只需要返回count和lowestCount的差值。
size() {
return this.count - this.lowestCount;
}
如果差值为0,则队列为空,isEmpty可以用size方法实现:
isEmpty() {
return this.size() === 0;
}
可以简单地将队列中地属性值重设为和构造函数中的一样。
clear() {
this.items = {
};
this.count = 0;
this.lowestCount = 0;
}
toString() {
if(this.isEmpty()) {
return ''
}
let objString = `${
this.items[this.lowestCount]}`;
// Queue类中第一个索引值不一定是0,需要从lowestCount的位置开始迭代队列
for(let i = this.lowestCount + 1; i < this.count; i++) {
objString = `${
objString}, ${
this.items[i]}`;
}
return objString;
}
const queue = new Queue();
console.log(queue.isEmpty()); // true
// 添加元素
queue.enqueue('aaa');
queue.enqueue('bbb');
console.log(queue.toString()); // aaa,bbb
queue.enqueue('ccc');
console.log(queue.toString()); // aaa,bbb,ccc
console.log(queue.size()); // 3
console.log(queue.isEmpty()); // false
queue.dequeue(); // 移除aaa
console.log(queue.toString()); // bbb,ccc
双端队列(deque)允许同时从前端和后端添加和移除元素。同时遵循了先进先出和后进先出的原则,是把栈和队列组合的一种数据结构。
常见应用:撤销操作。用户在软件中进行一个操作,该操作会被存在一个双端队列中,点击撤销时,将从后面被移除。
class Deque {
constructor() {
this.count = 0;
this.lowestCount = 0;
this.items = {
};
}
}
双端队列是一种特殊的队列,其构造函数中的部分代码和队列相同,包括相同的内部属性和以下方法:isEmpty、clear、size、toString。
双端队列允许在两端添加和移除元素,所有还有以下方法:
addFront(element) {
// 双端队列为空的情况下可以直接在队列后端添加
if(this.isEmpty()) {
this.addBack(element);
} else if(this.lowestCount) {
// 一个元素已经被从双端队列的前端移除,即lowestCount属性会大于等于1
this.lowestCount--;
this.items[this.lowestCount] = element;
} else {
// lowestCount为0时,可以设置负键
for(let i = this.count; i > 0; i--) {
this.items[i] = this.items[i - 1];
}
this.count++;
this.lowestCount = 0;
this.items[0] = element;
}
}
<script>
class Queue {
constructor() {
this.count = 0; // 控制队列大小
this.lowestCount = 0; // 追踪第一个元素
this.items = {
}; // 使用对象来存储元素
}
// 方法
enqueue(element) {
this.items[this.count] = element;
this.count++;
};
dequeue() {
if (this.isEmpty()) {
return undefined;
}
const result = this.items[this.lowestCount];
delete this.items[this.lowestCount];
this.lowestCount++;
return result;
};
peek() {
if (this.isEmpty()) {
return undefined;
}
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() {
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;
};
addFront(element) {
if (this.isEmpty()) {
this.enqueue(element);
} else if (this.lowestCount) {
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;
}
}
}
const queue = new Queue();
console.log(queue.isEmpty()); // true
// 添加元素
queue.enqueue('aaa');
queue.enqueue('bbb');
console.log(queue.toString()); // aaa,bbb
queue.enqueue('ccc');
console.log(queue.toString()); // aaa,bbb,ccc
console.log(queue.size()); // 3
console.log(queue.isEmpty()); // false
queue.dequeue(); // 移除aaa
console.log(queue.toString()); // bbb,ccc
queue.addFront('aaa'); // 头插法
console.log(queue.toString()); // aaa,bbb,ccc
</script>
<script>
class Queue {
constructor() {
this.count = 0; // 控制队列大小
this.lowestCount = 0; // 追踪第一个元素
this.items = {
}; // 使用对象来存储元素
}
// 方法
enqueue(element) {
this.items[this.count] = element;
this.count++;
};
dequeue() {
if (this.isEmpty()) {
return undefined;
}
const result = this.items[this.lowestCount];
delete this.items[this.lowestCount];
this.lowestCount++;
return result;
};
peek() {
if (this.isEmpty()) {
return undefined;
}
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() {
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;
};
}
function hotPotato(elementsList, num) {
const queue = new Queue();
// 把名单都加入队列
const eliminatedList = [];
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());
}
// 达到给定的传递次数,拿花者淘汰
eliminatedList.push(queue.dequeue());
}
return {
eliminated: eliminatedList,
// 剩下的胜者
winner: queue.dequeue()
}
}
const names = [1, 2, 3, 4, 5];
const result = hotPotato(names, 7);
result.eliminated.forEach(name => {
console.log(`${
name}在击鼓传花中被淘汰。`);
});
console.log(`胜利者:${
result.winner}`);
</script>
使用双端队列。
<script>
class Deque {
constructor() {
this.items = {
};
this.count = 0;
this.lowestCount = 0;
};
addFront(element) {
if (this.isEmpty()) {
this.addBack(element);
} else if (this.lowestCount > 0) {
this.lowestCount--;
this.items[this.lowestCount] = element;
} else {
for (let i = this.count; i > 0; i--) {
this.items[i] = this.this.items[i - 1];
}
this.count++;
this.lowestCount = 0;
this.items[0] = element;
}
};
addBack(element) {
this.items[this.count] = element;
this.count++;
};
removeFront() {
if (this.isEmpty()) {
return undefined;
}
const result = this.items[this.lowestCount];
delete this.items[this.lowestCount];
this.lowestCount++;
return result;
};
removeBack() {
if (this.isEmpty()) {
return undefined;
}
this.count--;
const result = this.items[this.count];
delete this.items[this.count];
return result;
};
peekFront() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.lowestCount];
};
peekBack() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.count - 1];
};
isEmpty() {
return this.count - this.lowestCount === 0;
};
clear() {
this.items = {
};
this.count = 0;
this.lowestCount = 0;
};
size() {
return this.count - this.lowestCount;
};
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;
};
}
function palindromeChecker(aString) {
// 检查传入的字符串是否合法
if (aString === undefined || aString === null || (aString !== null && aString.length === 0)) {
return false;
}
const deque = new Deque();
// 把所有字母转为小写,并移除所有空格
const lowestString = aString.toLocaleLowerCase().split(' ').join('');
let isEqual = true;
let firstChar, lastChar;
// 对字符串中所有字符进行操作
for (let i = 0; i < lowestString.length; i++) {
deque.addBack(lowestString.charAt(i));
}
// 如果只有一个字符,肯定为回文
while (deque.size() > 1 && isEqual) {
// 从前端移除一个元素
firstChar = deque.removeFront();
// 从后端移除一个元素
lastChar = deque.removeBack();
// 移除的元素不相同返回错误
if (firstChar !== lastChar) {
isEqual = false;
}
}
return isEqual;
}
console.log('a', palindromeChecker('a')); // true
console.log('abc', palindromeChecker('abc')); // false
console.log('madam', palindromeChecker('madam')); // true
</script>