一、栈的定义:
就是只能表的一端操作的顺序表或链表,允许操作的那一端成为栈顶元素,与之相对应的另一端称为栈底元素。
我们向栈里存入元素称为压栈,即最先放入的元素存放在栈底,最后放入的元素存放在栈顶。
我们将取出栈中的元素的操作称为出栈,即最先存入的元素最后取出,最后存入的元素最先取出。
二、对栈常规的操作
1.压栈(Push)
2.出栈(Pop)
3.获取栈顶元素(GetTop)
三、 栈的应用场景
四、顺序栈的实现
#include<stdio.h>#define MAXSIZE 10typedef struct stack{int data[MAXSIZE];//数据域int top;//指向栈顶的位置的变量}SqStack;
void InitSqStack(SqStack * S){S->top = -1;}
int GetTop(SqStack * S){//判空if(S->top == -1){printf("栈空");exit(0);}return S->data[S->top];}
bool Push(SqStack * S,int x){//判满if(S->top == MAXSIZE){printf("栈满\n");return false;}S->top++;S->data[S->top] = x;return true;}
bool Push(SqStack * S,int * x){//判空if(S->top == -1){printf("栈空");return false;}*x = S->data[S->top];
S->top--;
return true;
}
五、链栈的实现
1.定义链栈的结构体:
typedef struct LinkNode{
int data;
struct LinkNode* next;
}LinkNode,*LinkStack;
2.链栈的初始化:
LinkStack InitLinkStack(LinkStack S){
//为链栈的头结点开辟空间
S = (LinkStack)malloc(sizeof(LinkNode));
if(S == NULL){
printf("初始化失败\n");
return NULL;
}
S->data = 0;
S->next = NULL;
return S;
}
3.创建链栈:
栈是先进后出,链栈的创建使用链表的头插法实现
bool CreateLinkStack(LinkStack S){
//判断链栈是否未初始化
if(S == NULL){
printf("链栈未初始化\n");
return false;
}
//使用头插法创建链栈
//创建一个新的节点
int x;
printf("请你输入插入的值\n");
scanf("%d",&x);
LinkNode* node = NULL;
LinkNode* p = S;
while(x != 999){
node = (LinkNode*)malloc(sizeof(LinkNode));
node->data = x;
node->next = p->next;
p->next = node;
scanf("%d",&x);
}
return true;
}
4.链表的出栈:通过不断删除链表的第一个节点实现链表的出栈效果
bool PopLinkStack(LinkStack S,int *e){
if(S->next == NULL){
printf("该链栈为空栈\n");
return false;
}
LinkNode* p = S;
LinkNode* q = S->next;
*e = q->data;
p->next = q->next;
free(q);
q = NULL;
return true;
}
5.获取链栈的栈顶元素:
bool GetElemStack(LinkStack S,int *e){
if(S->next == NULL){
printf("该链栈为空栈\n");
return false;
}
*e = S->next->data;
return true;
}
6.main函数:
int main(){
LinkStack S;
S = InitLinkStack(S);
CreateLinkStack(S);
int e;
PopLinkStack(S,&e);
printf("%d\t",e);
PopLinkStack(S,&e);
printf("%d\t",e);
PopLinkStack(S,&e);
printf("%d\t",e);
GetElemStack(S,&e);
printf("%d\n",e);
}
六、栈的应用
1.括号匹配:
使用顺序栈实现
主要思想:当输入左括号 [ ( { 就将其入栈,遇到 ] } ) 就将站内的元素出栈,若站为空直接匹配失败
若是中间遇到一个不匹配成功的就匹配失败,全部匹配成功才显示匹配成功。
#include<stdio.h>
#include<stdbool.h>
#include<string.h>
#define MAXSIZE 10
typedef struct Stack
{
char data[MAXSIZE];
int top;
}Stack;
/**1.初始化栈 */
bool InitStack(Stack * S){
S->top = -1;
return true;
}
/**2.压栈 */
bool PushStack(Stack * S,char x){
if(S->top == MAXSIZE - 1){
printf("栈满\n");
return false;
}
S->top++;
S->data[S->top] = x;
return true;
}
/**3.出栈 */
bool PopStack(Stack * S,char * e){
if(S->top == -1){
printf("栈为空\n");
return false;
}
*e = S->data[S->top];
S->top--;
return true;
}
/**4.括号匹配 */
bool CheckBracket(char * bracket){
Stack S;
InitStack(&S);
PushStack(&S,'[');
PushStack(&S,'(');
int length = strlen(bracket);
for(int i = 0; i < length; i++){
if(bracket[i] == '(' || bracket[i] == '[' || bracket[i] == '{'){
//扫描到左括号
//压栈
PushStack(&S,bracket[i]);
}
//扫描到右括号
else if(bracket[i] == ')' || bracket[i] == ']' || bracket[i] == '}'){
if(S.top == -1){
//栈为空
printf("栈为空,匹配失败\n");
return false;
}
//出栈
char ch;
PopStack(&S,&ch);
if(ch != '(' && bracket[i] == ')'){
printf("匹配失败\n");
return false;
}
if(ch != '[' && bracket[i] == ']'){
printf("匹配失败\n");
return false;
}
if(ch != '{' && bracket[i] == '}'){
printf("匹配失败\n");
return false;
}
}
}
//匹配完当栈为空时表示匹配成功
if(S.top == -1){
printf("匹配成功\n");
return true;
}else{
printf("匹配失败\n");
return false;
}
}
int main(){
char bracket[] = ")]";
CheckBracket(bracket);
}
运行结果:
为啥是匹配成功呢?:我传递的给括号匹配功能函数CheckBracket的字符为")]",而我的匹配函数CheckBracket中先压入"(["根据栈的出栈规律先出栈( 与 字符串中的 )匹配成功 再出栈 [ 与 字符串中的 ]匹配,匹配成功,全部匹配成功则输出匹配成功。
2.计算器的实现
顺序栈的实现:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define MAXSIZE 20
typedef struct stack{
int data[MAXSIZE];
int top;
}SqStack;
/*1.初始化*/
bool InitSqStack(SqStack * S){
S->top = -1;
return true;
}
/**2.压栈 */
bool PushStack(SqStack * S,int x){
if(S->top == MAXSIZE - 1){
printf("栈满\n");
return false;
}
S->top++;
S->data[S->top] = x;
return true;
}
/**3.出栈 */
int PopStack(SqStack * S){
if(S->top == -1){
printf("栈空\n");
return 0;
}
int x = S->data[S->top];
S->top--;
return x;
}
/**4.判断运算符的优先级操作 */
int Priority(char u){
switch (u)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return -1;
}
}
/**5.运算操作 */
void PopPush(SqStack * Sdata,SqStack * Soper){
//将Sdata数字栈中的两个数据出栈
int x;
int y;
x = PopStack(Sdata);
y = PopStack(Sdata);
//将Soper运算符栈中的运算符出栈
char u;
u = PopStack(Soper);
//计算两数之和
int n;
switch (u)
{
case '+':
n = y+x;
break;
case '-':
n = y-x;
break;
case '*':
n = y*x;
break;
case '/':
n = y/x;
break;
}
PushStack(Sdata,n);
}
/**6.扫描输入的字符串,分情况不断的进行PopPush操作,得出最终结果 */
int count(char * str){
//创建数据栈与运算符栈
SqStack Sdata,Soper;
//初始化
InitSqStack(&Sdata);
InitSqStack(&Soper);
//对字符串进行遍历
while(*str != '\0'){
//遍历到的字符是数字
if(*str >= '0' && *str <= '9'){
int y = *str - '0';
str++;
//如果是多个数字呢
while(*str >= '0' && *str <= '9'){
y = y*10+(*str - '0');
str++;
}
PushStack(&Sdata,y);
}
//如果栈为空,或字符为(,或字符的优先级大于栈顶字符的优先级就将其放入字符栈
else if(Soper.top == -1 || *str == '(' || Priority(*str) > Priority(Soper.data[Soper.top])){
PushStack(&Soper,*str);
str++;
}
//如果字符为)并且字符栈的栈顶元素为( 就出将字符栈的栈顶元素出栈
else if(*str == ')' && Soper.data[Soper.top] == '('){
int ch;
ch = PopStack(&Soper);
str++;
}
//字符的优先级小于等于栈顶字符的优先级就将其出栈,并且数据栈的栈顶与其相邻的两个元素出栈计算
else{
PopPush(&Sdata,&Soper);
}
}
//字符串表达式扫描完毕,再次使用PopPush清空数据栈与运算符栈并计算
while(Soper.top > -1){
PopPush(&Sdata,&Soper);
}
int n = Sdata.data[Sdata.top];
return n;
}
int main(){
char c[50];
printf("请你输入表达式\n");
scanf("%s",c);
int n = count(c);
printf("结果为:%d",n);
}
运行结果: