1. 应用场景
- 程序的调用:程序指令的地址储存在堆栈内,每执行一个程序,就先放入栈中,执行完当前程序就从栈内取出下一个执行。
- 递归调用的处理:除了存程序指令地址,还存参数、区域变量等。
- 表达式转换和求值:如 “中缀 -> 后缀”
- 二叉树的遍历
- 图的深度优先算法(DFS)
2. 特点
- 结构:线性结构
- 栈顶(top) :栈的顶部,出栈入栈的出入口
- 栈底(bottom):栈的底部,最先入栈和最后出栈的位置
- 专有名词:
- 出栈(pop):从 栈顶 取出
- 入栈(push):从 栈顶 放入
- 先进后出 (FILO - First In Last Out) : 先入栈的后出栈。
- 优点:没有长度限制
3. 数据结构(类结构)
【节点 DoubleNode】
(1)成员变量(Field)
- data: int,节点所储存的数据
- nextNode: Node,所指向的下一个节点
- preNode: Node,所指向的上一个节点
private int data;
private DoubleNode nextNode;
private DoubleNode preNode;
(2)初始化 / 构造器(Constructor)
- 参数传入节点所要储存的数据
- 初始化节点数据
public DoubleNode(int data) {
this.data = data;
}
(3)方法(Methods)
- 三个成员变量的getter和setter
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public DoubleNode getNextNode() {
return nextNode;
}
public void setNextNode(DoubleNode nextNode) {
this.nextNode = nextNode;
}
public DoubleNode getPreNode() {
return preNode;
}
public void setPreNode(DoubleNode preNode) {
this.preNode = preNode;
}
- toString方法
@Override
public String toString() {
return "DoubleNode{" +
"data=" + data +
'}';
}
【栈 Stack】
(1)成员变量(Field)
- topNode: DoubleNode,指向栈顶节点
private DoubleNode topNode;
(2)初始化 / 构造器(Constructor)
- 默认构造器
(3)方法(Methods)
- 判断栈是否为空
isEmpty() ->boolean
/**
* 判断栈是否为空
* @return - true 为空,false 非空
*/
public boolean isEmpty() {
// 栈顶节点为null,栈为空
return topNode == null;
}
- 添加数据到栈(入栈)
push(int) -> void
/**
* 入栈:从栈顶添加数据
* @param data - 要添加的数据
*/
public void push(int data) {
// 1,设置新节点,节点值为data
DoubleNode newNode = new DoubleNode(data);
// 2,添加新节点:若topNode不为null,添加到topNode后面
if (this.topNode != null) {
this.topNode.setNextNode(newNode);
newNode.setPreNode(this.topNode);
}
// 3,将topNode指向新节点
this.topNode = newNode;
}
- 从栈内取出数据(出栈)
pop() -> int
/**
* 出栈:从栈顶取出数据
* @return - 返回栈顶节点值
*/
public int pop() {
// 1,栈顶节点为空,抛出异常
if (this.topNode == null) {
throw new RuntimeException("empty");
}
// 2,取出栈顶的数据,存入临时int变量
int data = this.topNode.getData();
// 3,删除当前栈顶的节点
DoubleNode tempNode = this.topNode.getPreNode();
if (tempNode != null) {
tempNode.setNextNode(null);
}
this.topNode = tempNode;
// 4,返回数据
return data;
}
- 获取栈的有效数据数目
getLength() -> int
/**
* 获取栈长
* @return - 栈内有效节点数
*/
public int getLength() {
// 1,设置临时int变量,存储计数
int count = 0;
// 2,设置节点变量,指向当前变量
DoubleNode currentNode = this.topNode;
// 3,遍历,逐个计数,当前节点为null时停止
while (currentNode != null) {
count++;
currentNode = currentNode.getPreNode();
}
// 4,返回计数
return count;
}
4. 完整实现
/**
* 双向链表实现栈
* @author hoy
*/
public class DoubleLinkedListStackPractice {
private DoubleNode topNode;
/**
* 判断栈是否为空
* @return - true 为空,false 非空
*/
public boolean isEmpty() {
// 栈顶节点为null,栈为空
return topNode == null;
}
/**
* 入栈:从栈顶添加数据
* @param data - 要添加的数据
*/
public void push(int data) {
// 1,设置新节点,节点值为data
DoubleNode newNode = new DoubleNode(data);
// 2,添加新节点:若topNode不为null,添加到topNode后面
if (this.topNode != null) {
this.topNode.setNextNode(newNode);
newNode.setPreNode(this.topNode);
}
// 3,将topNode指向新节点
this.topNode = newNode;
}
/**
* 出栈:从栈顶取出数据
* @return - 返回栈顶节点值
*/
public int pop() {
// 1,栈顶节点为空,抛出异常
if (this.topNode == null) {
throw new RuntimeException("empty");
}
// 2,取出栈顶的数据,存入临时int变量
int data = this.topNode.getData();
// 3,删除当前栈顶的节点
DoubleNode tempNode = this.topNode.getPreNode();
if (tempNode != null) {
tempNode.setNextNode(null);
}
this.topNode = tempNode;
// 4,返回数据
return data;
}
/**
* 获取栈长
* @return - 栈内有效节点数
*/
public int getLength() {
// 1,设置临时int变量,存储计数
int count = 0;
// 2,设置节点变量,指向当前变量
DoubleNode currentNode = this.topNode;
// 3,遍历,逐个计数,当前节点为null时停止
while (currentNode != null) {
count++;
currentNode = currentNode.getPreNode();
}
// 4,返回计数
return count;
}
/**
* 从栈顶开始打印全部节点值
*/
public void displayAllDataFromTop() {
// 1,栈顶节点为空,抛出异常
if (this.topNode == null) {
throw new RuntimeException("empty");
}
// 2,设置节点变量,指向当前变量
DoubleNode currentNode = this.topNode;
// 3,遍历,逐个打印,当前节点为null时停止
while (currentNode != null) {
System.out.println(currentNode.toString());
currentNode = currentNode.getPreNode();
}
}
}
class DoubleNode {
private int data;
private DoubleNode nextNode;
private DoubleNode preNode;
public DoubleNode(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public DoubleNode getNextNode() {
return nextNode;
}
public void setNextNode(DoubleNode nextNode) {
this.nextNode = nextNode;
}
public DoubleNode getPreNode() {
return preNode;
}
public void setPreNode(DoubleNode preNode) {
this.preNode = preNode;
}
@Override
public String toString() {
return "DoubleNode{" +
"data=" + data +
'}';
}
}