数据结构——将中缀表达式转换为后缀表达式并输出(含源码)

前言

最近在学习数据结构(C语言版),碰到了一个题目如下:

栈采用顺序栈存储,试设计算法实现将表达式转换成后缀表达式输出。

例如,输入表达式:      a+b/c-(d*e+f)*g

输出其后缀表达式:abc/+de*f+g*-

代码在VS2022中编写的,X64平台,C语言编写,使用了&引用形式,所以在.cpp中运行。代码不一定是最好的,但是可以正常编译与使用的,仅是我个人的一点思考、个人原创,欢迎批评指正与交流讨论。

原理

一.理解后缀表达式的算法:

以题目中的表达式为例:a+b/c-(d*e+f)*g

先算括号内的,且乘除法运算顺序高于加减,可以得到 de*,并将其看作一个整体;

然后继续看括号内,可以得到de*f+,又将其看作一个整体;

之后因为计算机读取顺序是从左往右,所以可以得到bc/,将其看作一个整体;

类似得到abc/+;

de*f+g*;

abc/+de*f+g*-

二.理解栈的特性:

栈是一种特殊且重要的数据存储结构,具有后进先出的特点,关于栈的操作包括:构建栈结构体,初始化栈,出栈,入栈,取栈中元素等。

本题目要求的是使用顺序栈。

栈的运用有:函数的嵌套调用,递归的实现(比如汉诺塔问题),回文问题,多进制的转换,表达式求值,著名的地图四染色问题,迷宫问题等。

三.问题求解:

1.构建栈结构体

//栈结构体
typedef char elem_type;
typedef struct Stack
{
    elem_type* base;
    elem_type* top;
    int stack_size;
}Stack;

2.初始化栈

使用malloc函数动态开辟内存,并将栈头指针(S.top)与栈尾指针(S.base)对齐。

//栈的初始化函数
int InitStack(Stack& S)
{
    S.base = (elem_type*)malloc(INIT_SIZE * sizeof(elem_type));
    if (!S.base)
        return 0;
    S.top = S.base;
    S.stack_size = INIT_SIZE;
    return 1;
}

3.出栈与入栈

此处注意两个点:

(1)出栈语句中e=*--S.top

*与--优先级相同,优先级相同时则分析结合方向,单目运算结合方向为从右向左,且前置减减为“先减后赋值”。

即该语句等价为:

S.top=S.top-1;

e=*S.top;

入栈语句类似分析

(2)realloc函数的使用,可自行回顾,此处不再赘述

//出栈函数
int OutStack(Stack& S,elem_type &e)
{
    if (S.base==S.top)
    {
        return 0;
    }
    e = *--S.top;
    return 1;
}


//入栈函数
int InStack(Stack& S, elem_type e)
{
    if (S.top-S.base==S.stack_size)
    {
        S.base = (elem_type*)realloc(S.base,(S.stack_size+ ADD_SIZE) * sizeof(elem_type));
        if (!S.base)
        {
            return 0;
        }
        S.top = S.base + S.stack_size;
        S.stack_size += ADD_SIZE;
    }
    *S.top++ = e;
    return 1;
}

4.符号的优先级比较函数

input为当前读取的符号,curtop为当前符号栈中栈顶的符号。

看不太懂没关系,请移步主函数

//符号优先级比较函数
elem_type Compare(elem_type curtop, elem_type input)
{
    elem_type order='\0';
    switch (input)
    {
    case'+':
    case'-':
        switch (curtop)
        {
        case'+':case'-':case'*':case'/':case')':
            order = '>';
            break;
        case'(':case'#':
            order = '<';
            break;
        }
        break;
    case'*':
    case'/':
        switch (curtop)
        {
        case'+':case'-':case'(':case'#':
            order = '<';
            break;
        case'*':case'/':case')':
            order = '>';
            break;
        }
        break;
    case'(':
        switch (curtop)
        {
        case'+':case'-':case'*':case'/': case'(':case'#':
            order = '<';
            break;
        }
        break;
    case')':
        switch (curtop)
        {
        case'+':case'-':case'*':case'/':case')':
            order = '>';
            break;
        case'(':
            order = '=';
            break;
        }
        break;
    case'#':
        switch (curtop)
        {
        case'+':case'-':case'*':case'/':case')':
            order = '>';
            break;
        case'#':
            order = '=';
            break;
        }
        break;
    }
    return order;
}

