一、棧的應用
1.1 括號匹配問題
怎樣判斷是不是匹配序列呢?
算法思想:
1)初始一個空棧,順序讀入括號。
2)若是右括號,則與棧頂元素進行匹配
●若匹配,則彈出棧頂元素並進行下一個元素
●若不匹配,則該序列不合法
3)若是左括號,則壓入棧中
4)若全部元素遍歷完畢,棧中非空則序列不合法
代碼如下:
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 50
#define ElemType char
typedef struct
{
ElemType data[MaxSize];
int top;
}SqStack;
void InitStack(SqStack *&s){
s = (SqStack*)malloc(sizeof(SqStack));
s->top=-1;
}
bool IsEmpty(SqStack *&s){
return s->top == -1;
}
bool Push(SqStack *&s, ElemType e){
//判斷棧有沒有滿
if(s->top == MaxSize)
return false;
s->data[++s->top] = e;
return true;
}
bool Pop(SqStack *&s, ElemType &e){
//如果棧爲空,則返回false
if(s->top == -1)
return false;
e = s->data[s->top--];
return true;
}
bool GetTop(SqStack *&s, ElemType &e){
if(s->top==-1)
return false;
e = s->data[s->top];
return true;
}
void DestroyStack(SqStack *&s){
free(s);
}
//括號匹配問題
bool Match(char exp[],int n)
{
int i=0; char e;
bool match=true;
SqStack *st;
InitStack(st); //初始化棧
while (i<n && match) //掃描exp中所有字符
{
if (exp[i]=='(') //當前字符爲左括號,將其進棧
Push(st,exp[i]);
else if (exp[i]==')') //當前字符爲右括號
{
if (GetTop(st,e)==true)
{
if (e!='(') //棧頂元素不爲'('時表示不匹配
match=false;
else
Pop(st,e); //將棧頂元素出棧
}
else match=false; //無法取棧頂元素時表示不匹配
}
i++; //繼續處理其他字符
}
if (!IsEmpty(st)) //棧不空時表示不匹配
match=false;
DestroyStack(st); //銷燬棧
return match;
}
2.2 表達式求值問題
((2+3)*4)-(5-3)
- 先要中綴轉後綴:
- 計算後綴
中綴轉後綴算法思想:
數字直接加入後綴表達式運算符時:
a.若爲’(’,入棧;
b.若爲")",則依次把棧中的運算符加入後綴表達式,直到出現’(’, 並從棧中刪除’(’;
C.若爲’+’, ‘’, ‘*’, ‘/’,
●棧空,入棧;
●棧頂元素爲’(’,入棧;
●高於棧頂元素優先級,入棧;
●否則,依次彈出棧頂運算符,直到-一個優先級比它低的運算符或(爲止;
d.遍歷完成,若棧非空依次彈出所有元素。
void trans(char *exp,char postexp[]) //將算術表達式exp轉換成後綴表達式postexp
{
char e;
SqStack *Optr; //定義運算符棧
InitStack(Optr); //初始化運算符棧
int i=0; //i作爲postexp的下標
while (*exp!='\0') //exp表達式未掃描完時循環
{ switch(*exp)
{
case '(': //判定爲左括號
Push(Optr,'('); //左括號進棧
exp++; //繼續掃描其他字符
break;
case ')': //判定爲右括號
Pop(Optr,e); //出棧元素e
while (e!='(') //不爲'('時循環
{
postexp[i++]=e; //將e存放到postexp中
Pop(Optr,e); //繼續出棧元素e
}
exp++; //繼續掃描其他字符
break;
case '+': //判定爲加或減號
case '-':
while (!IsEmpty(Optr)) //棧不空循環
{
GetTop(Optr,e); //取棧頂元素e
if (e!='(') //e不是'('
{
postexp[i++]=e; //將e存放到postexp中
Pop(Optr,e); //出棧元素e
}
else //e是'(時退出循環
break;
}
Push(Optr,*exp); //將'+'或'-'進棧
exp++; //繼續掃描其他字符
break;
case '*': //判定爲'*'或'/'號
case '/':
while (!IsEmpty(Optr)) //棧不空循環
{
GetTop(Optr,e); //取棧頂元素e
if (e=='*' || e=='/') //將棧頂'*'或'/'運算符出棧並存放到postexp中
{
postexp[i++]=e; //將e存放到postexp中
Pop(Optr,e); //出棧元素e
}
else //e爲非'*'或'/'運算符時退出循環
break;
}
Push(Optr,*exp); //將'*'或'/'進棧
exp++; //繼續掃描其他字符
break;
default: //處理數字字符
while (*exp>='0' && *exp<='9') //判定爲數字
{ postexp[i++]=*exp;
exp++;
}
postexp[i++]='#'; //用#標識一個數值串結束
}
}
while (!IsEmpty(Optr)) //此時exp掃描完畢,棧不空時循環
{
Pop(Optr,e); //出棧元素e
postexp[i++]=e; //將e存放到postexp中
}
postexp[i]='\0'; //給postexp表達式添加結束標識
DestroyStack(Optr); //銷燬棧
}
計算後綴算法思想
double compvalue(char *postexp) //計算後綴表達式的值
{
double d,a,b,c,e;
SqStack *Opnd; //定義操作數棧
InitStack(Opnd); //初始化操作數棧
while (*postexp!='\0') //postexp字符串未掃描完時循環
{
switch (*postexp)
{
case '+': //判定爲'+'號
Pop(Opnd,a); //出棧元素a
Pop(Opnd,b); //出棧元素b
c=b+a; //計算c
Push(Opnd,c); //將計算結果c進棧
break;
case '-': //判定爲'-'號
Pop(Opnd,a); //出棧元素a
Pop(Opnd,b); //出棧元素b
c=b-a; //計算c
Push(Opnd,c); //將計算結果c進棧
break;
case '*': //判定爲'*'號
Pop1(Opnd,a); //出棧元素a
Pop(Opnd,b); //出棧元素b
c=b*a; //計算c
Push(Opnd,c); //將計算結果c進棧
break;
case '/': //判定爲'/'號
Pop(Opnd,a); //出棧元素a
Pop(Opnd,b); //出棧元素b
if (a!=0)
{
c=b/a; //計算c
Push(Opnd,c); //將計算結果c進棧
break;
}
else
{
printf("\n\t除零錯誤!\n");
exit(0); //異常退出
}
break;
default: //處理數字字符
d=0; //將連續的數字字符轉換成對應的數值存放到d中
while (*postexp>='0' && *postexp<='9') //判定爲數字字符
{
d=10*d+*postexp-'0';
postexp++;
}
Push(Opnd,d); //將數值d進棧
break;
}
postexp++; //繼續處理其他字符
}
GetTop(Opnd,e); //取棧頂元素e
DestroyStack(Opnd); //銷燬棧
return e; //返回e
}
2.3 遞歸
我們可以用棧來實現遞歸過程
斐波拉契數列:0,1,1,2,3,5,…
//遞歸做法
int Fib(int n) {
if(n == 0)
return 0;
else if(n == 1)
return 1 ;
else
return Fib(n-1) + Fib(n-2) ;
}
使用棧:
int Fib(int n){
int ans;
if(n == 0)
return 0;
else if(n == 1)
return 1;
else{
SqStack *s;
InitStack(s);
Push(s,0);
Push(s,1);
while(n-- > 1){
int a,b;
Pop(s,a);
Pop(s,b);
Push(s,a);
Push(s,a+b);
}
GetTop(s,ans);
}
return ans;
}