1.栈相关知识
(1)栈的概念及结构
栈:一种特殊的线性表,只允许在固定一端进行插入删除。进行数据插入和删除操作的一端称 为 栈顶,另一端称为栈底。栈中数据元素遵循后进先出原则。
- 数组栈(推荐)
尾插尾删效率高,缓存利用率更高
- 链式栈
如果用尾做栈顶,尾插尾删,要设计成双向链表,否则删除数据效率低
如果用头做栈顶,头插头删,就可以设计成单链表
两种都可以,数组栈结构稍微好一点
数组栈的实现
(2)栈的应用——递归——待实现
(3)栈的应用——中缀表达式转后缀表达式
- 中缀、前缀、后缀的基本概念
- 中缀表达式:将操作符放在操作数中间的写法
操作数不一定要是常量或变量,操作数本身也可以是一个表达式
例:2+3;A-B;p*q;(2+3)*4
下面只考虑二元操作符
计算优先级:(){}【】^
- 前缀、后缀表达式可以不需要括号然后无歧义地进行分析,也无需关心操作符的优先级
- 前缀表达式:操作符置于操作数前
例:中缀:2+3 前缀+2 3
a+b*c +a*b c
- 后缀表达式:操作符置于操作数后
从编程角度:是最容易解析的,时间和内存的代价最少
例:中缀:2+3 前缀+2 3 后缀:2 3+
a+b*c +a*b c a bc* +
a+b*c=a+(b*c)=a(b*c)+ =a(bc*)+ =a b c*+
2.数组栈的实现
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top; //栈顶的位置
int capacity;
}ST;
void StackInit(ST* ps); //初始化
void StackDesroy(ST* ps);//释放
void StackPush(ST* ps, STDataType x);//插入
void StackPop(ST* ps);//删除
STDataType StackTop(ST* ps);//取栈顶的数据
int StackSize(ST* ps);//求栈中数据个数
bool StackEmpty(ST* ps);//判断栈是否为空
#include "stack.h"
//初始化
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0; //ps->top=-1; 初始化时,top给0,意味着top指向栈顶数据的下一个
//初始化时,top给-1,意味着top指向栈顶数据
ps->capacity = 0;
}
//释放
void StackDesroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
//插入
void StackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
//删除
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
//取栈顶的数据
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
//求栈中数据个数
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
//判断栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
/*if (ps->top > 0)
{
return true;
}
else
{
return false;
}*/
return ps->top == 0;
}
#include "stack.h"
void TestStack1()
{
ST st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
StackPop(&st);
StackPop(&st);
StackPop(&st);
StackPop(&st);
StackDesroy(&st);
}
void TestStack2()
{
ST st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
while (!StackEmpty(&st))
{
printf("%d ", StackTop(&st));
StackPop(&st);
}
printf("\n");
StackDesroy(&st);
}
int main()
{
//TestStack1();
TestStack2();
return 0;
}
3.有效的括号
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//给定一个只包括(,),{,},【,】的字符串s,判断字符串是否有效
//有效字符串需满足:
// 1.左括号类型必须用相同类型的右括号闭合
// 2.左括号必须以正确的顺序闭合
typedef char STDataType;
typedef struct Stack
{
STDataType* a;
int top; //栈顶的位置
int capacity;
}ST;
//初始化
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0; //ps->top=-1; 初始化时,top给0,意味着top指向栈顶数据的下一个
//初始化时,top给-1,意味着top指向栈顶数据
ps->capacity = 0;
}
//释放
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
//插入
void StackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
//判断栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
//删除
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
ps->top--;
}
//取栈顶的数据
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
//求栈中数据个数
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
bool isValid(char* s)
{
ST st;
StackInit(&st);
while(*s)
{
if(*s=='('||*s=='{'||*s=='[')
{
StackPush(&st,*s);
++s;
}
else
{
//遇到右括号了,但是栈里面没有数据
//说明前面没有做括号,不匹配了,返回false
if(StackEmpty(&st))
{
StackDestroy(&st);
return false;
}
STDataType top=StackTop(&st);
StackPop(&st);
if((*s=='}'&&top!='{')||(*s=='('&&top!=')')||(*s=='['&&top!=']'))
{
StackDestroy(&st);
return false;
}
else
{
++s;
}
}
}
//如果栈不是空,说明栈中还有左括号未出
//没有匹配,返回False
bool ret=StackEmpty(&st);
StackDestroy(&st);
return ret;
}
void test()
{
char s[4]={'{','[',']','}'};
isValid(s);
}
int main()
{
test();
return 0;
}
4.前缀、后缀表达式求值(用栈实现)——待实现
5.中缀到后缀表达式的转换(用栈来实现)——待实现