5.核心算法(主函数)

我的想法是:

(1)将要转化的字符串从键盘读入字符数组c

(2)构建并初始化两个栈,即数据栈Data(负责存放字母)、符号栈Symbol(负责存放符号)

(3)在c中为字符串首尾分别添加一个‘#’符号,便于判断表达式是否结束

(4)从左向右一个个读取c中添加了‘#’的字符串,将字符与字母分别存放入对应栈,并将当前读取的符号input,与当前符号栈中栈顶的符号curtop进行优先级比较,通过判断返回的‘>’'<''='符号来对符号进行出入栈的操作。将符号入栈到Data栈中,最后从Data栈尾到栈顶为我们需要的输出结果。

int main()
{
    Stack Symbol, Data;
    elem_type* p;
    char c[NUM] = "\0";//字符串数组中全部初始化为符号0,便于之后识别
    int i = 0;
    int j;
    elem_type curtop, input, answer, flag;
    
    //从键盘读取字符串表达式
    printf("请输入要转化的中缀表达式:\n");
    scanf("%s", c);

    /*
    printf("测试0:\n");
    printf("%s\n", c);
    */

    //栈的初始化
    InitStack(Symbol);
    InitStack(Data);
    

    while (c[i]!='\0')//统计有多少个字符
    {
        i++;
    }
    //将数组整体向后移一个
    for ( j = i-1; j >= 0; j--)
    {
        c[j + 1] = c[j];
    }
    c[0] = '#';//给字符串首追加一个#号
    c[i+1] = '#';//给字符串末尾追加一个#号

    /*
    printf("测试1:\n");
    printf("%s\n", c);
    */

    i = 0;
    while (c[i]!='\0')
        {
            if (c[i] == '+' || c[i] == '-' || c[i] == '*' || c[i] == '/' || c[i] == '(' || c[i] == ')'||c[i]=='#')//如果是运输符号,则入符号栈
            {
                if (Symbol.top-Symbol.base==0)//第一个符号一定入符号栈
                {
                    InStack(Symbol, c[i]);
                }
                else
                {
                        input = c[i];
                        curtop = *(Symbol.top - 1);
                        answer = Compare(curtop, input);

                        if (answer == '<')//如果输入符号比当前栈顶符号优先级高,则输入符号入栈
                            InStack(Symbol, c[i]);

                        else if (answer == '>')//如果输入符号比当前栈顶符号优先级低,则栈顶符号入数据栈,并从符号栈出
                        {
                            curtop = *(Symbol.top - 1);
                            answer = Compare(curtop, input);
                            while (answer == '>'||answer=='=')//连续与之后的符号比较
                            {
                                InStack(Data, curtop);
                                OutStack(Symbol, curtop);
                                curtop = *(Symbol.top - 1);
                                answer = Compare(curtop, input);
                                if (answer=='<')
                                {
                                    InStack(Symbol, input);
                                }
                                if (answer=='=')
                                {
                                    OutStack(Symbol, curtop);//消括号,消#号
                                    answer = '<';
                                }
                            }
                        }
                }
            }
            else//如果是字母,则入数据栈
                InStack(Data, c[i]);

            i++;
        }
        
    /*
    printf("测试2:\n");
    while (Data.top-Data.base!=0)
        printf("%c", *(--Data.top));
    */

    printf("\n转化的后缀表达式为:\n");
    while (Data.base!=Data.top)
    {
        printf("%c", *(Data.base++));//为了方便我直接从保存最终字符串的数据栈的base开始打印
    }

}

6.输出结果

 这是针对本题目的输出结果

后续我进行了其他表达式的检验,输出正确

 

源码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


#define INIT_SIZE 30
#define ADD_SIZE 10
#define NUM 20

//栈结构体
typedef char elem_type;
typedef struct Stack
{
    elem_type* base;
    elem_type* top;
    int stack_size;
}Stack;


//栈的初始化函数
int InitStack(Stack& S)
{
    S.base = (elem_type*)malloc(INIT_SIZE * sizeof(elem_type));
    if (!S.base)
        return 0;
    S.top = S.base;
    S.stack_size = INIT_SIZE;
    return 1;
}

//符号优先级比较函数
elem_type Compare(elem_type curtop, elem_type input)
{
    elem_type order='\0';
    switch (input)
    {
    case'+':
    case'-':
        switch (curtop)
        {
        case'+':case'-':case'*':case'/':case')':
            order = '>';
            break;
        case'(':case'#':
            order = '<';
            break;
        }
        break;
    case'*':
    case'/':
        switch (curtop)
        {
        case'+':case'-':case'(':case'#':
            order = '<';
            break;
        case'*':case'/':case')':
            order = '>';
            break;
        }
        break;
    case'(':
        switch (curtop)
        {
        case'+':case'-':case'*':case'/': case'(':case'#':
            order = '<';
            break;
        }
        break;
    case')':
        switch (curtop)
        {
        case'+':case'-':case'*':case'/':case')':
            order = '>';
            break;
        case'(':
            order = '=';
            break;
        }
        break;
    case'#':
        switch (curtop)
        {
        case'+':case'-':case'*':case'/':case')':
            order = '>';
            break;
        case'#':
            order = '=';
            break;
        }
        break;
    }
    return order;
}


//出栈函数
int OutStack(Stack& S,elem_type &e)
{
    if (S.base==S.top)
    {
        return 0;
    }
    e = *--S.top;
    return 1;
}


//入栈函数
int InStack(Stack& S, elem_type e)
{
    if (S.top-S.base==S.stack_size)
    {
        S.base = (elem_type*)realloc(S.base,(S.stack_size+ ADD_SIZE) * sizeof(elem_type));
        if (!S.base)
        {
            return 0;
        }
        S.top = S.base + S.stack_size;
        S.stack_size += ADD_SIZE;
    }
    *S.top++ = e;
    return 1;
}


int main()
{
    Stack Symbol, Data;
    elem_type* p;
    char c[NUM] = "\0";//字符串数组中全部初始化为符号0,便于之后识别
    int i = 0;
    int j;
    elem_type curtop, input, answer, flag;
    
    //从键盘读取字符串表达式
    printf("请输入要转化的中缀表达式:\n");
    scanf("%s", c);


    //栈的初始化
    InitStack(Symbol);
    InitStack(Data);
    

    while (c[i]!='\0')//统计有多少个字符
    {
        i++;
    }
    //将数组整体向后移一个
    for ( j = i-1; j >= 0; j--)
    {
        c[j + 1] = c[j];
    }
    c[0] = '#';//给字符串首追加一个#号
    c[i+1] = '#';//给字符串末尾追加一个#号


    i = 0;
    while (c[i]!='\0')
        {
            if (c[i] == '+' || c[i] == '-' || c[i] == '*' || c[i] == '/' || c[i] == '(' || c[i] == ')'||c[i]=='#')//如果是运输符号,则入符号栈
            {
                if (Symbol.top-Symbol.base==0)//第一个符号一定入符号栈
                {
                    InStack(Symbol, c[i]);
                }
                else
                {
                        input = c[i];
                        curtop = *(Symbol.top - 1);
                        answer = Compare(curtop, input);

                        if (answer == '<')//如果输入符号比当前栈顶符号优先级高,则输入符号入栈
                            InStack(Symbol, c[i]);

                        else if (answer == '>')//如果输入符号比当前栈顶符号优先级低,则栈顶符号入数据栈,并从符号栈出
                        {
                            curtop = *(Symbol.top - 1);
                            answer = Compare(curtop, input);
                            while (answer == '>'||answer=='=')//连续与之后的符号比较
                            {
                                InStack(Data, curtop);
                                OutStack(Symbol, curtop);
                                curtop = *(Symbol.top - 1);
                                answer = Compare(curtop, input);
                                if (answer=='<')
                                {
                                    InStack(Symbol, input);
                                }
                                if (answer=='=')
                                {
                                    OutStack(Symbol, curtop);//消括号,消#号
                                    answer = '<';
                                }
                            }
                        }
                }
            }
            else//如果是字母,则入数据栈
                InStack(Data, c[i]);

            i++;
        }
        

    printf("\n转化的后缀表达式为:\n");
    while (Data.base!=Data.top)
    {
        printf("%c", *(Data.base++));//为了方便我直接从保存最终字符串的数据栈的base开始打印
    }

}

源码公开,如果对你有帮助,请点赞吧👍

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值