栈的基本算法——后缀式转化及计算

最近学到数据结构栈的部分,为了加深记忆特意敲了栈基本算法的函数代码,并且运用栈来实现后缀式转化及计算的功能。
首先来简单的介绍一下栈的基本内容

定义:一种只能在一端进行插入(入栈)或删除(出栈)的线性表。

注意,栈是操作受限(只能在一端插删)的线性表,但受限的线性表也还是线性表。

特点:先进后出。

例如一条只有一人宽的死胡同,几个人进去,先进去一定是最后出来。

基本操作:

InitStack(s) // 初始化栈,构造一个空栈 s 。
DestroyStack(s) / /销毁栈,释放栈 s 占用的空间。
StackEmpty(s) / /判断栈是否为空,空返回真,否则返回假。
Push(s,e) / /进栈,将元素 e 插入到栈 s 中作为栈顶元素。
Pop(s,e) / /出栈,从栈 s 中删除栈顶元素,并将其赋值给 e 。
GetTop(s,e) / /取栈顶元素,返回栈顶元素,将其值赋给 e 。

在c++的STL中有关于栈的部分,只要写入< stack >的头文件就可以像引用库函数一样引用栈的操作函数。但笔者现在对STL不甚理解,故在下面代码示例中写下各操作函数的源代码

代码示例:

头文件及函数声明部分

#include<iostream>
#include<cstdlib>
using namespace std;
#define N 200
typedef struct lei
{
     char a;
     double b;
     struct lei *next;
}lei;
//------------------------------------字符型--------------------------------------------    
void InitStack(lei *&s);                     //初始化            InitStack(s);
void DestroyStack(lei *&s);                  //销毁栈            DestroyStack(s); 
bool StackEmpty(lei *s);                     //判断是否为空栈    StackEmpty(s);
void Push(lei *&s,char e);                   //进栈              Push(s,e);
bool Pop(lei *&s,char &e);                   //出栈              Pop(s,e);
bool GetTop(lei *s,char &e);                 //栈顶元素提取      GetTop(s,e);
void trans(char *exp,char postexp[]);        //后缀式转换        trans(exp,postexp);
//-------------------------------------实型---------------------------------------------
void Push1(lei *&s,double e);                //进栈              Push1(r,e);
bool Pop1(lei *&s,double &e);                //出栈              Pop1(r,e);
bool GetTop1(lei *s,double &e);              //栈顶元素提取      GetTop1(r,e);
double compvalue(char *postexp);             //后缀式计算        compvalue(postexp);

主函数部分

int main()
{
     char exp[]="2+1*2+(1+2/(4-2)+3)";
     char postexp[N]; 
     printf("中缀表达式:\t\t");
     puts(exp);
     trans(exp,postexp);
     printf("后缀表达式:\t\t");
     puts(postexp);
     printf("计算结果保留两位小数:  ");
     printf("%.2lf\n",compvalue(postexp));
     return 0;
}

功能函数部分

void trans(char *exp,char postexp[])  //后缀式转换        trans(exp,postexp);
{
     int i=0; 
     char e;
     lei *s;
     InitStack(s);                    //栈初始化                
     while(*exp!='\0')                //*exp 表示指针exp所指向的字符串的第一个字符            
     {
          switch(*exp)           
          {
          case '(':                   //判定为左括号
               Push(s,'(');           //左括号直接进栈         
               exp++;                 //扫描下一个字符      
               break;
          case ')':                   //判定为右括号 
               Pop(s,e);              //不为左括号是循环;目的是将该双括号内的的计算符全部存入postexp
               while(e!='(')            
               {
                    postexp[i++]=e;
                    Pop(s,e);         //先出栈(从栈中删除),不是左括号则存入postexp,注:此操作会将与右括匹配的左括号删除
               }
               exp++;
               break;
          case '+':
          case '-':
               while(!StackEmpty(s))      //栈不空时循环  
               {
                    GetTop(s,e);          //取栈顶元素
                    if(e!='(')             
                    {
                        postexp[i++]=e;   //不为左括号就存入postexp
                        Pop(s,e);         //出栈
                    }
                    else                  //e=='(' 时退出循环
                        break;
              } 
               Push(s,*exp);              //将该 '+'||'-' 入栈   
               exp++;
               break;
           case '*':
           case '/':
               while(!StackEmpty(s))      //栈不空时循环
               {
                    GetTop(s,e);          //去栈顶元素
                    if(e=='*'||e=='/')    //把前面的 '*' || '/' 全部出栈
                    {                     //原因:比'*'||'/'更高级的只有前面的'*'||'/'
                         postexp[i++]=e;  //注:之所以不考虑前面的左括号是因为遇见'('时就会跳出循环  
                         Pop(s,e);
                   }
                   else
                       break;             //当e=='+'||e=='-'||e=='(' 时跳出循环
               }
               Push(s,*exp);
               exp++;
               break; 
           default :                      //处理数字字符
               while(*exp>='0'&&*exp<='9')//数字直接存入postexp
               {
                   postexp[i++]=*exp;
                   exp++;
               }
               postexp[i++]='#';          //用'#'标识一个数字的结束,放在外面是考虑到可能有二位数三位数等
          }
 
     }
     while(!StackEmpty(s))                //exp已经扫描完毕
     {
          Pop(s,e);                       //将未出栈的运算符放在最后
          postexp[i++]=e;
     }
     postexp[i]='\0';                     //添加结束标识
     DestroyStack(s);                     //销毁栈
}

double compvalue(char *postexp)           //后缀式计算        compvalue(postexp);
{
     double a,b,c,d,e;
     lei *r;
     InitStack(r);
     while(*postexp!='\0')
     {
          switch(*postexp)
          {
          case '+':                           
               Pop1(r,a);
               Pop1(r,b);                              //取出运算符前面紧挨的两个数
               c=b+a;                                  //进行相关运算
               Push1(r,c);                             //入栈,用于进行下次运算
               break;
          case '-':
               Pop1(r,a);
               Pop1(r,b);
               c=b-a;
               Push1(r,c);
               break;
          case '*':
               Pop1(r,a);
               Pop1(r,b);
               c=b*a;
               Push1(r,c额);
               break;
          case'/':
               Pop1(r,a);
               Pop1(r,b);
               if(a!=0)    
               {
                   c=b/a;
                   Push1(r,c);
                   break;
               }
               else                                    //除数为零
               {
                    printf("\n除零错误!\n");
                    exit(0);                            //非正常结束进程
               }
               break;
          default :
               d=0;
               while(*postexp>='0'&&*postexp<='9')       
               {
                    d=10 * d + *postexp - '0';  
                    postexp++;
               }
               Push1(r,d);                             //将数字入栈
               break;
          }
          postexp++;
    }
    GetTop1(r,e);                                   //取栈顶元素,事实上此时栈中仅有一个元素
    DestroyStack(r);                                //销毁栈
    return e;                                       //返回结果
}

栈的操作函数部分

//字符型函数
void InitStack(lei *&s)        //初始化    InitStack(s);
{
     s=(lei *)malloc(sizeof(lei));
     s->next=NULL;
}

void DestroyStack(lei *&s)     //销毁栈    DestroyStack(s); 
{
     lei *pre=s,*p=s->next;              //pre指向头结点,p指向首节点
     while(p!=NULL)
     {
          free(pre);
          pre=p;
          p=p->next;
     }
     free(pre);                         //此时pre指向尾节点
}

bool StackEmpty(lei *s)        //判断是否为空栈    StackEmpty(s);
{
     return(s->next==NULL);
}

void Push(lei *&s,char e)      //进栈       Push(s,e);
{
     lei *p;
     p=(lei *)malloc(sizeof(lei));
     p->a=e;
     p->next=s->next;                   //头插法,将p节点插入作为首节点
     s->next=p;
}

bool Pop(lei *&s,char &e)      //出栈       Pop(s,e);
{
     lei *p;
     if(s->next==NULL) return false;    //空栈的情况返回假
     p=s->next;
     e=p->a;                            //提取首节点值
     s->next=p->next;                   //删除首节点
     free(p);                           //释放被删除节点的存储空间
     return true;
}

bool GetTop(lei *s,char &e)            //栈顶元素提取      GetTop(s,e);
{
     if(s->next==NULL) return false;
     e=s->next->a;
     return true;
}
//实型函数
void Push1(lei *&s,double e)              //进栈       Push1(s,e);
{
     lei *p;
     p=(lei *)malloc(sizeof(lei));
     p->b=e;
     p->next=s->next;                             //头插法,将p节点插入作为首节点
     s->next=p;
}

bool Pop1(lei *&s,double &e)              //出栈       Pop1(s,e);
{
     lei *p;
     if(s->next==NULL) return false;      //空栈的情况返回假
     p=s->next;
     e=p->b;                                      //提取首节点值
     s->next=p->next;                             //删除首节点
     free(p);                                     //释放被删除节点的存储空间
     return true;
}

bool GetTop1(lei *s,double &e)            //栈顶元素提取      GetTop1(s,e);
{
     if(s->next==NULL) return false;
     e=s->next->b;
     return true;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值