每周一练 之 数据结构与算法(Stack)

 更新时间:2019年04月16日 09:59:49   作者:pingan8787  
这篇文章主要介绍了数据结构与算法(Stack),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

最近公司内部在开始做前端技术的技术分享,每周一个主题的 每周一练,以基础知识为主,感觉挺棒的,跟着团队的大佬们学习和复习一些知识,新人也可以多学习一些知识,也把团队内部学习氛围营造起来。

我接下来会开始把每周一练的题目和知识整理一下,便于思考和巩固,就像今天这篇开始。

学习的道路,很漫长,要坚持,希望大家都能掌握自己喜欢的技术,和自己需要的技术。

本周练习内容:数据结构与算法 —— Stack

这些都是数据结构与算法,一部分方法是团队其他成员实现的,一部分我自己做的,有什么其他实现方法或错误,欢迎各位大佬指点,感谢。

一、栈有什么特点,生活中有什么例子?

  1. 栈( stack )又称堆栈,是一种后进先出的有序集合,其中一端为栈顶,另一端为栈底,添加元素(称为压栈/入栈或进栈)时,将新元素压入栈顶,删除元素(称为出栈或退栈)时,将栈底元素删除并返回被删除元素。
  2. 特点:先进后出,后进先出。
  3. 例子:一叠书、一叠盘子。

 

二、实现一个栈,并实现下面方法

  1. push(element):添加一个新元素到栈顶。
  2. pop():移除栈顶的元素,同时返回被移除的元素。
  3. peek():返回栈顶的元素,不对栈做任何修改 (这个方法不会移除栈顶的元素,仅仅返回它)。
  4. isEmpty():如果栈没有任何元素就返回 true,否则返回 false。
  5. clear():移除栈里面的所有元素。
  6. size():返回栈里的元素个数。这个方法与数组的 length 属性类似。

方法1: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
  }
  clear(){
    this.items = []
  }
  size(){
    return this.items.length
  }
}

上面实现的方式虽然简单,但是内部 items 属性是公共的,为了满足面向对象变成私有性的原则,我们应该让 items 作为私有属性,因此我们可以使用 ES6 中 Symbol 或 WeakMap 来实现:

方法2:使用 ES6 的 Symbol 基本数据类型实现
知识点复习:ES6 中的 Symbol 介绍

const _items = Symbol()
class Stack {
  constructor (){
    this[_items] = []
  }
  push (element){
    this[_items].push(element)
  }
  // 剩下方法和第一种实现的差不多,这里省略
  // 只要把前面方法中的 this.items 更改为 this[_items]
}

 方法3:使用 ES6 的 WeakMap 实现

知识点复习:ES6 中的 WeakMap 介绍

 

const items = new WeakMap()
class Stack {
  constructor (){
    items.set(this, [])
  }
  push (element){
    let item = items.get(this)
    item.push(element)
  }
  // 剩下方法和第一种实现的差不多,这里省略
  // 只要把前面方法中的获取 this.items 的方式,更改为 items.get(this) 获取
}

 三、编写一个函数,实现十进制转二进制

题目意思很简单,就是十进制转二进制,但是在实际工作开发中,我们更愿意实现的是任意进制转任意进制,不过呢,我们还是以解决问题为首要目标呀。

当然,业务需求可以直接使用 toString(2) 方法,但是为了练习,咱还是不这么用咯。

方法1:使用前面定义的 Stack 类

这里使用前面题目中定义的 Stack 类。

/**
 * 十进制转换为二进制
 * @param {Number} bit 
 */
function bitset (bit){
  if(bit == 0) return '0'
  if(!/^[0-9]+.?[0-9]*$/.test(bit)){
    return new Error('请输入正确的数值!')
  }

  let stack = new Stack(), result = ''
  while (bit > 0){
    stack.push(bit % 2)
    bit = Math.floor(bit / 2)
  }
  while (!stack.isEmpty()){
    result += stack.pop().toString()
  }
  return result

}

