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

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

  1. 6 手写Java LinkedHashMap 核心源码

    概述 LinkedHashMap是Java中常用的数据结构之一,安卓中的LruCache缓存,底层使用的就是LinkedHashMap,LRU(Least Recently Used)算法,即最近最少 ...

  2. 3 手写Java HashMap核心源码

    手写Java HashMap核心源码 上一章手写LinkedList核心源码,本章我们来手写Java HashMap的核心源码. 我们来先了解一下HashMap的原理.HashMap 字面意思 has ...

  3. 2 手写Java LinkedList核心源码

    上一章我们手写了ArrayList的核心源码,ArrayList底层是用了一个数组来保存数据,数组保存数据的优点就是查找效率高,但是删除效率特别低,最坏的情况下需要移动所有的元素.在查找需求比较重要的 ...

  4. 1 手写Java ArrayList核心源码

    手写ArrayList核心源码 ArrayList是Java中常用的数据结构,不光有ArrayList,还有LinkedList,HashMap,LinkedHashMap,HashSet,Queue ...

  5. 4.1 手写Java PriorityQueue 核心源码 - 原理篇

    本章先讲解优先级队列和二叉堆的结构.下一篇代码实现 从一个需求开始 假设有这样一个需求:在一个子线程中,不停的从一个队列中取出一个任务,执行这个任务,直到这个任务处理完毕,再取出下一个任务,再执行. ...

  6. 4.2 手写Java PriorityQueue 核心源码 - 实现篇

    上一节介绍了PriorityQueue的原理,先来简单的回顾一下 PriorityQueue 的原理 以最大堆为例来介绍 PriorityQueue是用一棵完全二叉树实现的. 不但是棵完全二叉树,而且 ...

  7. Java HashMap 核心源码解读

    本篇对HashMap实现的源码进行简单的分析. 所使用的HashMap源码的版本信息如下: /* * @(#)HashMap.java 1.73 07/03/13 * * Copyright 2006 ...

  8. 手撕spring核心源码,彻底搞懂spring流程

    引子 十几年前,刚工作不久的程序员还能过着很轻松的日子.记得那时候公司里有些开发和测试的女孩子,经常有问题解决不了的,不管什么领域的问题找到我,我都能帮她们解决.但是那时候我没有主动学习技术的意识,只 ...

  9. Java内存管理-掌握类加载器的核心源码和设计模式(六)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 上一篇文章介绍了类加载器分类以及类加载器的双亲委派模型,让我们能够从整体上对类加载器有 ...

随机推荐

  1. 基于Kubernetes 构建.NET Core技术中台

    今天下午在腾讯云+社区社区分享了<基于Kubernetes 构建.NET Core技术中台>,下面是演讲内容的文字实录. 我们为什么需要中台 我们现在处于企业信息化的新时代.为什么这样说呢 ...

  2. CI学习相关地址

    1.CI中国:http://codeigniter.org.cn/ 2.CodeIgniter 2.1.3 for SAE:http://codeigniter.org.cn/forums/forum ...

  3. Windows踩坑笔记之使用_tWinMain报错的解决方案

    对于如下代码 #include <Windows.h> int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, ...

  4. [数据挖掘课程笔记]Naïve Bayesian Classifier

    朴素贝叶斯模型 1) X:一条未被标记的数据 2) H:一个假设,如H=X属于Ci类 根据贝叶斯公式 把X表示为(x1,x2,....xn) x1,x2,....xn表示X在各个特征上的值. 假设有c ...

  5. CentOS-7-64bit 下为firefox安装flashplayer

    最近更新了Centos 7 还是有一些不习惯的 给ff安flashplayer插件时,按centos 6.x的方法时都无法成功,后来find了一下,才知道firefox还有一个64bit的文件夹: 解 ...

  6. loj#2340. 「WC2018」州区划分

    FWT&&FMT板子 #include<cstdio> #include<iostream> #include<cstring> #include& ...

  7. 关于Ajax实现的简单示例

    一.代码示例 关于Ajax的基本概念(包括XMLHttpRequest对象及其相关方法属性)移步这里(w3school中文版)学习了解. <!doctype html> <html ...

  8. hdu 1753 大明A+B(大数)

    题意:小数大数加法 思路:大数模板 #include<iostream> #include<stdio.h> #include<string.h> using na ...

  9. 阿里云数据库产品HybridDB简介——OLAP数据库,支持行列混合存储,基于数据库Greenplum的开源版本,并且吸收PostgreSQL精髓

    为什么会有HybridDB的诞生?它经历了怎样的研发历程?它的应用场景和情况是怎样的?带着这些问题,InfoQ对阿里云的数据库专家兼Postgres中国社区/中国用户会主席萧少聪先生进行了采访,以下文 ...

  10. 树堆(Treap)

    平衡树 简介: 平衡二叉树(Balanced Binary Tree)具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树.平衡二叉树的常用实现方 ...