数据结构栈

46次阅读

共计 922 个字符,预计需要花费 3 分钟才能阅读完成。

1、栈

2、栈实现

 //stack 构造函数
 class Stack {items = [];
    constructor() {}
    // 元素入栈,返回栈的大小
    push(el) {return this.items.push(el);
    }

    // 元素出栈,返回出栈元素
    pop() {return this.items.pop();
    }

    // 获取栈的大小
    size() {return this.items.length;}

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

    // 清空栈
    clear() {this.items = [];
    }
 }

3、应用 - 数值转换

 /***
  * @description 十进制转化为 N 进制函数
  * @param {Number} metadata 被转化的数值
  * @param {Number} n 指定被转化的进制
  * @returns {string} 
  */
 function binaryConversion(metadata, n) {
    // 初始化一个栈对象
    let stack = new Stack();
    let remainder = 0;
    let res = "";
    while(Math.floor(metadata / n) !== 0) {
      // 计算余数
      // debugger;
      remainder = metadata % n;

      switch(remainder) {
        case 10:
          remainder = "A";
          break;
        case 11:
          remainder = "B";
          break;
        case 12:
          remainder = "C";
          break;
        case 13:
          remainder = "D";
          break;
        case 14:
          remainder = "E";
          break;
        case 14:
          remainder = "F";
          break;
      }
      
      // 余数入栈
      stack.push(remainder);
      //metadata 重新赋值
      metadata = Math.floor(metadata / n);
    }
    // 最后一次计算余数没有入栈,这里需要加一次入栈操作
    remainder = metadata % n;
    stack.push(remainder);

    // 输出最后结果
    while(!stack.isEmpty()) {res += stack.pop();
    }
    return res;
 }

正文完
 0

数据结构栈

46次阅读

共计 3993 个字符,预计需要花费 10 分钟才能阅读完成。

数据结构 - 栈

定义

栈(英语:stack)又称为堆栈或堆叠,栈作为一种数据结构,它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
由于堆叠数据结构只允许在一端进行操作,因而按照后进先出(LIFO, Last In First Out)的原理运作。栈也称为后进先出表

栈的应用场景

undo 操作(撤销)

  • 例如:将操作的每组数据存入栈中,如果想要撤销,只需要弹出栈顶元素,就可以恢复上一步操作了。

程序调用的系统栈

  • 例如:A 方法调用 B 方法得到返回值,B 调用 C 得到返回值,A 操作走到了 B 方法,这个时候可以将 A 的代码位置存储到栈中,然后走到 B 方法,B 操作走到了 C 方法,这个时候可以将 B 的代码位置存储到栈中。最后 C 执行完成,根据栈的结构开始弹出数据,一步一步再走回 A 方法。

判断括号是否有效。下文会有代码实现(详细规则描述可以参考 leetcode 第 20 题)

  • 开括号必须用同一类型的括号闭合。
  • 开方括号必须按正确顺序闭合。
  • 例如:正确的:{[()]} [{()}] ({[]}) 等。错误的:[{(})] [}{()] 等。

自定义栈基类的代码实现

  • 栈在 java.util 有一个工具类,先不用,自定义实现一个
创建一个接口,用来统一规范所有栈实现
package com.datastructure.stack;

public interface Stack<E> {

    /**
     * 向栈插入元素
     * @param e
     */
    public  void push(E e);


    /**
     * 取出最上面的元素,并且返回
     * @return
     */
    public E pop();

    /**
     * 获取栈的大小
     * @return
     */
    public int getSize();

    /**
     * 判断栈是否为空
     * @return
     */
    public boolean isEmpty();

    /**
     * 获取栈最上面的元素
     * @return
     */
    public E peek();}
用基于数组的方式来实现一个栈(上文所写的自定义数组)
package com.datastructure.stack;

import com.datastructure.array.Array;

/**
 * @program: test
 * @description:
 * @author: Mr.Yang
 * @create: 2019-05-02 15:27
 **/
public class ArrayStack<E> implements Stack<E>{

    Array<E> array;

    public ArrayStack(int capacity){array=new Array<E>(capacity);
    }



    public ArrayStack(){array=new Array<E>();
    }

    @Override
    public void push(E e) {array.addLast(e);
    }

    @Override
    public E pop() {return array.removeLast();
    }

    @Override
    public int getSize() {return array.getSize();
    }


    @Override
    public boolean isEmpty() {return array.isEmpty();
    }


