(自复习用的笔记,参考严老师的数据结构c语言版)
栈(LIFO)
知识点
ADT
参照教材,有9个基本操作
- InitStack
- DestroyStack
- ClearStack (注意栈的**空状态**以及**不存在**状态)
- StackEmpty
- GetTop
- Push
- Pop
- StackTraverse
栈的表示及实现
-
顺序存储
当设置base恒指向栈底时- 设置栈底指针base始终指向栈底与栈顶指针top(当入栈时++,出栈时--),则top始终指向栈顶元素的下一个位置(top->next为栈顶元素)。 - 栈空时,top=base;栈结构不存在时,base=NULL; - top->next为栈顶结点 - 初始容量、储存空间分配增量 - 多个栈共用一个静态存储空间则有对整个栈的操作
当不设置base而数组[0]不放置元素时
- 此时top指向即栈顶元素 - 最大容量为数组长度-1 - 栈空时top=0
typedef struct{
SElemType *base; //栈构造前和销毁后,base的值为NULL;
SElemType *top;
int stacksize; //当前已分配的存储空间
}SqStack;
-
链式存储
- 显然栈顶元素作为表头对其插入、删除操作均较为方便。
链式代码实现
注意注释
# include<stdio.h>
# include<stdlib.h>
//增强可读性!nice!学到了!
# define TRUE 1
# define OK 1
# define FALSE 0
# define ERROR 0
/*结点定义*/
typedef int ElemType;
typedef int Status;
typedef struct NODE
{
ElemType *elem;
struct NODE *next;
}NODE;
typedef NODE* STACK;
/***************************************************函数声明************************************************************/
STACK CreateStack();
void DestroyStack(STACK S);
void ClearStack(STACK S);
Status StackEmpty(STACK S);
int StackLength(STACK S);
NODE* GetTop(STACK S);
STACK Push(STACK S, ElemType* e);
ElemType* Pop(STACK S);
Status StackTraverse(STACK S);
void StackVisit(NODE* p);
/***************************************************函数定义************************************************************/
//构造空栈,返回base
STACK CreateStack()
{
NODE *base, *top;
base = (NODE*)malloc(sizeof(NODE));
base->next = NULL; // 注意初始化设为NULL
top = base;
return base;
}
//销毁栈
void DestroyStack(STACK S)
{
if (S != NULL)
{
ClearStack(S);
free(S);
}
else
printf("Error!Can`t destroy a NULL STACK!");
}
//清空栈
void ClearStack(STACK S)
{
NODE *p;
if (S != NULL)
{
p = S->next;
while (p->next != NULL)
{
free(S);
S = p;
p = p->next;
}
free(S);
S = p;
}
else
printf("Error!Can`t clear a NULL stack!");
}
//判断是否为空栈
Status StackEmpty(STACK S)
{
if (S)
{
if (S->next == NULL)
return TRUE;
return FALSE;
}
fprintf(stderr, "ERROR!The stack doesn't exist!");
return ERROR; //学会用宏定义增加代码可读性
}
//返回栈长
int StackLength(STACK S)
{
int len = 0;
if (S)
{
while (S->next != NULL)
{
len++;
S = S->next;
}
return len;
}
fprintf(stderr, "ERROR!The stack doesn't exist!");
return -1;
}
//返回栈顶元素
NODE* GetTop(STACK S)
{
if (S)
{
if (S->next)
{
return S;
}
printf("The stack is empty!");
return NULL;
}
fprintf(stderr, "ERROR!The stack soesn't exist!");
return NULL;
}
//插入元素作为新栈顶
STACK Push(STACK S, ElemType* e)
{
NODE* p;
p = (NODE*)malloc(sizeof(NODE*));
p->next = S;
return p;
}
//删除栈顶元素,并返回数据指针
ElemType* Pop(STACK S)
{
NODE *p = NULL;
if (S->next)
{
p = S;
S = S->next;
return p->elem;
}
fprintf(stderr, "Stack doesn't exist!");
return NULL;
}
Status StackTraverse(STACK S)
{
NODE *p;
p = S;
if (S->next)
{
while (p->next)
{
StackVisit(p);
p = p->next;
}
}
}
void StackVisit(NODE* p)
{
printf("%d", *(p->elem));
}
应用
- 数制转换
void conversion()
{
//对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数
int N, *elem;
elem = (int*)malloc(sizeof(int));
STACK S;
S = CreateStack();
scanf_s("%d", &N);
while (N)
{
*elem = N % 8;
S = Push(S, elem);
N = N / 8; //注意关系
}
while (!StackEmpty(S))
{
elem = Pop(S,&S);
printf("%d", *elem);
free(elem);
}
}//conversion
- 括号匹配检验
BOOL correct(char ext[], int i)
{
STACK S;
int j = 0;
S = CreateStack();
for (j = 0; j < i; j++)
{
int mark = 0,*mark2 = NULL;
mark = IsBrackets(ext[j]);
if (mark >= 1 && mark <= 3)
{
S = Push(S, &mark);
}
else if (mark >= 7 && mark <= 9)
{
mark2 = Pop(S,&S);//注意这个地方要传入指针的地址奥
if ((*mark2) + mark != 10)
{
fprintf(stderr, "ERROR!");
return -1;
}
free(mark2);
}
}
if (S->next == NULL)
return TRUE;
return FALSE;
}
int IsBrackets(char a)
{
switch (a) {
case '(':return 1;
case '[':return 2;
case '{':return 3;
case ')':return 9;
case']':return 8;
case '}':return 7;
default:return 0;
}
}
- 行编辑程序
void LineEdit()
{
STACK S=CreatStack();
ch = getchar();
while(ch!=EOF)
{
while(ch!=EOF&&ch!='\n')
{
switch(ch){
case '#':Pop(S,c);
case '@':ClearStack(S);
default:Push(S,ch);
}//switch
ch=getchar();
}//while
}//while EOF
}//LineEdit
- 迷宫求解
void FindRoad(STACK S, int mark[][COL], int maze[][COL])
{
int i = 1, j = 1, v = 0;
int g, h;
int V[8][2] = { 0,1,1,1,1,0,1,-1,0,-1,-1,-1,-1,0,-1,1 };
NODE *e;
S = Push(S,i,j,v);
mark[1][1] = 1;
do {
g = i + V[v][0];
h = j + V[v][1];
if ((g == ROW - 2) && (h == COL - 2)&&maze[ROW-2][COL-2]==0)
{
output(S);
return;
}
if (maze[g][h] == 0 && mark[g][h] == 0)
{
S = Push(S, g, h, v);
i = g;
j = h;
v = 0;
mark[g][h] = 1;
}
else if (maze[g][h] == 1 || mark[g][h] == 1)
{
if (v == 7&&S&&!StackEmpty(S))
{
e = Pop(S, &S);
e = GetTop(S);
i = e->elem->i;
j = e->elem->j;
v = e->elem->v + 1;
}
else
{
v += 1;
}
}
} while (!StackEmpty(S)||v!=8);
printf("路径不存在!");
return;
}
- 判断字符串是否中心对称
- 汉诺塔
- 表达式求值(中缀转换为前后缀)重点
首先对算符之间有优先级的定义。
基本思想:- 设置两个栈,OPND和OPTR。OPND为寄存操作数以及运算结果(都是数字),OPNR寄存运算符。
- 依次读入表达式中的数字、字符。如果是操作数则进栈OPND,若是运算符则和OPNR栈顶的运算符的优先级作比较:
若优先级低于栈顶的操作符,则栈顶元素出栈并对操作数的最上面两个数出栈后进行相应的运算,运算结果存储于OPND中。
直至表达式读取结束且OPND栈为空,OPNR栈的仅剩的一个元素则为运算结果。
注:对于(),一旦相遇则说明括号内的运算已经完成,则可以出栈直接读取下一个操作符。(消消乐)