数据结构——栈的快速入门

栈的介绍

  1. 栈是一个先入后出(FILO-First In Last Out)的有序列表。

  2. 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一 端,称为栈底(Bottom)。

  3. 根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈项,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除

  4. 图解方式说明出栈(pop)和入栈(push)

image-20230117181009950

应用场景

1) 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。
2) 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
3) 表达式的转换[中缀表达式转后缀表达式]与求值(实际解决)。
4) 二叉树的遍历。
5) 图形的深度优先(depth—first)搜索法。

栈的代码实现

数组模拟栈

分析:

image-20230117181553142

  1. 使用数组模拟栈

  2. 定义一个变量为top来表示栈顶,初始化为-1

  3. 入栈的操作,当有数据加入到栈时,top++,stack[top]=data;

  4. 出栈的操作,int value=stack[top]; top—; return value;

实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//定义一个ArrayStack表示栈
class ArrayStack{
private int maxSize; //栈的大小
private int[] stack; // 用数组模拟栈,数据就放到该数组中
private int top = -1; //top表示栈顶,初始化为-1

//构造器
public ArrayStack ( int maxSize ) {
this.maxSize = maxSize;
stack = new int[ this.maxSize ];
}

//栈满
public boolean isFull(){
return top == maxSize - 1;
}
//栈空
public boolean isEmpty(){
return top == -1;
}

//入栈——push
public void push ( int value ) {
//先判断栈是否满
if ( isFull ( ) ) {
System.out.println ( "栈满" );
return;
}
top++;
stack[ top ] = value;
}

//出栈——pop,将栈顶数据返回
public int pop ( ) {
if ( isEmpty ( ) ) {
//抛出异常
throw new RuntimeException ( "栈空,没有数据" ); //运行异常
}
int value = stack[ top ];
top--;
return value;
}

//遍历栈,遍历时从栈顶到栈底
public void list ( ) {
if ( isEmpty ( ) ) {
System.out.println ("栈空没有数据~" );
return;
}
for ( int i = top ; i >= 0 ; i-- ) {
System.out.printf ( "stack[%d]=%d\n",i,stack[i]);
}
}


}
测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class ArrayStackDemo {
public static void main ( String[] args ) {
//测试一下ArrayStack是否正确
//先创建一个ArrayStack
ArrayStack stack = new ArrayStack ( 4 );
String key = "";
boolean loop = true; //控制是否退出菜单
Scanner sc = new Scanner ( System.in );

while (loop) {
System.out.println ("show,表示显示菜单" );
System.out.println ("exit,表示退出菜单" );
System.out.println ("push,表示添加数据到菜单(入栈)" );
System.out.println ("pop,表示从栈中取出数据(出栈)" );
System.out.println ( "请输入你的选择" );
key = sc.next ( );
switch (key){
case "show":
stack.list ();
break;
case "exit":
sc.close ();
loop = false;
break;
case "push":
System.out.println ( "请输入一个数" );
int value = sc.nextInt ( );
stack.push ( value );
break;
case "pop":
try {
int res = stack.pop ( );
System.out.printf ( "出栈的数据是%d\n", res );
} catch (Exception e) {
System.out.println ( e.getMessage ());
}
break;
}
}
System.out.println ("程序退出" );
}
}

链表模拟栈

  1. 使用双链表

  2. 定义一个top表示栈顶,初始值为-1;

  3. 入栈的操作,当有数据加入到栈时,弄一个辅助节点,temp=top,temp.next指向新节点;heroNode.pre = temp;top=heroNode

  4. 出栈的操作。当出栈时,top的节点出去,辅助节点temp=top;temp.pre.next=null; top=temp.pre; temp.pre=null;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//创建一个双向链表的类
class DoubleLinkList {
private int maxSize;
private HeroNode3 top =new HeroNode3(-1,null);
private int n;

private HeroNode3 head = new HeroNode3 ( 0, "" );


//构造器
public DoubleLinkList ( int maxSize ) {
this.maxSize = maxSize;
}

//栈满
public boolean isFull(){
return top.no == maxSize - 1;
}
//栈空
public boolean isEmpty(){
return top.no == -1;
}

//遍历双向链表
//显示链表遍历
public void list ( ) {
//判断链表是否为空
if ( isEmpty ()) {
System.out.println ( "栈空没有数据" );
return;
}
//因为头节点,不能动,因此我们需要一个辅助变量来遍历
HeroNode3 temp = top;
while (true) {
//判断是否到链表最后
if ( temp.no==-1 ) {
break;
}
//输出节点的信息
System.out.println ( temp );
//将temp后移
temp = temp.pre;

}

}
public void push ( String value ) {
//先判断栈是否满
if ( isFull ( ) ) {
System.out.println ( "栈满" );
return;
}
HeroNode3 heroNode = new HeroNode3 ( n++, value );
HeroNode3 temp = top;

temp.next = heroNode;
heroNode.pre = temp;
top=heroNode;
}

public HeroNode3 pop ( ) {
if ( isEmpty ( ) ) {
//抛出异常
throw new RuntimeException ( "栈空,没有数据" ); //运行异常
}
n--;
HeroNode3 temp=top;
temp.pre.next=null;
top = temp.pre;
temp.pre = null;
return temp;
}



}


//定义一个heroNode,每个HeroNode 对象是一个节点
class HeroNode3 {
public int no;
public String value;
public HeroNode3 next; //指向后一个节点 默认为null
public HeroNode3 pre; //指向前一个节点 默认为null

//构造器
public HeroNode3 ( int no, String value ) {
this.no = no;
this.value = value;
}

//为了显示方便,我们重写toString
@Override
public String toString ( ) {
return "HeroNode3 [no=" + no + ",value=" + value + "]";
}
}
测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class DoubleListStackDemo {
public static void main ( String[] args ) {
DoubleLinkList stack = new DoubleLinkList ( 5 );
String key = "";
boolean loop = true; //控制是否退出菜单
Scanner sc = new Scanner ( System.in );

while (loop) {
System.out.println ("show,表示显示菜单" );
System.out.println ("exit,表示退出菜单" );
System.out.println ("push,表示添加数据到菜单(入栈)" );
System.out.println ("pop,表示从栈中取出数据(出栈)" );
System.out.println ( "请输入你的选择" );
key = sc.next ( );
switch (key){
case "show":
stack.list ();
break;
case "exit":
sc.close ();
loop = false;
break;
case "push":
System.out.println ( "请输入一个值" );
String value = sc.next ( );
stack.push ( value );
break;
case "pop":
try {
HeroNode3 res = stack.pop ( );
System.out.printf ( "出栈的数据是%s\n", res.value );
} catch (Exception e) {
System.out.println ( e.getMessage ());
}
break;
}
}
System.out.println ("程序退出" );

}
}