本文将使用链表来实现栈结构,如果你对链表还不熟悉,建议先看我的上一篇文章LinkedList源码解析(手把手带你熟悉链表) 有对链表的讲解,本文将不再讲解链表
栈是一种先进后出的数据结构,可以理解为一个容器,最先进入的数据在最底部,新数据会一层层累加在旧数据的顶部,而取数据的时候先从顶部开始取,所以取出来的数据肯定是最后添加的数据
生活中的小例子: 每次洗完碗,把碗一个一个摞在一起,当下次使用的时候,拿的第一个碗肯定是最顶部的,也就是最后一个洗完的碗
String[] arr = {"A","B","C","D","E"}
假如我们要把这个数组添加到栈,那么
进栈的顺序应该是:
A->进栈
B->进栈
C->进栈
D->进栈
E->进栈
出栈的顺序应该是:
E->出栈
D->出栈
C->出栈
B->出栈
A->出栈
下面我们将使用单链表来实现栈结构
private class Node {
public T item;
public Node next;
public Node(T item, Node next) {
this.item = item;
this.next = next;
}
}
成员变量:
headNode: 用为记录头结点
size: 用来记录链表长度
构造方法:
由于使用单链表,所以在构造方法的时候,需要先创建一个头结点
public class MyStack {
//记录头结点
private Node headNode;
//链表长度
private int size;
/**
* 构造方法中初始化头结点
*/
public MyStack() {
this.headNode = new Node(null, null);
}
/**
* 节点实体类
*/
private class Node {
public T item;
public Node next;
public Node(T item, Node next) {
this.item = item;
this.next = next;
}
}
}
数据进栈有两种情况:
- 链表为空 直接添加到头结点后面
- 链表有数据 断开头结点与头结点后面的节点,并插入中间重新建立连接
先看链表为空的情况:
链表有数据的情况:
插入之后:
代码实现:
/**
* 数据进栈
*/
public T push(T value) {
//先拿到头结点
Node headNode = this.headNode;
//创建一个新的节点存储数据
Node newNode = new Node(value, null);
//判断链表是否为空
if (isEmpty()) {
//如果链表为空,数据直接添加在头结点后面
headNode.next = newNode;
} else {
//如果链表不为空,先获取到头节点的下一个节点(老节点)
//然后插入到两个节点之间
Node oldNode = headNode.next;
//头结点的下一个节点指向新节点
headNode.next = newNode;
//新节点的下一个节点指向老节点
newNode.next = oldNode;
}
size++;
return value;
}
- 数据出栈每次最先弹出的是最前(上)面的数据
- 数据出栈需要删除该节点,并重新建立头结点与当前节点的下一个节点的连接
代码实现:
/**
* 数据出栈
*/
public T pop() {
//判断链表是否为空
if (isEmpty()) {
return null;
}
//获取头结点的下一个节点
Node currentNode = this.headNode.next;
//将准备弹出的节点断开连接
this.headNode.next = currentNode.next;
size--;
return currentNode.item;
}
栈作为一种数据结构,它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
package test;
import java.util.Iterator;
/**
* 自定义栈结构
*/
public class MyStack<T> implements Iterable<T> {
//记录头结点
private Node headNode;
//链表长度
private int size;
/**
* 构造方法中初始化头结点
*/
public MyStack() {
this.headNode = new Node(null, null);
}
/**
* 数据进栈
*/
public T push(T value) {
//先拿到头结点
Node headNode = this.headNode;
//创建一个新的节点存储数据
Node newNode = new Node(value, null);
//判断链表是否为空
if (isEmpty()) {
//如果链表为空,数据直接添加在头结点后面
headNode.next = newNode;
} else {
//如果链表不为空,先获取到头节点的下一个节点(老节点)
//然后插入到两个节点之间
Node oldNode = headNode.next;
//头结点的下一个节点指向新节点
headNode.next = newNode;
//新节点的下一个节点指向老节点
newNode.next = oldNode;
}
size++;
return value;
}
/**
* 数据出栈
*/
public T pop() {
//判断链表是否为空
if (isEmpty()) {
return null;
}
//获取头结点的下一个节点
Node currentNode = this.headNode.next;
//将准备弹出的节点断开连接
this.headNode.next = currentNode.next;
size--;
return currentNode.item;
}
/**
* 判断当前是否为空链表
*/
public boolean isEmpty() {
if (size == 0 || headNode == null || headNode.next == null) {
return true;
}
return false;
}
public int getSize() {
return size;
}
@Override
public Iterator<T> iterator() {
return new Iterator<T>() {
Node currentNode = headNode;
@Override
public boolean hasNext() {
return currentNode.next != null;
}
@Override
public T next() {
currentNode = currentNode.next;
return currentNode.item;
}
};
}
private class Node {
public T item;
public Node next;
public Node(T item, Node next) {
this.item = item;
this.next = next;
}
}
}