Java数据结构与算法分析(四)栈

简介: 栈又叫堆栈,是一种运算受限制的线性表,限定只能在一端进行插入和删除操作,该端称为栈顶(Top),相对的另一端叫栈底(Bottom)。

GitHub源码分享

项目主页:https://github.com/gozhuyinglong/blog-demos
本文源码:https://github.com/gozhuyinglong/blog-demos/tree/main/java-data-structures

1. 栈(Stack)

栈又叫堆栈,是一种运算受限制的线性表,限定只能在一端进行插入和删除操作,该端称为栈顶(Top),相对的另一端叫栈底(Bottom)。

根据栈的定义可知,最先进入栈的元素在栈底,最后进入栈的元素在栈顶。而删除元素刚好相反,即删除顺序从栈顶到栈底

对栈的操作只有两种:

  • 入栈(push):又叫进栈或压栈,即向栈插入一条新的元素,该元素为新的栈顶元素。
  • 出栈(pop):又叫退栈,即从栈顶删除(取出)最后入栈的元素,而其相邻元素成为新的栈顶元素。

栈的模型.jpg

栈是一个先进后出(FILO - First In Last Out)的有序列表。在上图中描述了栈的模型,我们对栈的操作只有pushpop,栈顶元素是该栈唯一可见的元素。

2. 代码实现

由于栈是一个表,因此任何实现表的方法都能实现栈。显然我们之前用到的《 数组 》和《 链表 》都可以实现栈。下面代码是使用数组实现的一个栈。

size表示栈内元素的大小,栈顶元素为 elementData[size - 1],栈底元素为 elementData[0]。入栈时执行 size++,出站时执行 size--

public class StackDemo {
   
   

    public static void main(String[] args) {
   
   

        System.out.println("-------------------入站");
        Stack<String> stack = new Stack<>(10);
        stack.push("a");
        stack.push("b");
        stack.push("c");
        stack.push("d");
        stack.push("e");
        stack.print();

        System.out.println("元素大小: " + stack.size());
        System.out.println("栈容量: " + stack.capacity());

        System.out.println("-------------------出站");
        System.out.println("出站元素: " + stack.pop());
        System.out.println("出站元素: " + stack.pop());
        stack.print();
        System.out.println("元素大小: " + stack.size());
        System.out.println("栈容量: " + stack.capacity());
    }

    private static class Stack<E> {
   
   
        private int size; // 元素大小
        private final int capacity; // 栈的容量
        transient Object[] elementData; // 元素数据

        public Stack(int capacity) {
   
   
            if (capacity <= 0) {
   
   
                throw new IllegalArgumentException("Illegal Capacity: " + capacity);
            } else {
   
   
                this.capacity = capacity;
                elementData = new Object[capacity];
            }
        }

        /**
         * 获取栈的元素大小
         *
         * @return
         */
        public int size() {
   
   
            return size;
        }

        /**
         * 获取栈的容量
         *
         * @return
         */
        public int capacity() {
   
   
            return capacity;
        }

        /**
         * 入栈
         *
         * @param e
         * @return
         */
        public boolean push(E e) {
   
   
            if (size >= capacity) {
   
   
                return false;
            }
            elementData[size++] = e;
            return true;
        }

        /**
         * 出栈
         *
         * @return
         */
        public E pop() {
   
   
            if (size <= 0) {
   
   
                return null;
            }
            return (E) elementData[--size];
        }

        /**
         * 打印元素数据
         */
        public void print() {
   
   
            System.out.print("站内元素: ");
            for (int i = 0; i < size; i++) {
   
   
                System.out.printf("%s\t", elementData[i]);
            }
            System.out.println();
        }
    }
}

输出结果:

-------------------入站
站内元素: a    b    c    d    e    
元素大小: 5
栈容量: 10
-------------------出站
出站元素: e
出站元素: d
站内元素: a    b    c    
元素大小: 3
栈容量: 10

3. 栈的应用 - 平衡符号

编译器检查程序的语法错误时,常常会因为缺少一个符号(如遗漏一个花括号等)引起编译器上列出上百行的诊断,而真正的错误并没有找出。在这种情况下,如果能有一个工具能够检测括号必须成对出现那就好了,这便可以使用栈进行解决。

