准备学习《学习JavaScript数据结构与算法》,自己也开始做一写笔记来记录总结,本文也是仅针对实现方面的总结。
如果出现错误,请在评论中指出,我也好自己纠正自己的错误
author: thomaszhou
栈的实现
栈,其实就是一个数组,但是这是个非常特殊的数组,因为栈有个特性:先进后出,什么意思呢?看着下面的图来讲解。
原谅我是个灵魂画手
-
栈只有一个开口,这个开口,是进口,也是出口
- 我们从这个口添加数据,也从这个口取出数据
-
栈的原则:先进后出
- 我们依次添加1,2,3进入栈中,那我们取出的第一个值是3,第二个取出的值是2,第三个是1。那如果在取出2的时候,又添加一个数呢?大家可以模拟一下
-
定义栈类和声明的方法
function Stack() { //定义栈 的类
var items = [];
this.push = function(elem) {//添加元素
return items.push(elem);
};
this.pop = function() {//弹出元素
return items.pop();
};
this.print = function() { //输出
console.log(items.toString());
};
this.size = function() {//输出栈的长度
return items.length;
};
this.clear = function() {//将栈置为空
return items = [];
};
this.peek = function() {//显示顶层元素
return items[items.length-1]
};
this.isEmpty = function() { // 判断栈是否为空
return items.length === 0;
};
}
复制代码
栈的测试函数
(function demo1() {
let stack1 = new Stack(); //创建栈
stack1.push(1);
stack1.push(2);
stack1.push(3);
stack1.push(4);
stack1.print();
console.log(stack1.pop());//4
console.log(stack1.peek());// 3
console.log(stack1.isEmpty());// false
stack1.clear();
console.log(stack1.isEmpty());// true
})();
复制代码
- 栈的例子:十进制转换为任意进制
function divideBy2(elem, base) {
var str = '',
temp = 0,
arr = new Stack(),//创建栈
baseStr = '0123456789ABCDEF';
while (elem !== 0) {
arr.push(Math.floor(elem % base));//容易漏掉Math.floor()就会造成结果为undefine;
elem = Math.floor(elem / base);
//
//console.log(elem); 测试debug
}
while (!arr.isempty()) {
console.log(arr);
str += baseStr[arr.pop()]; // 字符串也是数组,所有要用baseStr[]。而不能用baseStr()
}
return str;
}
console.log(divideBy2(7, 2));
复制代码
队列的实现
(1) 普通队列
- 队列和栈的不同就在于:
- 1、栈是先进后出,那就是push和pop方法
- 2、队列是先进先出,那就是push和shift方法
- 我们看啊,从右边进去,依次添加1,2,3,4,取出的第一个值是啥?是1,第二个,第三个第四个就是2,3,4.也就是说,我们添加一定是从右边进去,取出一定是从左边出去,也就是上面说的先进先出,先进去的,就先出来
function Queue() {
let items = [];
this.enqueue = function(ele) {
items.push(ele);
};
this.dequeue = function() {
return items.shift();
};
this.front = function() {
return items[0];
};
// 下面方法 同 栈
this.isEmpty = function() {
return items.length === 0;
};
this.clear = function() {
items = [];
};
this.size = function() {
return items.length;
};
this.print = function() {
console.log(items.toString());
}
}
复制代码
普通队列的测试函数:
(function queueDemo() {
var queue = new Queue();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
queue.print(); //1,2,3
console.log(queue.dequeue()); //1
console.log(queue.isEmpty()); //false
console.log(queue.size()); //2
console.log(queue.front()); //2
queue.clear();
console.log(queue.size()); // 0
})();
复制代码
(2) 优先队列
优先队列的核心在于设置优先级,队列的每个数据不是单一值,而是一个值和一个优先级id
- 1、 采用构造函数,构造一个含有element和priority的实例
- 2、 每次添加实例到队列中,按照优先级的先后插入到队列中(splice方法)
// 优先队列
function PriorityQueue() {
let items = [];
function QueueElement(element, priority) {
this.element = element;
this.priority = priority;
}
this.enqueue = function(element, priority) {
let ele = new QueueElement(element, priority);
if (this.isEmpty() === true) { // 队列为空,直接push
items.push(ele);
}else {
// 队列不为空,element的优先级priority小的在前面
for (let i = 0; i < items.length; i++) {
if (ele.priority < items[i].priority) {
items.splice(i, 0, ele);
}else {
// element的优先级最低的情况-直接push到最后
items.push(ele);
}
break;
}
}
};
this.print = function() {
for (let i = 0; i < items.length; i++) {
console.log(`ele: ${items[i].element},prio: ${items[i].priority}`);
}
};
// 其他的方法和普通队列相同
this.dequeue = function() {
return items.shift();
};
this.front = function() {
return items[0];
};
this.isEmpty = function() {
return items.length === 0;
};
this.clear = function() {
items = [];
};
this.size = function() {
return items.length;
};
}
复制代码
优先队列测试函数:
(function priQueueDemo() {
var queue = new PriorityQueue();
queue.enqueue(1, 4);
queue.enqueue(2, 7);
queue.enqueue(3, 1);
queue.print();
// ele: 3,prio: 1
// ele: 1,prio: 4
// ele: 2,prio: 7
console.log(queue.dequeue());//QueueElement {element: 3, priority: 1}
console.log(queue.isEmpty());//false
console.log(queue.size());//2
console.log(queue.front());//QueueElement {element: 1, priority: 4}
queue.clear();
console.log(queue.size());// 0
})();
复制代码
(3)循环队列
循环队列和普通队列的区别:普通队列和循环队列都是后面进一个,前面进一个.不同点就在于,循环队列是要将弹出的元素再返回到尾部再添加进去 核心代码就是queue.enqueue(queue.dequeue())
循环队列的应用-击鼓传花 击鼓传花的游戏都玩过,就是一堆人围一个圈,然后传递花,轮一圈,谁拿到花就淘汰谁(我们的例子是通过设置num来表示一轮传递几个人,算是一个规律性的击鼓传花,如果想实现真正的击鼓传花,那么就设置num为random,然后设置一个范围,就可以了,num = Math.floor(num * Math.random())
)
- 所以也只是一个虚拟的游戏
function hotPotato (nameList, num) {
let queue = new Queue(),
len = nameList.length;
for (let i = 0; i < len; i++) {
queue.enqueue(nameList[i]);
}
while (queue.size() > 1) {// 队列最后剩下一个
for (let i = 0; i < num; i++) {
queue.enqueue(queue.dequeue());// 循环队列的核心
}
console.log(`${queue.dequeue()}被淘汰`);
}
console.log(`${queue.dequeue()}胜利`);//队列的最后一个值
}
let arr = ['thomas1', 'thomas2', 'thomas3', 'thomas4', 'thomas5'];
hotPotato(arr, 2);
//thomas3被淘汰
//thomas1被淘汰
//thomas5被淘汰
//thomas2被淘汰
//thomas4胜利
复制代码