    @Override
    public E peek() {return array.getLast();
    }

    /**
     * 获取容量值
     * @return
     */
    public int getCapacity(){return array.getCapacity();
    }


    @Override
    public String toString(){StringBuffer sb = new StringBuffer();
        sb.append("stack:");
        sb.append("[");
        for(int i=0;i<array.getSize();i++){sb.append(array.get(i));
            if(i!=array.getSize()-1){sb.append(",");
            }
        }
        sb.append("]            right value is stack top");
        return sb.toString();}
}
测试代码
package com.datastructure.stack;

/**
 * @program: test
 * @description:
 * @author: Mr.Yang
 * @create: 2019-05-02 16:11
 **/
public class StackTest {public static void main(String[] args) {ArrayStack<Integer> integerArrayStack = new ArrayStack<>();
        for(int i=0;i<5;i++){integerArrayStack.push(i);
            System.out.println(integerArrayStack);
        }
        Integer pop = integerArrayStack.pop();
        System.out.println("---- 移除上级元素 ----value is"+pop);
        System.out.println("------------- 移除之后的栈打印 ------------------");
        System.out.println(integerArrayStack);
    }
}
测试结果
stack: [0]            right value is stack top
stack: [0, 1]            right value is stack top
stack: [0, 1, 2]            right value is stack top
stack: [0, 1, 2, 3]            right value is stack top
stack: [0, 1, 2, 3, 4]            right value is stack top
---- 移除上级元素 ----value is 4
------------- 移除之后的栈打印 ------------------
stack: [0, 1, 2, 3]            right value is stack top

leetCode 第 20 题,花括号正确闭合

思路
  • 根据栈的数据结构特点,我们可以先将所有左括号‘[{(’放进栈中,然后判断当前字符如果是‘)]}’这种的右括号,但是栈顶的括号却不匹配,返回 false
  • 注意控制判断
  • 这里使用 java 自带的栈工具类来实现
  • leetcode 给的测试例子:
1 2 3 4 5
输入例子 () ()[]{} (] ([)] {[]}
代码实现
package com.datastructure.stack;

import java.util.Stack;

/**
 * @program: test
 * @description:
 * @author: Mr.Yang
 * @create: 2019-05-02 16:59
 **/
public class Solution {public static void main(String[] args) {Solution solution = new Solution();
        System.out.println(solution.isValid("{\"name\": \" 网站 \",\"num\": 3,\"sites\": [ \"Google.com\", \"Taobao.com\", \"Waibo.wang\"]}"));
    }
    public boolean isValid(String s) {Stack<Character> characters = new Stack<>();
        for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);
            if (c == '{' || c == '[' || c == '(') {characters.push(c);
            } else {if(characters.isEmpty()){return false;}
                Character peek = characters.pop();
                switch (c) {case '}':
                        if (!peek.equals('{')) {return false;}
                        continue;
                    case ']':
                        if (!peek.equals('[')) {return false;}
                        continue;
                    case ')':
                        if (!peek.equals('(')) {return false;}
                        continue;
                }
            }
        }
        return characters.isEmpty();}

    /*public boolean isValid(String s) {Stack<Character> characters = new Stack<>();
        for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);
            if (c == '{' || c == '[' || c == '(') {characters.push(c);
            } else {if(characters.isEmpty()){return false;}
                Character toChar = characters.pop();
                if(c == ')' && toChar != '('){return false;}
                if(c == '}' && toChar != '{'){return false;}
                if(c == ']' && toChar != '['){return false;}
            }
        }
        return characters.isEmpty();}*/
}
如果想实现更多字符串关于括号的匹配,如 JSON 等等,可以根据栈的特点来实现

代码例子 GIT 地址:https://git.dev.tencent.com/y…
项目简介:
这个项目是我做测试,学习的主要项目,目前里面包含了:

  • 一些设计模式的 demo(抽象工程模式,适配器模式,外观模式,命令模式,装饰者模式等等)
  • 即将学习的数据结构 demo,数组,栈,后续还会持续更新数据结构,可能会有队列,链表,递归,红黑树,线段树等等一系列,如果感兴趣,欢迎留言。

正文完
 0

数据结构-栈

45次阅读

共计 2505 个字符,预计需要花费 7 分钟才能阅读完成。

