5 手写Java Stack 核心源码

Stack是Java中常用的数据结构之一,Stack具有"后进先出(LIFO)"的性质。

只能在一端进行插入或者删除,即压栈与出栈

栈的实现比较简单,性质也简单。可以用一个数组来实现栈结构。

  1. 入栈的时候,只在数组尾部插入
  2. 出栈的时候,只在数组尾部删除**

我们来看一下Stack的用法 :如下

  public static void main(String[] args){

        //新建一个栈
        Stack<String> stack = new Stack<>();

        //分别向栈中添加不同的元素
        stack.push("tom");
        stack.push("jim");
        stack.push("wendy");
        stack.push("natasha");

        //分别弹栈
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());

    }

输出如下:

natasha
wendy
jim
tom

从输出可以看到,最后入栈的,最先出栈

下面我们底层用数组也来实现这样一个栈,在数组的尾部插入和删除。

也就是入栈和出栈。如下图:

完整的源码如下:

public class QStack<E> {
    //数组的默认大小为10
    private static final int DEFAULT_INIT_CAPACITY = 10;

    //底层的数组
    private Object[] elements;

    //栈中的个数
    private int size;

    public QStack() {
        this(DEFAULT_INIT_CAPACITY);
    }

    public QStack(int capacity) {
        //capacity条件检查 ,这里我们直接抛出异常
        if (capacity <= 0) {
            throw new IllegalArgumentException("capacity <= 0");
        }

        if (capacity > Integer.MAX_VALUE) {
            throw new IllegalArgumentException("capacity > Integer.MAX_VALUE");
        }

        //新建一个capacity大小的数组
        elements = new Object[capacity];

        //初始个数为0
        size = 0;
    }

    //栈是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    //返回栈中的元素个数
    public int size() {
        return size;
    }

    //将一个元素压入栈中
    public E push(E e) {
        //如果栈已满,进行扩容
        if (size >= elements.length) {
            grow();
        }

        //扩容完后将元素e压入栈中
        elements[size] = e;

        //别忘了size需要加 1
        size++;

        return e;
    }

    //出栈,就是将数组最后一个元素弹出
    public E pop() {
        //如果栈为空就返回null
        if (isEmpty()) {
            return null;
        }

        //拿到栈的大小
        int len = size();

        //把数组中最后一个元素保存起来
        E e = peek();
        //个数别忘了减1
        size--;

        //将最后一个元素置null
        elements[len - 1] = null;

        //返回e
        return e;
    }

    //返回最后一个元素
    public E peek() {
        int len = size();

        if (len == 0)
            throw new RuntimeException("stack is empty");

        return (E) elements[len - 1];
    }

    //扩容
    private void grow() {
        //将之前的数组保存
        int oldCapacity = elements.length;
        Object[] old = elements;

        //新的数组大小为原来数组大小的2倍
        int newCapacity = oldCapacity * 2;
        //再新建一个大小为原来数组2倍的新数组
        elements = new Object[newCapacity];

        //把以前的老的数组中的元素都移动新数组中
        for (int i = 0; i < oldCapacity; i++) {
            elements[i] = old[i];
        }

        //释放以前的内存空间
        old = null;
    }

}

以上面可知:用数组实现栈结构,主要需要注意以下 2 点:

  1. 在数组的尾部插入和删除,也就是压栈和弹栈
  2. 由于是用数组实现栈结构,数组满的时候,需要扩容

下面我们写一段测试代码来测试,如下:

   public static void main(String[] args){
        //创建一个栈
        QStack<String> stack = new QStack<>();

        //分别向栈中压入4个不同的元素
        stack.push("tom");
        stack.push("jim");
        stack.push("wendy");
        stack.push("natasha");

        //分别弹栈
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
    }

打印如下:

natasha
wendy
jim
tom

原文地址:https://www.cnblogs.com/start1225/p/10099988.html

时间: 2024-08-30 07:03:59

5 手写Java Stack 核心源码的相关文章

Java HashMap 核心源码解读

