栈结构
什么是栈结构
栈结构是从数据的运算来分类的,也就是说栈结构具有特殊的运算规则。而从数据的逻辑结构来看,栈结构其实就是线性结构。 如果从数据的存储结构来进一步划分, 栈结构包括两类。
- 顺序栈结构:即使用一组地址连续的内存单元依次保存栈中的数据。在程序中,可以定义一个指定大小的结构数组来作为栈,序号为0的元素就是栈底,再定义一个变量top保存栈顶的的序号即可。
- 链式栈结构:即使用链表形式保存栈中各元素的值。链表首部(head引用所指向元素)为栈顶,链表尾部(指向地址为null)为栈底。
典型的栈结构,如图所示。从图中可以看出,在栈结构中只能在一端进行操作, 该操作端称为栈顶,另一端称为栈底。 也就是说,保存和取出数据都只能从栈结构的一端进行。 从数据的运算角度来分析,栈结构是按照“后进先出”(Last In First Out, LIFO) 的原则处理结点数据的。
一般栈结构的基本操作有两个:
- 入栈(Push):将数据保存到栈项的操作。进行入栈操作前,先修改栈项引用。使其向上移一个元素位置。通过修改栈顶引用,使其向上移一个元素位置,然后将数据保存到栈顶引用所指的位置
- 出栈(Pop):将栈顶的数据弹出的操作。通过修改栈项引用,使其指向栈中的下一个元素。
接下来,了解如何在Java语言中建立顺序栈,并完成顺序栈结构的基本操作
1. 准备数据
class DATA3{
String name;
int age;
}
class StackType{
static final int MAXLEN=50;
DATA3[] data=new DATA3[MAXLEN+1];
int top;
}
在类StackType中,data 为数据元素,top 为栈顶的序号。当top=0时表示栈为空,top=SIZE时表示栈满。
Java语言中数组都是从下标0开始的。在这里,为了讲述和理解的方便,从下标1开始记录据结点,下标0的位置不使用。
2.初始化栈结构
在使用顺序栈之前,首先要创建个空的顺序栈, 即初始化顺序栈。 顺序栈的初始化操作步如下:
(1)按符号常量SIZE指定的大小申请一片内存空间, 用来保存栈中的数据。
(2)设置栈项引用的值为0,表示一个空栈。
初始化顺序栈的代码示例如下:
StackType STInit() {
StackType p;
p = new StackType();
if (p != null) {
p.top = 0;
return p;
}
return null;
}
3.判断空栈
判断栈是否为空,为空则不可以进行出栈操作,可以进行入栈操作
boolean STIsEmpty(StackType s){
boolean t;
t=(s.top==0);
return t;
}
4.判断满栈
如果是满栈,表示该栈中没有多余的空间来保存额外的数据,此时不可进行入栈操作,但可以进行出栈操作
boolean STIsFull(StackType s) {
boolean t;
t = (s.top == MAXLEN);
return t;
}
5.清空栈
void STClear(StackType s) {
s.top = 0;
}
6.释放空间
释放空间即释放栈结构所占用的内存单元。在初始化栈结构时,使用了malloc函数分配内存空间。虽然可以使用清空栈操作,但是清空栈操作并没有释放内存空间,这里就需要使用free函数释放所分配的内存
void STFree(StackType s) {
if (s != null) {
s = null;
}
}
7.入栈
入栈(Push)是栈结构的基本操作,主要操作时将数据元素保存到栈结构中。入栈操作的具体步骤如下:
1. 首先判断栈顶top,如果top大于等于SIZE,则表示溢出,进行出错处理;否则执行以下操作;
2. 设置top=top+1(栈顶引用加1,指向入栈地址);
3. 将入栈元素保存到top指向的位置;
入栈
操作示例代码:
int PushST(StackType s, DATA3 data) {
if (s.top + 1 > MAXLEN) {
System.out.println("栈溢出!");
return 0;
}
s.data[++s.top] = data;
return 1;
}
8.出栈
出栈(Pop)是栈结构的基本操作,主要操作域入栈相反,其操作是从栈顶弹出一个数据元素。出栈操作的具体步骤如下:
1. 首先判断栈顶top,如果top等于0,则表示为空栈,进行出错处理;否则执行以下操作;
2. 将栈顶引用top所指位置的元素返回;
3. 设置top=top-1,也就是是栈顶引用减1,指向栈的下一元素的地址,原来的栈顶元素被弹出;
出栈操作示例代码:
DATA3 PopST(StackType s) {
if (s.top == 0) {
System.out.println("栈为空!");
System.exit(0);
}
return (s.data[s.top--]);
}
返回值是栈顶的数据元素
9.栈操作的演示实例
import java.util.Scanner;
class DATA3 {
String name;
int age;
}
class StackType {
static final int MAXLEN = 50;
DATA3[] data = new DATA3[MAXLEN + 1];
int top;
StackType STInit() {
StackType p;
p = new StackType();
if (p != null) {
p.top = 0;
return p;
}
return null;
}
boolean STIsEmpty(StackType s) {
boolean t;
t = (s.top == 0);
return t;
}
boolean STIsFull(StackType s) {
boolean t;
t = (s.top == MAXLEN);
return t;
}
void STClear(StackType s) {
s.top = 0;
}
void STFree(StackType s) {
if (s != null) {
s = null;
}
}
int PushST(StackType s, DATA3 data) {
if (s.top + 1 > MAXLEN) {
System.out.println("栈溢出!");
return 0;
}
s.data[++s.top] = data;
return 1;
}
DATA3 PopST(StackType s) {
if (s.top == 0) {
System.out.println("栈为空!");
System.exit(0);
}
return (s.data[s.top--]);
}
}
public class Stack {
public static void main(String[] args) {
StackType st = new StackType();
DATA3 data1 = new DATA3();
StackType stack = st.STInit();
Scanner input = new Scanner(System.in);
System.out.println("入栈操作:");
System.out.println("输入姓名 年龄进行入栈操作:");
do {
DATA3 data = new DATA3();
data.name = input.next();
if (data.name.equals("0")) {
break;
} else {
data.age = input.nextInt();
st.PushST(stack, data);
}
} while (true);
String temp = "1";
System.out.println("出栈操作:按任意非0键进行出栈操作:");
temp = input.next();
while (!temp.equals("0")) {
data1 = st.PopST(stack);
System.out.println("出栈的数据是" + data1.name + " " + data1.age);
temp = input.next();
}
System.out.println("测试结束!");
//释放栈所占用的空间
st.STFree(st);
}
}