栈
概念:
栈(Stack)是一种先进后出(FILO,First in Last Out)的线性表,只允许在线性表的一端进行操作。
典型应用:
函数调用时,函数的上下文环境(返回地址,全局变量等),形参,是以栈这样的数据结构存储的。
基本操作:
1. 压栈
2. 出栈
3. 栈判空
4. 元素个数
5. 栈清空
6. 栈销毁
操作应用:
1. 进制转换
2. 括号匹配
3. 后缀表达式求值
4. 中缀转后缀
5. 迷宫问题求解
栈的实现方法:
方法1:静态顺序表
方法2:动态顺序表(高效)
方法3:只能头插头删的单链表
栈的定义(动态顺序表):
-
typedef
struct Stack {
-
//以数组地址为栈底指针
-
DataType* _array;
-
//栈顶指针
-
int _top;
-
//栈的大小
-
unsigned
int _capacity;
-
}*PStack;
初始化:
-
//初始化栈
-
void StackInit(PStack stack) {
-
stack->_array = (DataType*)
malloc(
sizeof(DataType)*Init_StackSize);
-
for (
int i =
0; i <
sizeof(
stack->_array) /
sizeof(
stack->_array[
0]); i++) {
-
stack->_array[i] =
0;
-
}
-
if (!
stack->_array) {
-
exit(
0);
-
}
-
stack->_top =
0;
-
stack->_capacity = Init_StackSize;
-
}
基本操作:
1. 压栈
class=“language-cpp”>//压栈
-
//压栈
-
void StackPush(PStack stack, DataType data) {
-
assert(
stack);
-
//判断栈是否已满
-
if (
stack->_top >=
stack->_capacity) {
-
//申请10个空间
-
stack->_array = (DataType*)
realloc(
stack->_array,
-
sizeof(DataType)*(
stack->_capacity +
10));
-
//判断是否申请成功
-
if (!
stack->_array) {
-
exit(
0);
-
}
-
stack->_top =
stack->_capacity;
-
stack->_capacity =
stack->_capacity +
10;
-
}
-
-
*(
stack->_array +
stack->_top) = data;
-
stack->_top++;
-
}
2. 出栈(pop的数据放在data里面)
-
//出栈
-
int StackPop(PStack stack, DataType* data) {
-
assert(
stack);
-
//判断栈是否为空
-
if (
stack->_top ==
0) {
-
return
0;
-
}
-
//先减一再取值
-
--
stack->_top;
-
*data = *(
stack->_array +
stack->_top);
-
-
return
1;
-
}
3. 栈判空
-
//判断栈是否为空
-
int StackEmpty(PStack stack) {
-
assert(
stack);
-
//为空返回1
-
return
stack->_top ==
0 ?
1 :
0;
-
}
4. 有效元素个数
-
//有效元素个数
-
int StackSize(PStack stack) {
-
assert(
stack);
-
return
stack->_top;
-
}
5. 栈清空
-
//清空栈,不进行物理删除
-
void ClearStack(PStack stack) {
-
assert(
stack);
-
stack->_top =
0;
-
}
6. 栈销毁
-
//销毁栈
-
void dropStack(PStack stack) {
-
assert(
stack);
-
int len =
stack->_capacity;
-
for (
int i =
0; i < len; i++) {
-
free(
stack->_array);
-
stack->_array++;
-
}
-
stack->_array =
NULL;
-
stack->_top =
0;
-
stack->_capacity =
0;
-
}
操作应用:
1. 进制转换
-
//二进制转10进制
-
int BinaryToTen(PStack stack, DataType* str) {
-
assert(
stack);
-
unsigned
int len =
stack->_capacity;
-
char* p_str = str;
-
int sum =
0;
-
for (
int i =
0; i < len; i++) {
-
if (*p_str ==
'\0')
-
break;
-
StackPush(
stack, *p_str);
-
p_str++;
-
}
-
char binary =
' ';
-
for (
int i =
0; i < len; i++) {
-
if (
0 == StackPop(
stack, &binary))
-
break;
-
sum += (binary -
48)*
pow(
2, i);
-
}
-
return sum;
-
}
2. 括号匹配
-
//括号匹配
-
void MatchBranckets(char* str) {
-
if (str ==
NULL)
-
return;
-
-
//初始化栈
-
PStack
stack = (PStack)
malloc(
sizeof(struct Stack));
-
StackInit(
stack);
-
-
char* p_str = str;
-
-
//用来保存弹出的字符
-
char c;
-
-
while (*p_str) {
-
-
if (*p_str ==
'{' || *p_str ==
'(' || *p_str ==
'[') {
-
StackPush(
stack, *p_str);
-
}
-
-
if (*p_str ==
'}' || *p_str ==
')' || *p_str ==
']') {
-
-
StackPop(
stack, &c);
-
-
if (c ==
'{' && *p_str ==
'}');
-
else
if (c ==
'(' && *p_str ==
')');
-
else
if (c ==
'[' && *p_str ==
']');
-
else {
-
printf(
"匹配失败\n");
-
return;
-
}
-
-
}
-
-
p_str++;
-
}
-
-
//遍历完之后,栈中还有括号,代表匹配失败
-
if (StackPop(
stack, &c))
-
{
-
printf(
"匹配失败\n");
-
return;
-
}
-
printf(
"匹配成功\n");
-
}
3. 后缀表达式求值
-
//根据操作符的不同进行不同的计算
-
int caculate(int first, int second, char operator) {
-
if (
operator ==
'+') {
-
return first + second;
-
}
-
else
if (
operator ==
'-') {
-
return first - second;
-
}
-
else
if (
operator ==
'*') {
-
return first * second;
-
}
-
else
if (
operator ==
'/') {
-
return first / second;
-
}
-
}
-
-
//后缀表达式求值
-
int caculateNifixExpression(char* str) {
-
-
//用来放整形操作数
-
PStack
operator = (PStack)
malloc(
sizeof(struct Stack));
-
StackInit(
operator);
-
-
if (str ==
NULL)
-
return;
-
-
char* p_str = str;
-
char* p_preStr = str;
-
-
int StackPopData =
0;
-
//弹出的第一个操作数,右操作数
-
int first =
0;
-
//弹出的第二个操作数, 左操作数
-
int second =
0;
-
while (*p_str) {
-
if (*p_str ==
' ') {
-
//空格前是数字,压栈
-
if (*p_preStr >=
'0' && *p_preStr <=
'9')
-
StackPush(
operator, atoi(p_preStr));
-
p_preStr = p_str +
1;
-
}
-
if (*p_str ==
'+' || *p_str ==
'-' || *p_str ==
'*' || *p_str ==
'/') {
-
-
StackPop(
operator, &StackPopData);
-
second = StackPopData;
-
StackPop(
operator, &StackPopData);
-
first = StackPopData;
-
-
//计算结果
-
StackPopData = caculate(first, second, *p_str);
-
-
//结果入栈
-
StackPush(
operator, StackPopData);
-
}
-
p_str++;
-
}
-
StackPop(
operator, &StackPopData);
-
printf(
"计算结果为%d\n", StackPopData);
-
return StackPopData;
-
}
4.中缀表达式转后缀表达式
思路:
(1).初始化两个栈(一个用来运算operand,一个用来存放结果operand)
(2).扫描字符串
-
//中缀转后缀
-
char* SuffixToNifix(char* str) {
-
-
//操作数栈
-
PStack operand = (PStack)
malloc(
sizeof(struct Stack));
-
StackInit(operand);
-
-
//操作符栈
-
PStack
operator = (PStack)
malloc(
sizeof(struct Stack));
-
StackInit(
operator);
-
-
char buffer;
-
while (*str) {
-
//判断是操作数还是操作符
-
if (*str >=
'0' && *str <=
'9') {
-
//操作数入栈
-
StackPush(operand, *str);
-
if(*(str +
1) <
'0' || *(str +
1) >
'9')
-
if (StackTop(operand) !=
0)
-
StackPush(operand,
0);
-
}
-
else {
-
/*if (StackTop(operand) != 0)
-
StackPush(operand, 0);*/
-
//扫描到操作符
-
//判断操作符栈是否为空,为空直接入栈
-
if (
1 == StackEmpty(
operator)) {
-
StackPush(
operator, *str);
-
}
-
else
if (
'(' == *str) {
-
//遇到左括号,直接入栈,左括号的优先级最高
-
StackPush(
operator, *str);
-
}
-
else
if (
')' == *str) {
-
//遇到右括号,一直出栈,并压栈到操作数栈,直到把括号弹出
-
while (
1) {
-
StackPop(
operator, &buffer);
-
if (buffer ==
'(')
-
break;
-
StackPush(operand, buffer);
-
/*if (StackTop(operand) != 0)
-
StackPush(operand, 0);*/
-
}
-
}
-
else {
-
-
//非空,则比较当前栈顶运算符和遇到的运算符的优先级
-
char operatorTop = StackTop(
operator);
-
if (cmpPriority(operatorTop, *str) >
0 && operatorTop !=
'(') {
-
//栈顶运算符优先级较高,弹出栈顶运算符,并压到操作数栈
-
StackPop(
operator, &buffer);
-
StackPush(operand, buffer);
-
StackPush(
operator, *str);
-
}
-
else {
-
//栈顶运算符优先级较低,当前运算符直接入栈
-
StackPush(
operator, *str);
-
}
-
-
}
-
-
}
-
-
str++;
-
}
-
char buf;
-
while (StackPop(
operator, &buf)) {
-
StackPush(operand, buf);
-
}
-
while (StackPop(operand, &buf)) {
-
StackPush(
operator, buf);
-
-
}
-
while (StackPop(
operator, &buf)) {
-
printf(
"%c", buf);
-
}
-
printf(
"\n");
-
return
NULL;
-
}
5. 迷宫问题
思路:
非递归:
(1)入口点压栈。
(2)以左上右下的顺序判断周围有哪个坐标可以到达(数组的值设置为1)。
(3)遇到可以到达的坐标就把当前坐标设置为这个坐标,将当前坐标设置为不可达(数组的值设置为2),并把这个坐标压栈
(4)重复(2)(3)步。
(5)遇到了死胡同(周围都不可达),栈顶坐标出栈,并将弹出的坐标设置为当前坐标。
(6)判断是否到达了起点(无出口),判断是否到达了边界位置(非起点),到达边界跳出。未到达边界。
(7)重复(2)(3)步
-
#include
-
#include
-
#include
-
#define INIT_STACKSIZE 100
-
#define WIDTH 10
-
-
//设置当前坐标的状态,将当前坐标入栈
-
#define SET_WENTSTATE_AND_PUSHSTACK \
-
map[y][x] = 2;\
-
loc._x = x;\
-
loc._y = y;\
-
StackPush(s, loc);\
-
continue
-
-
-
typedef
struct Location {
-
//坐标
-
int _x;
-
int _y;
-
-
}Location;
-
-
typedef Location DataType;
-
-
typedef
struct Stack {
-
DataType* _array;
-
int _top;
-
//最大容量
-
int _capacity;
-
}*PStack, Stack;
-
-
void StackInit(PStack s) {
-
s->_array = (PStack)
malloc(
sizeof(Stack)*INIT_STACKSIZE);
-
if (s->_array ==
NULL)
-
exit(
0);
-
s->_capacity = INIT_STACKSIZE;
-
s->_top =
0;
-
}
-
-
void StackPush(PStack s, DataType loc) {
-
assert(s);
-
if (s->_top >= s->_capacity) {
-
s->_array = (PStack)
realloc(s->_array, ((s->_capacity)+
10)*
sizeof(Stack));
-
if (s->_array ==
NULL)
-
exit(
0);
-
s->_capacity = s->_capacity +
10;
-
}
-
*(s->_array + s->_top) = loc;
-
s->_top++;
-
}
-
-
int StackPop(PStack s, DataType* loc) {
-
assert(s);
-
if (!s->_top) {
-
return
0;
-
}
-
--s->_top;
-
*loc = *(s->_array + s->_top);
-
return
1;
-
}
-
-
DataType StackTop(PStack s) {
-
return *(s->_array + s->_top);
-
}
-
-
//判断是否到达边界
-
int isBorder(int x, int y) {
-
if (x == WIDTH -
1 || x ==
0 || y ==
0 || y == WIDTH -
1)
-
return
1;
-
return
0;
-
}
-
-
//判断是否回到了起点
-
int isStart(int start_x, int start_y, int x, int y) {
-
if (start_x == x && start_y == y)
-
return
1;
-
return
0;
-
}
-
-
//打印地图
-
void showMap(int map[WIDTH][WIDTH]) {
-
for (
int i =
0; i < WIDTH; i++) {
-
for (
int j =
0; j < WIDTH; j++) {
-
if (
map[i][j] ==
0) {
-
printf(
"█");
-
}
-
else
if(
map[i][j] ==
1){
-
printf(
" ");
-
}
-
else {
-
printf(
" *");
-
}
-
//printf("%d ", map[i][j]);
-
}
-
printf(
"\n");
-
}
-
}
-
-
void maze(int map[WIDTH][WIDTH], int start_x, int start_y) {
-
-
PStack s = (PStack)
malloc(
sizeof(Stack));
-
StackInit(s);
-
-
//入口
-
int x = start_x;
-
int y = start_y;
-
-
//将入口位置设置为已走过的状态
-
map[y][x] =
2;
-
//将当前坐标压栈,
-
-
showMap(
map);
-
-
Location loc = { x, y };
-
StackPush(s, loc);
-
-
while (
1) {
-
int oldx = x;
-
int oldy = y;
-
-
//左
-
if (
map[y][x -
1] ==
1) {
-
--x;
-
SET_WENTSTATE_AND_PUSHSTACK;
//宏:入栈和赋值当前坐标操作。
-
}
-
//上
-
if (
map[y -
1][x] ==
1) {
-
--y;
-
SET_WENTSTATE_AND_PUSHSTACK;
-
}
-
//右
-
if (
map[y][x +
1] ==
1) {
-
++x;
-
SET_WENTSTATE_AND_PUSHSTACK;
-
}
-
//下
-
if (
map[y +
1][x] ==
1) {
-
++y;
-
SET_WENTSTATE_AND_PUSHSTACK;
-
}
-
-
Location loc1;
-
if (!StackPop(s, &loc1)) {
-
if (isStart(start_x, start_y, oldx, oldy)) {
-
printf(
"迷宫无出口\n");
-
break;
-
}
-
break;
-
}
-
-
//判断是否到达边界
-
if (isBorder(x, y)) {
-
//判断是否遇到起始位置
-
showMap(
map);
-
break;
-
}
-
-
//遇到分叉点的处理,因为第二次到达分叉点的时候分叉点已经弹出。所以要求出分叉点的坐标
-
if (oldx +
2 == loc1._x || oldy +
2 == loc1._y ||
-
oldx -
2 == loc1._x || oldy -
2 == loc1._y
-
) {
-
x = (oldx + loc1._x) /
2;
-
y = (oldy + loc1._y) /
2;
-
StackPush(s, loc1);
-
}
-
else {
-
x = loc1._x;
-
y = loc1._y;
-
}
-
-
}
-
}
-
-
//迷宫问题递归解法
-
int ENDX =
0;
-
int ENDY =
8;
-
int mazeRecursion(int map[][WIDTH], int x, int y) {
-
map[y][x] =
2;
-
int isEnd =
0;
//判断是不是终点
-
if (ENDX == x && ENDY == y) {
-
isEnd =
1;
-
}
-
//左
-
if (isEnd !=
1 && x >=
0 &&
map[y][x -
1] ==
1) {
-
if(mazeRecursion(
map, x -
1, y) ==
1)
-
return
1;
-
}
-
//上
-
if (isEnd !=
1 && y >=
0 &&
map[y -
1][x] ==
1) {
-
if (mazeRecursion(
map, x, y -
1) ==
1)
-
return
1;
-
}
-
//右
-
if (isEnd !=
1 && x < WIDTH &&
map[y][x +
1] ==
1) {
-
if (mazeRecursion(
map, x +
1, y) ==
1)
-
return
1;
-
}
-
//下
-
if (isEnd !=
1 && y < WIDTH &&
map[y +
1][x] ==
1) {
-
if (mazeRecursion(
map, x, y +
1) ==
1)
-
return
1;
-
}
-
-
//未到终点,但是没有路可以走了。
-
if (isEnd ==
0) {
-
map[y][x] =
1;
-
}
-
//未到终点返回0。
-
return isEnd;
-
}
-
int main() {
-
int
map[WIDTH][WIDTH] = {
-
{
0,
0,
0,
0,
0,
0,
1,
0,
0,
0 },
-
{
0,
0,
1,
1,
1,
0,
1,
0,
1,
0 },
-
{
0,
0,
1,
0,
1,
0,
1,
0,
1,
0 },
-
{
0,
0,
1,
0,
1,
0,
1,
0,
1,
0 },
-
{
0,
0,
1,
0,
0,
0,
1,
0,
1,
0 },
-
{
0,
0,
1,
1,
1,
0,
1,
0,
1,
0 },
-
{
0,
0,
1,
0,
1,
0,
1,
1,
1,
0 },
-
{
0,
0,
1,
0,
1,
0,
0,
0,
1,
0 },
-
{
1,
1,
1,
0,
1,
1,
1,
1,
1,
0 },
-
{
0,
0,
0,
0,
0,
0,
0,
0,
0,
0 }
-
};
-
-
printf(
"非递归:\n");
-
maze(
map,
6,
0);
-
/*printf("递归:\n");
-
mazeRecursion(map, 6, 0);
-
showMap(map);*/
-
return
0;
-
}
运行结果: