用c语言实现中缀表达式转前缀表达式

废话:

在粤嵌培训的时候老师讲到数据结构阶段,也讲到了中缀表达式,前缀表达式,后缀表达式,以及这其中的转换,说有兴趣可以把中缀转前缀的代码写出来。

大家都写了不过我发现以单纯的数据为char型的栈无法真正的做到多位数的中缀转前缀,我就想试试。诶搞了两天的空余时间终于被我这呆瓜写出来了。

关键字:c语言,中缀表达式转前缀表达式,多位数,括号,等于。

正文:

中缀转前缀的方法:

中缀表达式转换成前缀表达式: 

        1.初始化两个栈 一个是运算符栈s1 一个是数据栈s2 
        2.从右到左扫描中缀表达式 
        3.当遇到数字(操作数)时 直接将其压入s2 
        4.当遇到运算符的时候 比如其跟s1栈顶运算符的优先级 
          4.1 如果s1为空 或者栈顶运算符为')' 则直接将次运算符入栈 
          4.2 否则 如果优先级比栈顶运算符优先级要高或者相等 也将运算符入栈s1 
          4.3 否则 将s1栈顶的运算符弹出并压入到s2中 再次判断当前符号与现在s1栈中新的栈顶符号的优先级 
       重复操作步骤4
        5.遇到括号的时候 
          5.1 如果是右括号")" 则直接入栈 
          5.2 如果是左括号"(" 则依次弹出s1栈顶的元素并压入s2 直到遇到右括号"("为止  
              并且这对括号要被丢弃 
        6.重复上面的步骤 直到表达式被扫描完毕 
        7.将s1栈中剩余的运算符依次弹出并压入s2 
        8.将s2中的元素依次弹出 结果即为中缀表达式对应的前缀表达式

栈的定义:

typedef char Elemtype;

//符号栈
typedef struct seqstack1
{
    Elemtype ** elem;//指向栈本体,二级指针,栈的元素是字符串
    int top;   //栈顶下标
    int max_len; //最长
}Seqstack1;

主函数:

#include "seqstack.h"
#include <stdio.h>
#include <stdlib.h>

int main()
{
    char* str;
    MidTofront();
}

功能函数:

#define len_max 100
//此函数是整个操作过程
int MidTofront(void)
{
    //初始化
    Seqstack1* s1 = InitStack(len_max);
    Seqstack1* s2 = InitStack(len_max);
    int i;
    char* outstr;
    //输入中缀表达式
    printf("请输入中缀表达式\n");
    char str_buf[len_max];
    for(i=0;i<len_max;i++)
    {
        scanf("%c",&str_buf[i]);
        if(str_buf[i] == '#')
        {
            str_buf[i] = '\0';
            break;
        }
    }
    //用一个指针指向整个式子的最后一个
    i--;      //将i移至中缀表达式的最后一个也就是指针指向最后一个

    //从后往前扫描
    while(i>=0)//从最后一个扫描到第一个
    {
        char scan_buf[10];
        int sort = 0;//为1是代表输入字符为数字,为2时代表输入字符为符号
        //两种可能
        //扫描到数字
        if(ScanNumisOk(str_buf[i]))
        {
            int j;
            for(j=0;ScanNumisOk(str_buf[i]);i--,j++)    //这个方法会把数字放反,存进去之前需要把scanf数组中的内容倒置一下是正常的
            {
                scan_buf[j] = str_buf[i];
            }
            scan_buf[j] = '\0';
            j--;//让j指向这个数字的最后一位
            //倒置
            int temp;
            for(int k=0;k < (j/2)+1;k++)
            {
                temp = scan_buf[k];
                scan_buf[k] = scan_buf[j-k];
                scan_buf[j-k] = temp;
            }
            sort = 1;
        }
        //提取数字完成
        //扫描到运算符(包括括号)
        else if(ScanSymbolisOk(str_buf[i]))
        {
            scan_buf[0] = str_buf[i];
            scan_buf[1] = '\0';
            sort = 2;
            i--;
        }
        //都不是就是输入错误
        else 
        {
            printf("输入错误!!!\n");
            return 0;
        }
        //提取符号完成
        printf("输入:%s\n",scan_buf); //测试提取的数字是否符合标准
        //将扫描到的数据整理好后放入入栈函数 
        //进栈并判定是否入栈成功

        if(MTFenstack(s1,s2,scan_buf,sort) == 0)
        {
            printf("错误!!!\n");
            return 0;
        } 
    }
     收尾
     将s1剩下的出栈到s2中
    char b1[10];
    while(StackIsEmpty(s1) == 0)
    {
        Pop(s1,b1);
        Push(s2,b1);
    }
    //输出
    int k;
    for(k=0;StackIsEmpty(s2) == 0;k++)
    {
        Pop(s2,b1);
        printf("%s ",b1);
    }
}








