概念

栈是一种线性结构,相比数组,栈对应的操作是数组的子集,只能从一端添加元素,也只能从一端取出元素,这一端称为栈顶.
image.png

特点

栈是一种先进后出(后进先出)的数据结构.

image.png

数组栈实现

  1. public interface Stack<E> {
  2. /**
  3. * 获取栈中元素个数
  4. *
  5. * 时间复杂度 O(1)
  6. * @return int
  7. */
  8. int getSize();
  9. /**
  10. * 判断栈是否为空
  11. *
  12. * 时间复杂度 O(1)
  13. * @return boolean
  14. */
  15. boolean isEmpty();
  16. /**
  17. * 在栈中添加元素e(入栈)
  18. *
  19. * 时间复杂度 O(1)均摊
  20. * @param e 元素
  21. */
  22. void push(E e);
  23. /**
  24. * 从栈中取出元素(出栈)
  25. *
  26. * 时间复杂度 O(1)均摊
  27. * @return E
  28. */
  29. E pop();
  30. /**
  31. * 查看栈顶元素
  32. *
  33. * 时间复杂度 O(1)
  34. * @return E
  35. */
  36. E peek();
  37. }

注意:这里的Array类是前面动态数组实现的Array类,点击动态数组跳转:

  1. public class ArrayStack<E> implements Stack<E> {
  2. Array<E> array;
  3. public ArrayStack(int capacity) {
  4. array = new Array<>(capacity);
  5. }
  6. public ArrayStack() {
  7. array = new Array<>();
  8. }
  9. @Override
  10. public int getSize() {
  11. return array.getSize();
  12. }
  13. @Override
  14. public boolean isEmpty() {
  15. return array.isEmpty();
  16. }
  17. public int getCapacity() {
  18. return array.getCapacity();
  19. }
  20. @Override
  21. public void push(E e) {
  22. //在数组末尾添加元素
  23. array.addLast(e);
  24. }
  25. @Override
  26. public E pop() {
  27. return array.removeLast();
  28. }
  29. @Override
  30. public E peek() {
  31. return array.getLast();
  32. }
  33. @Override
  34. public String toString() {
  35. StringBuilder builder = new StringBuilder();
  36. builder.append("Stack: ");
  37. builder.append("[");
  38. for (int i = 0; i < array.getSize(); i++) {
  39. builder.append(array.get(i));
  40. if (i != array.getSize() - 1) {
  41. builder.append(",");
  42. }
  43. }
  44. builder.append("] top");
  45. return builder.toString();
  46. }
  47. public static void main(String[] args) {
  48. ArrayStack<Integer> stack = new ArrayStack<>();
  49. for (int i = 0; i < 5; i++) {
  50. //入栈
  51. stack.push(i);
  52. System.out.println(stack);
  53. }
  54. //出栈
  55. stack.pop();
  56. System.out.println(stack);
  57. }
  58. }

栈的应用

有效的括号(leetcode20题):

1. 要求:

  1. 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。<br />有效字符串需满足:<br />左括号必须用相同类型的右括号闭合。<br />左括号必须以正确的顺序闭合。

2. 使用Java的Stack实现:

  1. public static boolean isValid(String s) {
  2. Stack<Character> stack = new Stack<>();
  3. for (int i = 0; i < s.length(); i++) {
  4. char c = s.charAt(i);
  5. if (c == '(' || c == '[' || c == '{') {
  6. //将左括号全部放入栈中
  7. stack.push(c);
  8. } else {
  9. if (stack.isEmpty()) {
  10. return false;
  11. }
  12. //删除栈顶元素并返回栈顶元素
  13. char topChar = stack.pop();
  14. if (c == ')' && topChar != '(') {
  15. return false;
  16. }
  17. if (c == ']' && topChar != '[') {
  18. return false;
  19. }
  20. if (c == '}' && topChar != '{') {
  21. return false;
  22. }
  23. }
  24. }
  25. return stack.isEmpty();
  26. }

3.使用Java的Stack结合Map实现:

  1. public static boolean isValid2(String s) {
  2. int n = s.length();
  3. //当括号成对时必然是偶数,若不为偶数可直接返回false
  4. if (n % 2 == 1) {
  5. return false;
  6. }
  7. Map<Character, Character> pairs = new HashMap<Character, Character>() {{
  8. put(')', '(');
  9. put(']', '[');
  10. put('}', '{');
  11. }};
  12. Deque<Character> stack = new LinkedList<Character>();
  13. for (int i = 0; i < n; i++) {
  14. char ch = s.charAt(i);
  15. //当元素是右括号时,删除栈顶元素使用返回的被删除的栈顶元素判断是否等于当前key元素的value值,不等直接返回false
  16. if (pairs.containsKey(ch)) {
  17. if (stack.isEmpty() || !stack.pop().equals(pairs.get(ch))) {
  18. return false;
  19. }
  20. } else {
  21. //当元素是左括号时存入栈中
  22. stack.push(ch);
  23. }
  24. }
  25. //循环完毕,判断栈中是否还有元素,若没有元素则为ture
  26. return stack.isEmpty();
  27. }

4.使用go结合Map实现:

与Java版本Map实现方式思路一致

  1. func isValid(s string) bool {
  2. n := len(s)
  3. if n%2 == 1 {
  4. return false
  5. }
  6. pairs := map[byte]byte{
  7. ')': '(',
  8. ']': '[',
  9. '}': '{',
  10. }
  11. var stack []byte
  12. for i := 0; i < n; i++ {
  13. if pairs[s[i]] > 0 {
  14. if len(stack) == 0 || stack[len(stack)-1] != pairs[s[i]] {
  15. return false
  16. }
  17. stack = stack[:len(stack)-1]
  18. } else {
  19. stack = append(stack, s[i])
  20. }
  21. }
  22. return len(stack) == 0
  23. }

5.使用go不结合Map实现

与java版本的不结合map实现思路一致

  1. func isValid2(s string) bool {
  2. var stack []byte
  3. for i := 0; i < len(s); i++ {
  4. c := s[i]
  5. if c == '(' || c == '[' || c == '{' {
  6. stack = append(stack, c)
  7. } else {
  8. if len(stack) == 0 {
  9. return false
  10. }
  11. topChar := stack[len(stack)-1]
  12. if c == ')' && topChar != '(' {
  13. return false
  14. }
  15. if c == ']' && topChar != '[' {
  16. return false
  17. }
  18. if c == '}' && topChar != '{' {
  19. return false
  20. }
  21. stack = stack[:len(stack)-1]
  22. }
  23. }
  24. return len(stack) == 0
  25. }

6.使用上面自己实现的ArrayStack数组栈实现:

  1. public static boolean isValid3(String s){
  2. ArrayStack<Character> stack = new ArrayStack<>();
  3. for (int i = 0; i < s.length(); i++) {
  4. char c = s.charAt(i);
  5. if (c == '(' || c == '[' || c == '{') {
  6. //将左括号全部放入栈中
  7. stack.push(c);
  8. } else {
  9. if (stack.isEmpty()) {
  10. return false;
  11. }
  12. //删除栈顶元素并返回栈顶元素
  13. char topChar = stack.pop();
  14. if (c == ')' && topChar != '(') {
  15. return false;
  16. }
  17. if (c == ']' && topChar != '[') {
  18. return false;
  19. }
  20. if (c == '}' && topChar != '{') {
  21. return false;
  22. }
  23. }
  24. }
  25. return stack.isEmpty();
  26. }

项目demo