前言
数组是 JS 中最常用的数据结构,它可以在任意位置添加或删除数据。栈是另外一种数据结构,类似于数组,但是在添加或删除数据时更加灵活。
栈数据结构
栈是一种 后进先出(LIFO)的数据结构。新添加或待删除的元素都保存在栈的一端,叫 栈顶,另一端就叫做 栈底。在栈中,新元素都靠近栈顶,就元素都靠近栈底。
创建栈
可以用数组来模拟一个栈结构:
function Stack() {
let items = []
// 栈的属性和方法
}
需要实现的方法:

push(element): 添加一个元素到栈顶
pop(): 移除栈顶的元素,并返回该元素
peek(): 仅仅返回栈顶的元素
clear(): 清空栈
size(): 返回栈中的元素的个数
isEmpty(): 判断栈是否为空

// 向栈中添加元素
this.push = function (element) {
items.push(element)
}
// 从栈中移除元素
this.pop = function () {
return items.pop()
}
// 查看栈顶元素
this.peek = function () {
return items[item.length – 1]
}
// 检查栈是否为空
this.isEmpty = function () {
return !!item.length
}
// 清空栈中的元素
this.clear = function () {
items = []
}
// 返回栈的大小
this.size = function () {
return items.length
}
// 打印栈
this.print = function () {
console.log(items.toString())
}
ES6 与 栈
ES6 的写法:
class Stack {
constructor() {
this.items = []
}
push (element) {
this.items.push(element)
}
// … 其他方法
}
ES6 的类是基于原型的,虽然基于原型的类比基于函数的类更节省内存,但是却不能声明私有变量,所以变量 items 是公共的。这种情况下,可以直接通过修改 items 来修改栈中的数据,这是无法避免的。
用 ES6 的限定作用域 Symbol 实现类
ES6 新增了 Symbol 基础类型,它是不可变的,也可以作用对象的属性。
let _items = Symbol()
class Stack {
constructor() {
this[_items] = []
}
// … 其他方法
}
上面这个例子创建了一个假的私有属性,不能完全规避上面提到的问题,因为 ES6 新增的 Object.getOwnPropertySymbols 方法能够取到类里面声明的所有 Symbols 属性,比如:
let stack = new Stack()
stack.push(66)
stack.push(88)
let objectSymbols = Object.getOwnPropertySymbols(stack)
console.log(objectSymbols.length) // 1
console.log(objectSymbols[0]) // Symbol()
stack[objectSymbols[0]].push(1)
stack.print() // 66 88 1
通过访问 stack[objectSymbols[0]] 是可以访问 _items 的,并且可以对 _items 进行任意操作。
用 ES6 的 WeakMap 实现类
有一种数据类型可以确保属性是私有的,这就是 WeakMap。WeakMap 可以存储键值对,其中键是对象,值可以是任意数据类型。
const items = new WeakMap()
class Stack {
constructor() {
items.set(this, [])
}
push(element) {
let s = items.get(this)
s.push(element)
}
pop() {
let s = items.get(this)
return s.pop()
}
// … 其他方法
}
现在,Stack 中的 items 是私有的了,但是 items 是在 Stack 类以外声明的,还是可以被改动,所以需要借助闭包来实现一层封装:
let Stack = (function () {
const items = new WeakMap()
class Stack {
constructor() {
items.set(this, [])
}
// … 其他方法
return Stack
}
})()
### 用栈解决实际问题 栈在 JS 中应用还是十分广泛的,比如 调用栈。进制转换也是很常见的例子,可以用 栈 来处理,比如要把十进制转化成二进制,可以将该十进制数字和 2 整除,直到结果是 0 为止。
function divideBy2 (decNumber) {
var remStack = new Stack(),
rem,
binaryString = ”

while (decNumber > 0) {
rem = Math.floor(decNumber % 2)
remStack.push(rem)
decNumber = Math.floor(decNumber / 2)
}
while (!remStack.isEmpty()) {
binaryString += remStack.pop().toString()
}
return binaryString
}
这个例子中,当结果满足和 2 做整除的条件是,会取得当前结果和 2 的余数,放到栈里,然后让结果继续和 2 做整除。
#### 改进算法 把上面的例子改成十进制转成任意进制的:
function baseConverter(decNumber, base) {
var remStack = new Stack(),
rem,
binaryString = ”,
digits = ‘0123456789ABCDEF’

while (decNumber > 0) {
rem = Math.floor(decNumber % base)
remStack.push(rem)
decNumber = Math.floor(decNumber / base)
}
while (!remStack.isEmpty()) {
binaryString += digits[remStack.pop()]
}
return binaryString
}

正文完
 0