数据结构-栈和队列
- 2.1栈
- 2.1.1栈的表示和实现
- 2.1.2栈的应用举例
- 数制转换
- 括号匹配检验
- 迷宫给求解
- 表达式求值
2.1栈
栈是限定仅在表尾进行插入或删除操作的线性表,因此,对栈来说,表尾端有其特殊含义,称为栈顶(top),相应地,表头称为栈底。
E为栈底元素,A为栈顶元素。也就意味着,栈的修改是按后进先出的原则进行的。因此栈又称为后进先出线性表(简称LIFO结构)。
2.1.1栈的表示和实现
和线性表类似,栈也有两种存储表示方式。
顺序栈,即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置。通常的习惯做法是top=0表示空栈,鉴于C语言中数组的下标约定从0开始,则当以C作描述语言时,如设定会带来很大不便;另一方面,由于栈在使用过程中所需最大空间的大小很难估计,一般来说,在初始化设空栈时不应限定栈的最大容量。一个较合理的做法是;先分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐段扩大。为此可设定两个常量:STACK_INIT_SIZE(存储空间初始分配量)和STACKINCREMENT(存储空间分配增量)。
top 并不是栈顶元素,而是指向栈顶元素的下一个位置。
top - 1 才是真正的栈顶元素位置。
typedef struct{
SElemType *base; //栈底指针
SElemType *top; //栈顶指针,其初值指向栈底
int stacksize; //栈当前可使用的最大容量
//每当插入心得栈顶元素时,指针top+1
};
顺序栈所有操作汇总:
#include<stdio.h>
#include<stdlib.h>
#define SElemType int
#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量
#define Status int
typedef struct{
SElemType *base;
SElemType *top;
int stacksize;
} SqStack;
Status InitStack (SqStack &S){
//构造一个空栈
S.base = (SElemType *) malloc(STACK_INIT_SIZE * sizeof(SElemType));
if(!S.base) exit(0); //存储分配失败
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return 1;
}
Status Push(SqStack &S, SElemType e){
//插入元素e为新的栈顶元素
if(S.top - S.base >= S.stacksize){ //栈满.追加存储空间
S.base = (SElemType *) realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(SElemType));
if(!S.base) exit(0); //存储分配失败
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top++ = e;
return 1;
}
Status Pop(SqStack &S, SElemType &e){
//若栈不为空,则删除S的栈顶元素,用e返回其值
if(S.top == S.base) return 0; //空栈
e = * --S.top; //先将S.top赋值给e,再自减
return 1;
}
Status GetTop(SqStack &S, SElemType &e){
//若栈不为空,则用e返回S的栈顶元素
if(S.top == S.base) return 0;
e = *(S.top - 1);
return 1;
}
int StackLength(SqStack &S){
//返回栈的元素个数,即栈的长度
return S.top - S.base;
}
int StackEmpty(SqStack &S){
//返回栈是否为空,为空返回0,不为空返回1
if(!StackLength(S)) return 0;
return 1;
}
void ClearStack(SqStack &S){
//把S置为空栈
S.top = S.base;
}
void DestroyStack(SqStack &S){
//销毁栈
if(S.base){
free(S.base);
S.base = S.top = NULL;
S.stacksize = 0;
}
}
int main()
{
SqStack S;
InitStack(S);
Push(S, 1);
Push(S, 2);
int e;
Pop(S, e);
printf("%d\n", e);
GetTop(S, e);
printf("%d\n", e);
int l = StackLength(S);
printf("length: %d\n", l);
return 0;
}
2.1.2栈的应用举例
数制转换
将十进制数N和其他d进制数的转换。算法原理如下:
N
=
(
N
/
d
)
∗
d
+
N
m
o
d
d
N = (N/d)*d+N \ \ mod \ \ d
N=(N/d)∗d+N mod d
要求: 对于输入的任意一个非负十进制整数,打印与其等值的八进制数。
//栈的操作与2.1.1中代码相同
int main()
{
SqStack S;
InitStack(S);
printf("请输入一个非负的十进制数: ");
int numT;
scanf("%d", &numT);
while(numT){
Push(S, numT % 8);
numT /= 8;
}
int e;
while(StackEmpty(S)){
Pop(S, e);
printf("%d", e);
}
return 0;
}
括号匹配检验
假设表达式中允许包含两种括号:圆括号和方括号,其嵌套顺序随意,即()为正确格式,[{]为不正确格式。
要求: 输入只含圆括号和方括号的字符串,判断其是否是正确的格式。
//要加上#include<string.h>
int main()
{
SqStack S;
InitStack(S);
char str[100];
printf("输入只含圆括号和方括号的字符串: ");
scanf("%s", str);
int length = strlen(str), i, flag = 1, e;
//(为1, )为2, [为3, ]为4
for(i = 0; i < length; i ++){
if(str[i] == '[') Push(S, 3);
if(str[i] == '(') Push(S, 1);
if(str[i] == ')') {
GetTop(S, e);
if(e == 1) Pop(S, e);
}
if(str[i] == ']') {
GetTop(S, e);
if(e == 3) Pop(S, e);
}
}
if(!StackEmpty(S)) printf("%s是合法字符串\n", str);
else printf("%s不是合法字符串\n", str);
return 0;
}
迷宫给求解
链接: C语言 严蔚敏 数据结构 迷宫求解_顺序栈应用
类似于深度优先搜索,用栈去模拟这个过程。
表达式求值
链接: C语言 严蔚敏 数据结构 表达式求值_顺序栈应用
类似于括号匹配检验。