一、栈
栈的特点:
- 栈中的数据元素遵守”后进先出”(First In Last Out)的原则,简称FILO结构。
- 限定只能在栈顶进行插入和删除操作。
1.栈结构实现:
function Stack() {
var items = []; // 使用私有变量,避免被外部操作
// push 栈顶添加元素
this.push = function(ele) {
items.push(ele);
}
// pop 移除栈顶元素 需返回移除的元素 因为可能要用到
this.pop = function() {
return items.pop();
}
// peek 检查栈顶
this.peek = function() {
return items[items.length - 1];
}
// isEmpty 检查栈是否为空
this.isEmpty = function() {
return items.length == 0;
}
// clear 清除栈
this.clear = function() {
items = [];
}
// size 获取栈大小
this.size = function() {
return items.length;
}
// getItems 检查items
this.getItems = function() {
return items;
}
}
// 使用栈
var stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.getItems());
// stack.pop(); // 使用pop会使整个数组改变,上方的打印也会受影响
console.log(stack.peek());
console.log(stack.isEmpty());
console.log(stack.size());
stack.clear()
console.log(stack.getItems());
2.使用案例:十进制转二进制
思路:使用余数法 ,将所有余数依次放入栈中,栈顶为最后剩余的数,最后依次pop栈中的数据并整理成字符串。
实现:
方法一:使用while
// 十进制转二进制
var divBy2 = function(number) {
var stack = new Stack();
var remainder;
var str = '';
while(number > 0) {
remainder = number % 2;
stack.push(remainder);
number = Math.floor(number / 2);
}
while(!stack.isEmpty()) {
str += stack.pop();
}
return str;
}
console.log(divBy2(10));
方法二:使用递归
var divBy2 = function(number) {
var stack = new Stack();
// 获取
return loop(stack,number)
}
// 递归
function loop(stack,newNum) {
// 获取商
var quotient = Math.floor(newNum / 2);
// 获取余数
var remainder = newNum % 2;
// 将余数放入栈中
stack.push(remainder);
// 将商进行递归
if(quotient < 2) {
stack.push(quotient);
return stack.getItems();
} else {
loop(stack,quotient)
}
return stack.getItems();
}
console.log(divBy2(10));
3.内存中的栈和函数:
二、队列
队列的特点:
- 队列中的数据遵循先入先出,FIFO(First In First Out)
- 只能在队列头进行删除操作,在队列尾部进行插入操作
1.队列结构实现:
var Queue = function() {
var items = [];
// enqueue 入列
this.enqueue = function(ele) {
items.push(ele)
}
// dequeue 出列
this.dequeue = function() {
return items.shift();
}
// front 查看列头
this.front = function() {
return items[0]
}
// isEmpty 检查队列是否为空
this.isEmpty = function() {
return items.length == 0;
}
// size 检查队列大小
this.size = function() {
return items.length;
}
}
2.使用案例:传花游戏
思路:一群小伙伴坐一圈传递一朵花,自定义第n位被淘汰,如此循环至剩下一个人 。
实现:
// 传花游戏:一群小伙伴坐一圈传递一朵花,自定义第n位被淘汰,如此循环至剩下一个人 。
var chuanhua = function(names,num) {
var queue = new Queue();
// 将所有小伙伴放入队列中
for(var i = 0; i < names.length; i++) {
queue.enqueue(names[i]);
}
while(queue.size() > 1) {
// 队列中的前n-1个小伙伴插入到列尾
for(var i = 0; i < num - 1; i++) {
queue.enqueue(queue.dequeue());
}
// 第n个小伙伴出列
taotai = queue.dequeue()
}
// 返回最后一个小伙伴
return queue.dequeue()
}
var names = ['a','b','c','d','e','f'];
var num = 3;
console.log(chuanhua(names,num));
3.优先队列:设置优先级,数字大的排前
// 优先队列
var PriorityQueue = function() {
var items = [];
// 辅助类:因为优先队列需要制定优先级,所以队列中的项应该是对象{ele:ele,priority:priority}
function QueueItem(ele, priority) {
this.ele = ele;
this.priority = priority;
}
// enqueue 优先队列的入队方法
this.enqueue = function(ele,priority) {
var queueItem = new QueueItem(ele,priority);
var status = false;
for(var i = 0; i < items.length; i ++) {
if(queueItem.priority > items[i].priority) {
items.splice(i,0,queueItem);
status = true;
// 中断循环,避免ele被插入之后继续向后找位置插入
break;
}
}
if(status == false) {
items.push(queueItem);
}
return items;
}
this.getItem = function() {
return items;
}
}
var priorityQueue = new PriorityQueue();
priorityQueue.enqueue('小明',1)
priorityQueue.enqueue('小黄',8)
priorityQueue.enqueue('小红',6)
priorityQueue.enqueue('小黑',4)
console.log(priorityQueue.getItem());