方法2:简单实现

下面这个方法,其实不太好,因为没有怎么用到这次要练习的栈方法,哈哈。

/**
 * 十进制转换为二进制
 * @param {Number} bit 
 */
function bitset (bit){
  if(bit == 0) return '0'
  if(!/^[0-9]+.?[0-9]*$/.test(bit)){
    return new Error('请输入正确的数值!')
  }

  let arr = []
  while(bit > 0){
    arr.push(bit % 2)
    bit = Math.floor(bit / 2)
  }
  return arr.reverse().join('')
}

另外可以参考:wikiHow - 从十进制转换为二进制。

四、编写一个函数,实现检验圆括号顺序的有效性

主要目的就是:该函数接收一个圆括号字符串,判断里面的括号顺序是否有效,如果有效则返回 true 反之 false。
如:

  1. (   -> false
  2. ()  -> true
  3. (() -> false
  4. ()) -> false
  5. ()) -> false
  6. (((()()))()) -> true

这个题目实现的主要方法是:遍历字符串,先排除错误情况,然后将 ( 入栈保存,将 ) 入栈匹配前一个元素是否是 ( ,如果是,则 pop() 前一个元素 (,如果不是,则 push() 这个 ) 入栈,最终查看栈是否为空,若是则检验成功,否则失败。

方法1:使用前面定义的 Stack 类

这里使用前面题目中定义的 Stack 类。

/**
 * 检验圆括号顺序的有效性
 * @param {String} str 
 */
function validParentheses (str){
  if(!str || str.length === 0 || str[0] === ')') return false

  let stack = new Stack()
  str.split('').forEach(char => {
    let status = stack.peek() === '(' && char === ')'
    status ? stack.pop() : stack.push(char)
  })
  return stack.isEmpty()
}

方法2:出入栈操作

/**
 * 检验圆括号顺序的有效性
 * @param {String} str 
 */
function validParentheses (str){
  if(!str || str.length === 0 || str[0] === ')') return false

  let arr = []
  for(let i = 0; i < str.length ; i++){
    str[i] === '(' ? arr.push(str[i]) : arr.pop()
  }
  return arr.length === 0
}

五、改造题二,添加一个 min 函数来获得栈中最小元素

步骤 数据栈 辅助栈 最小值
1.push 3 3 0 3
2.push 4 3, 4 0, 0 3
3.push 2 3, 4, 2 0, 0, 2 2
4.push 1 3, 4, 2 ,1 0, 0, 2, 3 1
5.pop 3, 4, 2 0, 0, 2 2
6.pop 3, 4 0, 0 3
7.push 3, 4 ,0 0, 0, 2 0

使用示例如下:

let stack = new Stack();
stack.push(3);
console.log('After push 3, Min item is', stack.min());
stack.push(4);
console.log('After push 4, Min item is', stack.min());
stack.push(2);
console.log('After push 2, Min item is', stack.min());
stack.push(1);
console.log('After push 1, Min item is', stack.min());
stack.pop();
console.log('After pop, Min item is', stack.min());
stack.pop();
console.log('After pop, Min item is', stack.min());
stack.push(0);
console.log('After push 0, Min item is', stack.min());

提示:利用辅助栈(Web 端可利用数组),每次对栈 push/pop 元素时,也同时更新辅助栈(存储最小元素的位置)

方法1:小操作

class Stack {
 constructor() {
  this.items = [];
  this.minIndexStack = [];
 }

 push(element) {
  this.items.push(element);
  let minLen = this.minIndexStack.length;
  let minItemIndex = this.minIndexStack[minLen - 1];
  if(minLen === 0 || this.items[minItemIndex] > item) {
   this.minIndexStack.push(this.items.length - 1);
  } else {
   this.minIndexStack.push(minItemIndex);
  }
 }

 pop() {
  this.minIndexStack.pop();
  return this.items.pop();
 }
 
 min() {
  let len = this.minIndexStack.length;
  return (len > 0 && this.items[this.minIndexStack[len - 1]]) || 0;
 }

 peek() {
  return this.items[this.items.length - 1];
 }
 
 // 省略其它方法
}

方法2:与方法1中push实现的差异

class Stack {
  constructor (){
    this.items = [] // 数据栈
    this.arr = []  // 辅助栈
  }
  push( element ){
    this.items.push(element)
    let min = Math.min(...this.items)
    this.arr.push( min === element ? this.size() - 1 : 0)
  }
  pop(){
    this.arr.pop()
    return this.items.pop()
  }
  peek(){
    return this.items[this.items.length - 1]
  }
  isEmpty(){
    return this.items.length === 1
  }
  clear(){
    this.items = []
  }
  size(){
    return this.items.length
  }
  min (){
    let last = this.arr[this.arr.length - 1]
    return this.items[last]
  }
}

以上所述是小编给大家介绍的数据结构与算法(Stack)详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

相关文章

  • javascript实现别踩白块儿小游戏程序

    javascript实现别踩白块儿小游戏程序

    我们先看到的未开始的页面黑色和白色方块是随机生成的,完了这么多把没有发现时固定不变的。点击一次方块,程序需要判断是黑色还是白色的。如果是黑色的,当然程序也是实现了一次自减,在动画中是实现一次下移的,下移的时候点击的方块到黄颜色的区域会变成灰色
    2015-11-11
  • 可以拖动的div 实现代码

    可以拖动的div 实现代码

    可以拖动的div是一个比较难以做到的效果,特别是在浏览器对于js代码的运行效率还不是足够高的情况下,不过听说firefox对于js的支持正在增加,大概是料到了js在网页浏览的桌面化趋势中所占的重要地位吧。
    2009-06-06
  • ie浏览器使用js导出网页到excel并打印

    ie浏览器使用js导出网页到excel并打印

    简单介绍一种可以使用简单的JS来实现把网页中的信息原样导出到Excel、还可以打印的方法,需要的朋友可以参考下
    2014-03-03
  • iframe窗口高度自适应的实现方法

    iframe窗口高度自适应的实现方法

    这篇文章主要介绍了iframe窗口高度自适应的实现方法,有需要的朋友可以参考一下
    2014-01-01
  • js前端存储之sessionStorage使用方法举例

    js前端存储之sessionStorage使用方法举例

    sessionStorage是指本地存储一个会话中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁,这篇文章主要给大家介绍了关于js前端存储之sessionStorage使用方法的相关资料,需要的朋友可以参考下
    2024-06-06
  • JavaScript股票的动态买卖规划实例分析上篇

    JavaScript股票的动态买卖规划实例分析上篇

    这篇文章主要介绍了JavaScript对于动态规划解决股票问题的真题例举讲解。文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • 原生js仿淘宝网商品放大镜效果

    原生js仿淘宝网商品放大镜效果

    本文主要介绍了原生js仿淘宝网商品放大镜效果的实例,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • 利用JavaScript实现一个日期范围选择器

    利用JavaScript实现一个日期范围选择器

    日期范围选择器是一个常见的Web应用功能,它允许用户选择一个日期范围,本文我们将使用JavaScript来实现这个功能,感兴趣的小伙伴可以了解下
    2024-01-01
  • js判断数组是否包含某个字符串变量的实例

    js判断数组是否包含某个字符串变量的实例

    下面小编就为大家分享一篇js判断数组是否包含某个字符串变量的实例,具有很好的参考价值,希望对大家有所帮助
    2017-11-11
  • JavaScript中的垃圾回收与内存泄漏示例详解

    JavaScript中的垃圾回收与内存泄漏示例详解

    这篇文章主要给大家介绍了关于JavaScript中垃圾回收与内存泄漏的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用JavaScript具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-05-05

最新评论