数据结构与算法–栈(Stack)–JS
数据结构(存储和组织数据的方式)包含以下几种结构:
数组(Array)、栈(Stack)、队列(Queue)、链表(Lisked list)、
图(Graph)、散列表(Hash)、树(Tree)、堆(Heap)
栈
先进后出(FILO),进出的一端为栈顶、不动的一端为栈底
函数调用栈
多个函数相互调用,A调用B,B又调用C,C又调用D,会将A压入栈,A没有执行完不会弹出栈,在执行A的过程中调用了B,把B压入栈,依次这样,最终D执行完了把D弹出栈,再依次把CBA弹出栈,,递归也是这样的,所以如果递归没有结束的判断语句,会出现栈溢出的现象
实现栈结构通常有两种方式
基于数组实现、基于链表实现
栈结构的封装实现
ps:通常约定俗成的叫法,方法很函数的区别:
方法Method:和某一个对象实例有联系
函数function
//封装栈类
function Stack() {
//栈中的属性
this.items = [];
//栈的相关操作
//1.将元素压入到栈
//添加方法有两种方式,这里叫方法
//第一种
// this.push = function () {
// }
//第二种,最好用第二种,
//因为第一种相当于给对象实例添加了方法,每个对象都拥有这样一个方法,
//而第二种是给类添加了一个方法,方法是共享的,更节省内存并且效率更高
Stack.prototype.push = function (element) {
this.items.push(element);
}
//2.从栈中取出元素
Stack.prototype.pop = function () {
return this.items.pop();
}
//3.查看一下栈顶元素
Stack.prototype.peek = function () {
return this.items[this.items.length - 1];
}
//4.判断栈是否为空
Stack.prototype.isEmpty = function () {
return this.items.length == 0;
}
//5.获取栈中元素的个数
Stack.prototype.size = function () {
return this.items.length;
}
//6.toString方法
//假如想写成这样子,20 10 16 45 52
Stack.prototype.toString = function () {
let resultString = '';
for (let i = 0; i < this.items.length; i++) {
resultString += this.items[i] + ' ';
}
return resultString;
}
}
var s = new Stack();
s.push(10);
s.push(15);
栈的应用:
函数:将十进制转成二进制
function dec2bin(decNumber) {
//定义栈对象
var stack = new Stack();
//循环操作
while (decNumber > 0) {
//获取余数并放入栈中
stack.push(decNumber % 2);
//获取整除后的结果,作为下一次运行的数字
decNumber = Math.floor(decNumber / 2);
}
//从栈中取出0和1
var binaryStr = '';
while (!stack.isEmpty()) {
binaryStr += stack.pop();
}
return binaryStr;
}
alert(dec2bin(100));
中缀表达式转为后缀表达式(逆波兰表达式),波兰表达式是前缀表达式
从左到右进行遍历
1运算数,直接输出.
2左括号,直接压入栈(此时左括号为最低优先级)
3右括号,不断弹出栈顶运算符并输出直到遇到左括号(弹出但不输出)
4运算符,将该运算符与栈顶运算符进行比较。如果优先级高于栈顶运算符则压入堆栈;如果优先级低于等于栈顶运算符则将栈顶运算符弹出并输出,然后比较新的栈顶运算符。直到优先级大于栈顶运算符或者栈空,再将该运算符入栈.
5如果对象处理完毕,则按顺序弹出并输出栈中所有运算符.
将中缀转后缀思路:
假如表达式是一个字符串,创建一个符号栈和一个字符串队列,遍历各个字符信息,判断该字符是 运算符、括号、数值
1运算符:判断当前字符优先级是否小于等于栈顶字符优先级,此时栈顶元素中的左括号优先级最小,大于将当前字符存入到符号栈中,小于等于将符号栈栈顶内容弹出且存入到字符串队列中,再与栈顶字符进行比较,直到大于当前栈顶字符,将当前字符存入到符号栈中
2括号:左括号存入到符号栈中;右括号,依次将符号栈中的运算符弹出进入到字符串队列中直到在符号栈中弹出左括号并停止弹栈
3数值:直接输出
示例:
2*(9+6/3-5)+4 => 2963/+5-*4+
// 判断优先级
function f(str) {
let yxj; //优先级
switch (str) {
case '*': yxj = 5; break;
case '/': yxj = 5; break;
case '+': yxj = 4; break;
case '-': yxj = 4; break;
}
return yxj;
}
// 创建一个栈
stack = new Stack();
// 表示缓存数据区
list = new Array();
function getList(str) {
for (let i = 0; i < str.length; i++) {
// 只要是数字直接缓存区
if (str[i] >= '0' && str[i] <= '9') {
list.push(str[i]);
} else if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/') {
while (true) {
if (stack.isEmpty() || stack.peek() == '(') {
stack.push(str[i]);
break;
} else if (f(str[i]) > f(stack.peek())) { //当前运算符优先级大于s1栈顶运算符优先级
stack.push(str[i]);
break;
} else { //小于等于
let cc = stack.peek();
list.push(cc);
stack.pop();
}
}
} else {
if (str[i] == '(') {
stack.push(str[i]);
} else {
while (stack.peek() != '(') {
let ccc = stack.peek();
list.push(ccc);
stack.pop();
}
stack.pop();
}
}
}
// 将剩下的全部追加在后面
while (!stack.isEmpty()) {
let cccc = stack.peek();
list.push(cccc);
stack.pop();
}
}
getList('9+(3-1)*3+10/2');
console.log(list);
stack.print();