下面代码使用了Java自带的Stack类进行实现。字符串[ ( ) ]是合法的,而[ ( ] )是错误的。

代码实现:

public class StackDemoBalancedChar {
   
   

    public static void main(String[] args) {
   
   

        BalancedChar balancedChar = new BalancedChar();
        String str = "[()][{}][][((()))]";
        boolean ok = balancedChar.isOk(str);
        System.out.printf("字符串:%s\t----> %s", str, ok);
    }

    private static class BalancedChar {
   
   
        private final char[] openArray = {
   
   '(', '[', '{'};  // 左括号
        private final char[] closeArray = {
   
   ')', ']', '}'}; // 右括号

        /**
         * 判断字符串是否正确
         *
         * @param str
         * @return
         */
        public boolean isOk(String str) {
   
   
            // 使用 Java 自带的 Stack 类
            Stack<Character> stack = new Stack<>();

            boolean ok = true; // 判断字符串是否正确

            for (char c : str.toCharArray()) {
   
   

                // 若不是平衡符则忽略
                if (!isBalancedChar(c)) {
   
   
                    continue;
                }

                // 如果是左括号,则入栈
                if (isOpen(c)) {
   
   
                    stack.push(c);
                    continue;
                }

                // 如果是右括号,而栈为空则报错
                if (stack.empty()) {
   
   
                    ok = false;
                    break;
                }
                // 如果是右括号,从栈中取出一个元素,并与当前元素判断是否是一对,若不是一对则报错
                Character open = stack.pop();
                if (!isTwain(open, c)) {
   
   
                    ok = false;
                }
            }

            return ok && stack.empty();
        }

        /**
         * 是否为左括号
         *
         * @param c
         * @return
         */
        public boolean isOpen(char c) {
   
   
            return inArray(openArray, c);
        }

        /**
         * 是否为右括号
         *
         * @param c
         * @return
         */
        public boolean isClose(char c) {
   
   
            return inArray(closeArray, c);
        }

        /**
         * 是否是平衡符
         */
        public boolean isBalancedChar(char c) {
   
   
            return isOpen(c) || isClose(c);
        }

        /**
         * 是否在数组中
         *
         * @param charArray
         * @param c
         * @return
         */
        public boolean inArray(char[] charArray, char c) {
   
   
            for (char c1 : charArray) {
   
   
                if (c1 == c) {
   
   
                    return true;
                }
            }
            return false;
        }

        /**
         * 是否一对平衡符
         *
         * @param open
         * @param close
         * @return
         */
        public boolean isTwain(char open, char close) {
   
   
            switch (open) {
   
   
                case '(':
                    if (close == ')') {
   
   
                        return true;
                    }
                case '[':
                    if (close == ']') {
   
   
                        return true;
                    }
                case '{':
                    if (close == '}') {
   
   
                        return true;
                    }
                default:
                    return false;
            }
        }

    }
}

输出结果:

字符串:[()][{}][][((()))]    ----> true
相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
159 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
26 1
|
2月前
|
存储 Java
Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。
【10月更文挑战第19天】本文详细介绍了Java中的HashMap和TreeMap,通过具体示例展示了它们在处理复杂数据结构问题时的应用。HashMap以其高效的插入、查找和删除操作著称,而TreeMap则擅长于保持元素的自然排序或自定义排序,两者各具优势,适用于不同的开发场景。
47 1
|
2月前
|
存储 Java
告别混乱!用Java Map优雅管理你的数据结构
【10月更文挑战第17天】在软件开发中,随着项目复杂度增加,数据结构的组织和管理至关重要。Java中的Map接口提供了一种优雅的解决方案,帮助我们高效、清晰地管理数据。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,有效提升了代码质量和维护性。
93 2
|
2月前
|
存储 Java 开发者
Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
71 2
|
3天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
21 5
|
17天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
38 5
|
1月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
47 6
|
1月前
|
存储 Java 索引
Java中的数据结构:ArrayList和LinkedList的比较
【10月更文挑战第28天】在Java编程世界中,数据结构是构建复杂程序的基石。本文将深入探讨两种常用的数据结构:ArrayList和LinkedList,通过直观的比喻和实例分析,揭示它们各自的优势与局限,帮助你在面对不同的编程挑战时做出明智的选择。

热门文章

最新文章