Java集合篇之逐渐被遗忘的Stack,手写一个栈你会吗?

简介: 总之,虽然在日常开发中,`java.util.Stack`正逐渐被其他类如 `Deque`接口的实现所取代,但手写一个栈(无论是基于数组还是链表)都是一次很好的编程练习,它可以帮助开发者更加深入地理解栈这种数据结构的工作原理和各种操作。

在Java集合框架中,Stack类是一个后入先出(LIFO)的堆栈,但在现代的Java开发中,这个类往往被 Deque接口的实现类(如 LinkedListArrayDeque)所替代。不过,手写一个栈结构不仅是对数据结构理解的一种体现,也是检验编程能力的一个很好的例子。

为了实现一个基础的栈,我们可以使用数组或链表作为内部存储结构。以下是使用数组实现的一个简单的栈结构,考虑到易懂和实用性,我会展示一个简易版本的栈实现,它将支持基本的操作:压栈(push)、弹栈(pop)、查看栈顶元素(peek)和检查栈是否为空(isEmpty)。首先,我们定义栈的数据结构如下:

public class CustomStack<E> {
    private Object[] array;
    private int size;
    private static final int DEFAULT_CAPACITY = 10;

    public CustomStack() {
        array = new Object[DEFAULT_CAPACITY];
        size = 0;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public E peek() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        return (E) array[size - 1];
    }

    public E pop() {
        E element = peek();
        array[--size] = null; // 防止内存泄漏
        return element;
    }

    public void push(E item) {
        ensureCapacity();
        array[size++] = item;
    }

    private void ensureCapacity() {
        if (size >= array.length) {
            int newSize = array.length * 2;
            array = Arrays.copyOf(array, newSize);
        }
    }

    // 更多实用方法(例如返回栈的大小,遍历等)可以根据需要增加
}

在这个 CustomStack类中,我们使用了泛型来提供类型安全,并且内部使用了一个 Object类型的数组来存储栈中的元素。数组的初始化大小为 DEFAULT_CAPACITY,这是我们预设的一个值,在数组容量不够时,通过 ensureCapacity方法进行扩容。

push方法将元素压入栈,并在必要时增加数组的大小。pop方法从栈中移除顶部元素并返回这个元素,该方法在执行之前会调用 peek方法来确保栈不为空,并获取栈顶元素。

这种简单的栈实现在功能上可能与 java.util.Stack类类似,但它避免了继承自 Vector类的 java.util.Stack带来的线程同步开销。在多线程环境下,我们需要关注线程安全的问题,java.util.Stack是线程同步的,如果不需要这个特性,使用我们自己的 CustomStack会更高效。

如果需要使用链表来手写栈,则可以创建一个节点类来代表链表的节点,然后在栈类中使用这些节点来存储信息。链表实现的栈可以避免数组实现时的数组扩容操作,从而提高操作的效率。

总之,虽然在日常开发中,java.util.Stack正逐渐被其他类如 Deque接口的实现所取代,但手写一个栈(无论是基于数组还是链表)都是一次很好的编程练习,它可以帮助开发者更加深入地理解栈这种数据结构的工作原理和各种操作。

目录
相关文章
|
9天前
|
存储 算法 Java
惊!Java程序员必看:JVM调优揭秘,堆溢出、栈溢出如何巧妙化解?
【8月更文挑战第29天】在Java领域,JVM是代码运行的基础,但需适当调优以发挥最佳性能。本文探讨了JVM中常见的堆溢出和栈溢出问题及其解决方法。堆溢出发生在堆空间不足时,可通过增加堆空间、优化代码及释放对象解决;栈溢出则因递归调用过深或线程过多引起,调整栈大小、优化算法和使用线程池可有效应对。通过合理配置和调优JVM,可确保Java应用稳定高效运行。
88 4
|
8天前
|
Java
用JAVA架建List集合为树形结构的代码方法
这段代码定义了一个表示树形结构的 `Node` 类和一个用于构建树形结构的 `TreeController`。`Node` 类包含基本属性如 `id`、`pid`、`name` 和 `type`,以及子节点列表 `children`。`TreeController` 包含初始化节点列表并将其转换为树形结构的方法。通过过滤和分组操作实现树形结构的构建。详情可见:[代码示例链接1](http://www.zidongmutanji.com/zsjx/43551.html),[代码效果参考链接2](https://www.257342.com/sitemap/post.html)。
23 5
|
8天前
|
存储 Java 程序员
Java中的集合框架:从入门到精通
【8月更文挑战第30天】在Java的世界里,集合框架是一块基石,它不仅承载着数据的存储和操作,还体现了面向对象编程的精髓。本篇文章将带你遨游Java集合框架的海洋,从基础概念到高级应用,一步步揭示它的奥秘。你将学会如何选择合适的集合类型,掌握集合的遍历技巧,以及理解集合框架背后的设计哲学。让我们一起探索这个强大工具,解锁数据结构的新视角。
|
9天前
|
Java 开发者
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选。相比 `synchronized`,Lock 提供了更灵活强大的线程同步机制,包括可中断等待、超时等待、重入锁及读写锁等高级特性,极大提升了多线程应用的性能和可靠性。通过示例对比,可以看出 Lock 接口通过 `lock()` 和 `unlock()` 明确管理锁的获取和释放,避免死锁风险,并支持公平锁选择和条件变量,使其在高并发场景下更具优势。掌握 Lock 接口将助力开发者构建更高效、可靠的多线程应用。
11 2
|
9天前
|
存储 算法 Java
Java中的集合框架深度解析云上守护:云计算与网络安全的协同进化
【8月更文挑战第29天】在Java的世界中,集合框架是数据结构的代言人。它不仅让数据存储变得优雅而高效,还为程序员提供了一套丰富的工具箱。本文将带你深入理解集合框架的设计哲学,探索其背后的原理,并分享一些实用的使用技巧。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往高效编程的大门。
|
7天前
|
存储 算法 Java
Java中的集合框架深度解析与实践
【8月更文挑战第31天】在Java编程的海洋中,集合框架扮演着不可或缺的角色。本文将带你领略Java集合框架的魅力,从理论到实践,深入浅出地探索List、Set和Map等核心接口的使用技巧。我们将通过具体代码示例,展示如何在日常开发中高效运用这些工具,让你的代码更加优雅和高效。无论你是初学者还是有经验的开发者,这篇文章都将为你打开一扇通往Java集合世界的大门。
|
7天前
|
存储 人工智能 Java
JAVA集合
【8月更文挑战第31天】
|
4天前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
26 6
【Java学习】多线程&JUC万字超详解
|
3天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
7天前
|
安全 Java 程序员
Java编程中实现线程安全的策略
【8月更文挑战第31天】在多线程环境下,保证数据一致性和程序的正确运行是每个程序员的挑战。本文将通过浅显易懂的语言和实际代码示例,带你了解并掌握在Java编程中确保线程安全的几种策略。让我们一起探索如何用同步机制、锁和原子变量等工具来保护我们的数据,就像保护自己的眼睛一样重要。
下一篇
DDNS