JavaScript 数据结构与算法——第 2 章 栈

2.1 栈数据结构

是一种**后进先出(LIFO)**原则的有序集合。

函数调用栈:A 调用 B,B 中又调用 C ,C 中又调用 D。

  • 会先将 A 压入栈,A 没有执行完,所以不会弹出栈

  • 在 A 执行过程中调用了 B ,会将 B 压入栈,这时候 B 在栈顶,A 在栈底

  • 如果这时候 B 可以执行完,那么 B 会弹出栈,但是 B 没有执行完,它调用了 C

  • 所以 C 会压入栈,并且在栈顶,而 C 调用了 D ,D 会压入栈顶

  • 当前栈顺序:栈底 A -> B -> C -> D 栈顶

  • D 执行完,弹出栈,之后 C B A 依次弹出栈

题目:有 6 个元素 6,5,4,3,2,1 按顺序进栈,问下列哪一个不是合法的出栈顺序?

A:5 4 3 6 1 2 (√)

B:4 5 3 2 1 6 (√)

C:3 4 6 5 2 1 (×)

D:2 3 4 1 5 6 (√)

解析:

题目所说的按顺序进栈指的不是一次性全部进栈,而是有进有出,进栈顺序为 6 -> 5 -> 4 -> 3 -> 2 -> 1。

  • A 答案:65 进栈,5 出栈,4 进栈出栈,3 进栈出栈,6 出栈,21 进栈,1 出栈,2 出栈(整体入栈顺序符合 654321)。
  • B 答案:654 进栈,4 出栈,5 出栈,3 进栈出栈,2 进栈出栈,1 进栈出栈,6 出栈(整体的入栈顺序符合 654321)。
  • C 答案:6543 进栈,3 出栈,4 出栈,之后应该 5 出栈而不是 6,所以错误。
  • D 答案:65432 进栈,2 出栈,3 出栈,4 出栈,1 进栈出栈,5 出栈,6 出栈。符合入栈顺序。

2.2 栈结构实现

2.2.1 栈常见的一些方法

  • push() 添加一个新元素到栈顶位置。
  • pop() 移除栈顶的元素,同时返回被移除的元素。
  • peek() 返回栈顶的元素,不对栈做任何修改(该方法不会移除栈顶的元素,仅仅返回它)。
  • isEmpty() 如果栈里没有任何元素就返回 true,否则返回 false
  • size() 返回栈里的元素个数。这个方法和数组的 length 属性类似。
  • toString() 将栈结构的内容以字符串的形式返回。
  • clear() 移除栈里的所有元素。

2.2.2 ES6 实现

class Stack {
  constructor() {
    this.items = [];
  }
  
  // 压栈操作
  push(element) {
    this.items.push(element);
  }
  
  // 出栈操作,从栈中取出元素,并返回取出的那个元素
  pop() {
    return this.items.pop();
  }

  // 查看栈顶元素
  peek() {
    return this.items[this.items.length - 1];
  }

  // 判断栈是否为空
  isEmpty() {
    return this.items.length === 0;
  }

  // 获取栈中元素个数
  size() {
    return this.items.length;
  }

  // 返回以字符串形式的栈内元素数据
  toString() {
    let result = "";
    for (let item of this.items) {
      result += item + " ";
    }
    return result;
  }
  
  // 清空栈元素
  clear() {
    this.items = [];
  }
}

2.2.3 使用

let stack = new Stack();

// push() 测试
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.items); //--> [1, 2, 3]

// pop() 测试
console.log(stack.pop()); //--> 3

// peek() 测试
console.log(stack.peek()); //--> 2

// isEmpty() 测试
console.log(stack.isEmpty()); //--> false

// size() 测试
console.log(stack.size()); //--> 2

// toString() 测试
console.log(stack.toString()); //--> 1 2

// clear() 测试
console.log(stack.clear()); // --> undefined

2.3 简单应用

利用栈结构的特点封装实现十进制转换为二进制的方法。

function dec2bin(dec) {
  // new 一个 Stack,保存余数
  let rem = new Stack();

  // 当不确定循环次数时,使用 while 循环
  while (dec > 0) {
    // 除二取余法
    rem.push(dec % 2); // 获取余数,放入栈中
    dec = Math.floor(dec / 2); // 除数除以二,向下取整
  }

  let binaryString = "";
  // 不断地从栈中取出元素(0 或 1),并拼接到一起。
  while (!rem.isEmpty()) {
    binaryString += rem.pop();
  }

  return binaryString;
}

// dec2bin() 测试
console.log(dec2bin(100)); //--> 1100100
console.log(dec2bin(88)); //--> 1011000

还可以实现任意进制转换。

function baseConverter(dec, base) {
  let rem = new Stack();
  const digits = '0123456789ABCDEF'
  let baseString = '';
  
  while(dec > 0) {
    rem.push(dec % base);
    dec = Math.floor(dec / base);
  }
  
  while(!rem.isEmpty()) {
    // 将十进制转为16进制时,保证结果正确
    baseString += digits[rem.pop()];
  }
  
  return baseString;
}

console.log(baseConverter(100345, 2)); //--> 11000011111111001
console.log(baseConverter(100345, 8)); //--> 303771
console.log(baseConverter(100345, 16)); // --> 187F9
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值