栈
(1)栈是一个先入后出(Filo-Frist In last out)的有序列表
(2)栈是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(top),另一端为固定的一端,称为栈底(bottom)
(3)根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除
数组结构栈
- 使用数组结构栈,需要实例化数组,且传入数组的大小(即最大栈空间)
- 需要一个maxSize初始化栈的最大空间,构造器时传入该值
- 还需要一个top变量记录栈顶,默认的初始化值为-1
- 因为是数组结构,所以需要判断栈是否为空的方法boolean isEmpty(){}
- 判断栈是否已满的方法boolean isFall(){}
- 入栈::void push(Tree value){}
- 出栈::Tree pop(){}
- 遍历栈中内容::void showStack(){}
数组栈流程图
代码
public class StackTest {
public static void main(String[] args) {
//创建数组栈
ArrayStack arrayStack = new ArrayStack(5);
//入栈
arrayStack.push(new Tree(1));
//输出栈
arrayStack.showStack();
//出栈
arrayStack.pop();
arrayStack.showStack();
}
}
class ArrayStack {
//最大栈空间
public int maxSize;
//栈顶
public int top = -1;
//栈数组
public Tree[] stack;
//构造器
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
//初始化栈数组
stack = new Tree[this.maxSize];
}
//判断栈是否满
public boolean isFall() {
return top == this.maxSize - 1;
}
//判断栈是否空
public boolean isEmpty() {
return top == -1;
}
//入栈
public void push(Tree value) {
if (isFall()) {
System.out.println("栈满!");
return;
}
//先自身加 1
stack[++top] = value;
}
//出栈
public Tree pop() {
if (isEmpty()) {
throw new RuntimeException("栈为空!");
}
Tree value = stack[top];//接收到值之后
top--;//top--
return value;
}
//循环遍历栈
public void showStack() {
if (isEmpty()) {
System.out.println("栈为空!");
return;
}
for (int i = top; i >= 0 ; i--) {
System.out.println("stack["+i+"]"+ stack[i]);
}
}
}
//创建树类
class Tree {
private int no;
public Tree(int no) {
this.no = no;
}
@Override
public String toString() {
return "Tree{" +
"no=" + no +
'}';
}
}
控制台
stack[0]Tree{no=1}
栈为空!
链表结构栈
向链表头push数据
- 创建链表栈需要Tree结构维护一个指向属性Tree next;
- 链表栈不需要指针(top)之类的属性进行记录
- 链表栈没有长度限制,不需要进行扩容
- 向链表头push数据,更简单,push(入栈)和pop(出栈)不需要进行循环操作,性能最好
- 输出数据时,向链表头push数据跟向链表尾push数据,数据顺序是相反的
链表栈流程图
链表栈代码
public class 优快云LinkedStack {
public static void main(String[] args) {
//创建链表栈
LinkedStack linkedStack = new LinkedStack();
//入栈
linkedStack.push(new Tree(1));
linkedStack.push(new Tree(2));
linkedStack.push(new Tree(3));
//显示栈中数据
linkedStack.showLinkedStack();
//出栈
System.out.println("*******出栈*******");
System.out.println(linkedStack.pop());
System.out.println("*******出栈后*******");
linkedStack.showLinkedStack();
}
}
class LinkedStack {
//维护一个头节点
public Tree head = new Tree(0);
//入栈
public void push(Tree tree) {
//保存head的下一个节点
Tree next = head.next;//头节点的下一个节点,如果是第一次便是空,第二次就不是空了
//给头节。next点赋值
head.next = tree;
//然后把之间的链接起来
tree.next = next;
}
//出栈
public Tree pop() {
if (head.next == null) {
throw new RuntimeException("栈为空!");
}
//保存一个节点
Tree cur = head.next;
/*
* 将头节点的下一个指针指向头节点的下一个的下一个
* 这样就完成了最简单的删除操作
* */
head.next = head.next.next;//自我删除
return cur;
}
//循环显示
public void showLinkedStack() {
if (head.next == null) {
System.out.println("栈空!");
return;
}
//维护指针
Tree temp = head.next;
while (temp != null) {
System.out.println(temp);
temp = temp.next;//指针后移
}
}
}
//创建树类
class Tree {
public int no;
public Tree next;//保存指向的下一个Tree
//构造器
public Tree(int no) {
this.no = no;
}
@Override
public String toString() {
return "Tree{" +
"no=" + no +
'}';
}
}
向链表尾push数据
- 向链表尾添加数据和删除数据比较麻烦,都需要循环操作,效率低
- 由于是向链表尾添加数据,循环输出时是按照加入的顺序进行输出
流程图
代码
public class 优快云LinkedStack2 {
public static void main(String[] args) {
//创建链表栈
LinkedStack linkedStack = new LinkedStack();
//入栈
linkedStack.push(new Tree(1));
linkedStack.push(new Tree(2));
linkedStack.push(new Tree(3));
//显示栈中数据
linkedStack.showLinkedStack();
//出栈
System.out.println("*******出栈*******");
System.out.println(linkedStack.pop());
System.out.println("*******出栈后*******");
linkedStack.showLinkedStack();
}
}
class LinkedStack {
//维护一个头节点
public Tree head = new Tree(0);
//入栈
public void push(Tree tree) {
//维护一个辅助指针
Tree temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = tree;//入栈
}
//出栈
public Tree pop() {
if (head.next == null) {
System.out.println("栈为空!");
return null;
}
//维护一个辅助指针
Tree temp = head;
//temp.next.next找到当前节点的后一个节点的后一个节点为空的
while (temp.next.next != null) {//如果temp.next.next不等于空,就接着找下一个
temp = temp.next;//指针后移
}
//将需要pop的变量保存起来
Tree temp1 = temp.next;
//置空
temp.next = null;
return temp1;//返回
}
//显示栈
public void showLinkedStack() {
if (head.next == null) {
System.out.println("空!");
return;
}
//维护指针
Tree temp = head.next;
while (temp != null) {
System.out.println(temp);
temp = temp.next;
}
}
}
//创建树类
class Tree {
public int no;
public Tree next;//保存指向的下一个Tree
//构造器
public Tree(int no) {
this.no = no;
}
@Override
public String toString() {
return "Tree{" +
"no=" + no +
'}';
}
}
控制台
Tree{no=1}
Tree{no=2}
Tree{no=3}
*******出栈*******
Tree{no=3}
*******出栈后*******
Tree{no=1}
Tree{no=2}
总结
- 数组结构栈:结构比较容易理解,缺点是如果栈的大小不合适需要进行扩容
- 链表结构栈,向链表头push数据:不需要进行扩容操作,且出栈和入栈都不需要进行循环,效率高
- 链表结构栈,向链表尾push数据:不需要进行扩容,但是出栈和入栈都需要进行循环,效率低,不推荐
PS:如果有错误请指正
END