1. 栈(堆栈)
- 栈结构是什么,栈结构是一种受限制的线性结构
- 栈的特征,先进后出、后进先出(LIFO – last in first out)
- 栈只能在一端进行添加和删除,这一端被称为栈顶,另一端称为栈底。向栈顶添加数据称为进栈、入栈或压栈,删除数据又称为出栈或退栈
1.1 栈的封装
// 栈类
class Stack {
constructor() {
this.arr = []
}
// 1.push(Ele):添加一个新元素到栈顶位置
push(Ele) {
this.arr.push(Ele)
}
// 2.pop():移除栈顶的元素,同时返回被移除的元素
pop() {
return this.arr.pop()
}
// 3.peek():返回栈顶的元素,不对栈做任何修改
peek() {
return this.arr[this.arr.length - 1]
}
// 4.isEmpty():查看栈里有没有东西,没有就true,有就false
isEmpty() {
return this.arr.length == 0
}
// 5.size():返回栈里的元素个数
size() {
return this.arr.length
}
// 6.toString():将栈结构的内容以字符形式返回
toString() {
let resultStr = ""
for (let i = 0; i < this.arr.length; i++) {
resultStr += this.arr[i] + " "
}
return resultStr
}
}
1.2 十进制转二进制
// 10 / 2 0
// 5 / 2 1
// 2 / 2 0
// 1 / 2 1
// 10 ---> 1010
// 封装十进制转二进制的方法
function DecChangeBin(decNum) {
// 引用封装的栈类
let stack = new Stack()
// 当数不为零时一直循环
while (decNum > 0) {
// 余数为零或一时添加
stack.push(decNum % 2)
// 向下取整,因为余数为一时已经获取到了那个一
decNum = Math.floor(decNum / 2)
}
let resultStr = ''
// 表示栈里还有东西
while (!stack.isEmpty()) {
// 按顺序弹栈
resultStr += stack.pop()
}
return resultStr
}
let dec = 2048
let decChangeBin = DecChangeBin(dec)
console.log(`原十进制的数:${dec},现二进制的数:${decChangeBin}`);
1.3 智能重复
把数组中的字母重复对应前面数字的次数
// 把 2[1[a]3[b]2[3[c]4[b]]] 变成 abbbcccddddcccddddabbbcccddddcccdddd 这种形式
// 1. 当遇到数字连接[时 数字添加到栈1,栈2添加空字符串
// 2. 当遇到字母链接]时 把栈2最后一个空字符串变为这个字母
// 这里有必要说一下为什么要连接后面的括号,数字后面还有可能会是数字,字母同理
// 3. 当遇到]时(即使遇到相邻的也不会影响),栈1和栈2最后一位出栈
// 然后把栈2出栈的字母乘栈1数字的倍数,在拼接到栈2最后一个字母
// replace:两个参数(匹配到的字符,被替换成谁)
// match:能够找到所有匹配到的字符
// test:查询开头字符是否存在(可多个)
// substring:第一个参数截取第一个的多少位,返回剩余的
let str = '2[1[aaa]3[b]2[3[c]4[b]]]'
// 存放数字栈
let stackNum = []
// 存放字母栈
let stackStr = []
// 指针
let i = 0
// 存放剩余字符串
let rest = str
function smartRepeat(str) {
while (i < str.length - 1) {
rest = str.substring(i)
// 当遇到数字连接[时 数字添加到栈1,栈2添加空字符串
if (/^\d+\[/.test(rest)) {
// match(/^(\d+)\[/)捕获 括号中的数放到数组中下标为1
let num = Number(rest.match(/^(\d+)\[/)[1])
stackNum.push(num)
stackStr.push('')
// 数字可能有多位 加一是[ 因为数字后面必为[
i += num.toString().length + 1
// 当遇到字母链接]时 把栈2最后一个空字符串变为这个字母
} else if (/^\w+\]/.test(rest)) {
let str = rest.match(/^(\w+)\]/)[1]
stackStr[stackStr.length - 1] = str
i += str.length
// 当遇到]时(即使遇到相邻的也不会影响),栈1和栈2最后一位出栈
// 然后把栈2出栈的字母乘栈1数字的倍数,在拼接到栈2最后一个字母
} else if (/\]/.test(rest)) {
let outNum = stackNum.pop()
let outStr = stackStr.pop()
// 'a'.repeat(3) 返回'aaa'
stackStr[stackStr.length - 1] += outStr.repeat(outNum)
i++
}
}
// 因为在whil循环的时候专门少循环了一次
// 在数字栈中的第一项一定是最开始字符串第一项的数字
// 而字母栈也是都乘好的就差第一个数字没有乘了
return stackStr[0].repeat(stackNum[0])
}
smartRepeat(str)