本篇对HashMap实现的源码进行简单的分析. 所使用的HashMap源码的版本信息如下: /* * @(#)HashMap.java 1.73 07/03/13 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ 一.概述 在Java中每一个对象都有一个哈希码,这个值可以通过hashCo

java集合核心源码01——ArrayList

首先呢,对于ArrayList,相当于一个动态数组,里面可以存储重复数据,并且支持随机访问,不是线程安全的.对于更多的底层东西,且听分解. 打开源码,先看继承了哪些类,实现了哪些接口,然后继承的这些类或接口是否还有父类,一直深挖到顶部 public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable 可以看

1 手写ArrayList核心源码

手写ArrayList核心源码 ArrayList是Java中常用的数据结构,不光有ArrayList,还有LinkedList,HashMap,LinkedHashMap,HashSet,Queue,PriorityQueue等等,我们将手写这些常用的数据结构的核心源码,用尽量少的代码来揭示核心原理. 下面我们来手写ArrayList的核心源码 首先我们定义一个QArrayList,不要问为什么叫QArrayList,因为我之前写过Qt,仅此而已.源码 public class<T> QAr

1小时手写SpringMVC T5大牛带你解读Spring核心源码(附详细视频教程)

SpringMVC简介 SpringMVC是当前最优秀的MVC框架,自从Spring 2.5版本发布后,由于支持注解配置,易用性有了大幅度的提高.Spring 3.0更加完善,实现了对Struts 2的超越.现在越来越多的开发团队选择了Spring MVC. Spring为展现层提供的基于MVC设计理念的优秀的Web框架,是目前最主流的MVC框架之一 Spring3.0后全面超越Struts2,成为最优秀的MVC框架 Spring MVC通过一套MVC注解,让POJO成为处理请求的控制器,而无须

Backbone事件机制核心源码(仅包含Events、Model模块)

一.应用场景 为了改善酷版139邮箱的代码结构,引入backbone的事件机制,按照MVC的分层思想搭建酷版云邮局的代码框架.力求在保持酷版轻量级的基础上提高代码的可维护性. 二.遗留问题 1.backbone的升级问题,新的特性无法引入 2.backbone中的潜在BUG,若官方已修复则无法同步更新 解决办法: 关注backbone官网的更新记录. http://github.com/documentcloud/backbone/ 三.核心源码 /** * @裁剪版backbone,仅包含Ev

携程系统架构师带你手写spring mvc,解读spring核心源码!

讲师简介: James老师 系统架构师.项目经理 十余年Java经验,曾就职于携程.人人网等一线互联网公司,专注于java领域,精通软件架构设计,对于高并发.高性能服务有深刻的见解, 在服务化基础架构和微服务技术有大量的建设和设计经验. 课程内容: 1.为什么读Spring源码? 如果你是一名JAVA开发人员,你一定用过Spring Framework. 作为一款非常经典的开源框架,从2004年发布的1.0版本到现在的5.0版本,经历了14年的洗礼, 持久不衰 与其说现在是JAVA的天下, 不如

java并发之线程池Executor 核心源码解析

1.什么是线程池 定义:线程池是指管理一组同构工作线程的资源池 组成部分: 线程管理器(ThreadPool):用于创建并管理线程池.包括创建线程池,销毁线程池,添加新任务 工作线程(PoolWorker):线程池中的线程 任务接口(Task):每个任务必须实现的接口,一共工作线程调度任务的执行 任务队列:用于存放没有处理的任务,提供一种缓冲机制 2.为什么要使用线程池 通过重用现有的线程而不是创建新线程,从而减少了线程创建 和 销毁过程中的巨大开销 当请求到达时,工作线程已经存在,不用再等待线

迷你版jQuery——zepto核心源码分析

前言 zepto号称迷你版jQuery,并且成为移动端dom操作库的首选 事实上zepto很多时候只是借用了jQuery的名气,保持了与其基本一致的API,其内部实现早已面目全非! 艾伦分析了jQuery,小钗暂时没有那个本事分析jQuery,这里就恬不知耻说说自己对zepto的源码理解,希望对各位有用 首先zepto的出现其实还是很讨巧的,他看见了巨人jQuery在移动浪潮来临时的转身慢.牵挂多的问题 马上搞出了一套轻量级类jQuery框架代码,核心代码1000行不到,快速占领了移动端的市场,

JDK核心源码(2)

Java的基础知识有很多,但是我认为最基础的知识应该要属jdk的基础代码, jdk的基础代码里面,有分了很多基础模块,其中又属jdk包下面的lang包最为基础. 我们下面将总结和分析一下lang包下面最为基础和常用的几个部分. 1:常用的对象类型包 (1)其中最基础的类为Object,所有的对象都是继承于这个类的.我们知道所有的类如果没有显示的声明继承于哪个类的话,默认都会继承于Object类,这个类里面也有很多我们常用的方法的默认实现. (2)然后就是字符串类了,我们常用的有String.St