//此函数是完成规则入栈出栈的操作
//按照规则向a(符号栈) b(数据栈)插入 成功了返回1 失败返回0
int MTFenstack(Seqstack1* s1,Seqstack1* s2,Elemtype* str_in,int s)
{
    if(s1 == NULL || s2 == NULL || str_in == NULL)
    {
        printf("错误!\n");
        return 0;
    }
    char buf[10];//用来中转弹出的字符
    if(s == 1) //为数字
    {
        Push(s2,str_in);

    }
    else if(s == 2) //为符号
    {
        if(str_in[0] == '*' || str_in[0] == '/') //直接入栈
        {
           Push(s1,str_in);
        }
        else if(str_in[0] == '+' || str_in[0] == '-') //如果栈顶的符号不是*/就入栈。否则需要一直出栈直到可以入栈
        {
            if(s1->top > -1)
            { 
                while(*(s1->elem[s1->top]) == '*' || *(s1->elem[s1->top]) == '/') //优先级不够 
                {
                    Pop(s1,buf);
                    Push(s2,buf);
                    if(s1->top == -1)
                    {
                        break;
                    }
                }
            }
            Push(s1,str_in);
        }
        else if(str_in[0] == '=') //等于只能放在栈底,所以需要把所有的符号栈弹出才能进栈
        {
            if(s1->top > -1)
            {
                while(*(s1->elem[s1->top]) == '*' || *(s1->elem[s1->top]) == '/' || *(s1->elem[s1->top]) == '+' || *(s1->elem[s1->top]) == '-') 
                {
                    Pop(s1,buf);
                    Push(s2,buf);
                }
            }
            Push(s1,str_in);
        }
        else if(str_in[0] == ')') //遇到就进栈,且后面的符号直接进栈
        {
            Push(s1,str_in);
        }
        else if(str_in[0] == '(') //遇到就直接一直出栈,知道遇到)右括号
        {

            while(*(s1->elem[s1->top]) != ')')
            {
                Pop(s1,buf);
                Push(s2,buf);
            }

            Pop(s1,buf);
        }
    }
    return 1;
}





//检测当前扫描的值是否为数字
//是返回1,不是返回0
int ScanNumisOk(char a)
{
    if(a >= '0' && a <= '9')
    {
        return 1;
    }
    return 0;
}





//检测当前扫描的值是否为运算符
//是返回1,不是返回0
int ScanSymbolisOk(char a)
{
    if((a=='+') || (a=='-') || (a=='*') || (a=='/') || (a=='(') || (a==')') || (a=='=')) //遇到括号时,只有可能会遇到左括号
    {
        return 1;
    }
    return 0;
}






//入栈:把一个元素e压入栈中
//成功入栈返回1 失败返回0 
int Push(Seqstack1 * s,Elemtype* e)
{
    if(s == NULL || s->max_len-1 == s->top)
    {
        return 0;
    }
    s->top++;
    s->elem[s->top] = malloc(10*sizeof(Elemtype));
    strcpy(s->elem[s->top],e); 
    return 1;
}





//出栈: 把栈顶元素出栈 并把栈顶元素保存在e指向的空间  
//成功返回1 失败返回0
int Pop(Seqstack1 * s, Elemtype* e)
{
    if(s == NULL)
    {
        return 0;
    }
    strcpy(e,s->elem[s->top]); 
    s->top--;
    return 1;
}





//初始化一个栈 
Seqstack1 * InitStack(int size) //使用满栈
{
    //为所谓的“头结点”申请空间并初始化 
    Seqstack1 * s = malloc(sizeof(Seqstack1));    //为所谓“头结点”申请空间
    s->elem = malloc(size * sizeof(Elemtype**));  //为栈本体申请空间
    s->max_len = size; //创建栈的长度
    s->top = -1; //满栈
    return s;
}


以上就是我的所有有关的代码,有点多。但是逻辑算是清晰的把,没有啥奇招。反正能动。

一下是我的测试结果:

在虚拟机中执行的

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值