C++中缀表达式转后缀表达式代码及思路

转换过程

下面的 输出 一词表示将该值存起来(保存到要求的结果中),压栈 就是入栈的意思。
①遇到操作数直接输出
②遇到操作符:分以下几种情况
1.栈为空时: 无论操作符是什么,直接压栈
2.新的操作符优先级比栈顶的高: 直接压栈(优先级: 括号 > * / > + -)
3.新操作符是左括号: 直接压栈,且左括号只有在有右括号操作符时才出栈。
4.新操作符是右括号: 右括号不入栈,从栈顶开始出栈并输出,直到碰到左括号才停下来(包括左括号也出栈,但是不输出),且一个右括号只能对应一个左括号,不能多出。
5.新的操作符优先级比栈顶的低或者相同: 栈顶开始出栈并输出,直到出现比新操作符优先级低的位置停止(不包括该位置)或者栈空了,或者遇到了左括号停止。
③最后将栈的数据一次输出。

本人思路

这过程中有一个重要的概念就是优先级,所以我定义了操作符的优先级数据:
操作数优先级为-1, + - 优先级为 0, * / 优先级为 1,左括号优先级为2, 右括号优先级为3(因为右括号优先级如果也为2的话,就没法区分是左括号还是右括号,这是个有影响的),函数如下:

// 返回优先级(+-为0,*/为1, ()为2, 3)
int retPriority(char c)
{
    int temp = -1;
    switch (c)
    {
    case '+': case '-':
        temp = 0;
        break;
    case '*': case '/':
        temp = 1;
        break;   
    case '(':
        temp = 2;
        break;   
    case ')': 
        temp = 3;
        break;            
    default:
        temp = -1;
    }
    return temp;
}

然后有了优先级之后,直接按照上面的转换过程,直接撸代码就哦了。

准备下基本数据

1.先准备下结点的结构。

struct ListNode
{
    char data;
    ListNode* next;
};

我下面的操作都是带头结点的链表。

2.1栈的基本操作(初始化)

// 初始化 栈
void InitStack(ListNode* &head)
{
    ListNode* start = new ListNode;  // 创建一个头结点
    start->data = '#';
    start->next = nullptr;
    head = start;
}

2.2栈的基本操作(入栈)

// 入栈(带头结点的链表)
bool PushStack(ListNode* &head, char &data)
{
    if (!head) return false;   
    ListNode* temp = new ListNode;
    temp->data = data;
    temp->next = head->next;
    head->next = temp;
    return true;
}

2.3栈的基本操作(出栈)

// 出栈(带头结点的链表)
bool PopStack(ListNode* &head, char &data)
{
    if (!head || !head->next) return false;
    ListNode *p = head->next;
    data = p->data;
    head->next = p->next;
    delete p;
    return true;
}

2.4栈的基本操作(是否为空)

// 栈是否为空
bool isEmpty(ListNode* &head)
{
    if(!head->next) return true;
    return false;
}

2.5栈的基本操作(查看栈顶值)

// 查看栈顶值
bool TopStack(ListNode* &head, char &data)
{
    if (!head || !head->next) return false;
    data = head->next->data;
    return true;
}

2.6链表的销毁

// 销毁链表
void DestroyListNode(ListNode* &L)
{
    if (!L) return;
    ListNode* pNext = L->next;
    while (pNext != nullptr)
    {
        delete L;
        L = pNext;
        pNext = L->next;
    }

    delete L;
    L = nullptr;  
}

3.main函数的测试数据

int main()
{
    /* *****************************************************************
    *  构造一个 链表 
    */
    cout << "请输入中缀表达式(结尾加$):"; // $作为输入的结束符号,不会保存或参与运算
    char tmp;

    ListNode* head = new ListNode;
    head->data = '#';
    head->next = nullptr;  // 这个是保存 中缀表达式 链表的头结点
    ListNode* p = head;

    while (cin >> tmp && tmp != '$')
    {
        ListNode* ac = new ListNode;
        ac->data = tmp;
        ac->next = nullptr;
        p->next = ac;
        p = p->next;
    } // 把输入存入链表
    vector<char> result;        // 结果保存到这里
    /*
    *   midToBehind 只是实现了表达式的处理例如:A * (B-C) + D
    *   每一个操作数都是一个字符表示的,不能输入具体的超过9的具体值
    *   比如: 12 + 123 * (45 - 2 * 63) 这种是不行的
    */
    midToBehind(head, result);  // 这里是我们要编写的转换函数
    cout << "计算结果为:";
    if (!result.empty())
    {
        for(const auto &c : result)
        {
            cout << c << " ";
        }
    }  // 这里输出结果

    return 0;
}

编写 midToBehind函数

/*
*   midToBehind 只是实现了表达式的处理例如:A * (B-C) + D
*   每一个操作数都是一个字符表示的,不能输入具体的超过9的具体值
*   比如: 12 + 123 * (45 - 2 * 63) 这种是不行的
*/

下面的代码逻辑,就是上面的转换过程(注释写的比较详细):

// 中缀表达式转后缀表达式
bool midToBehind(ListNode* head, vector<char> &data)
{
    if (!head || !head->next) return false;
    int maxLength = -1;  // 曾经用过的最大栈深度
    char temp;  // 临时存储栈顶元素的值
    // 新建一个临时栈用来 保存操作符
    ListNode* saveOperator = nullptr;
    InitStack(saveOperator); // 初始化栈
    ListNode *start = head->next;
    while (start)
    {
    	maxLength = maxLength < StackLength(saveOperator) ? StackLength(saveOperator) : maxLength;
        if (retPriority(start->data) == -1) data.push_back(start->data); // 操作数直接输出
        else if (!isEmpty(saveOperator))  // 栈是否为空
        {
            TopStack(saveOperator, temp);  // 查看栈顶元素是啥
            int priStarck = retPriority(temp); // 栈顶元素优先级
            int newDataPri = retPriority(start->data); // 新来操作符的优先级

            if (newDataPri > priStarck)  // 新来的优先级高的话
            {
                if (newDataPri == 3)  // 看是不是右括号来了,如果是,出栈一直出到遇到第一个左括号
                {
                    bool isRun = true;
                    while (isRun)
                    {
                        if (retPriority(temp) == 2) isRun = false;  // 遇到了第一个左括号
                        PopStack(saveOperator, temp);
                        if (temp != '(') data.push_back(temp);  // 出栈并输出,左括号也出栈,但是不输出
                        TopStack(saveOperator, temp);   // 重新查看栈顶元素
                    }  
                }
                else PushStack(saveOperator, start->data); // 如果新来的不是右括号直接压栈
            }
            else if (newDataPri == priStarck) // 如果和栈顶拥有相同的优先级
            {
                // 优先级相同,看是不是左括号(左括号比较特殊,因为上面还有左括号的话是不出栈的,但是假如新来的操作符是+,栈顶也是+,就得出栈)
                if (newDataPri == 2) PushStack(saveOperator, start->data); // 是的话,直接压栈
                else
                {
                    PopStack(saveOperator, temp);
                    data.push_back(temp);
                    PushStack(saveOperator, start->data);
                }  // 不是,就栈顶出栈, 新操作符压栈
            }
            else  // 新来的优先级小,这个要一直出栈,出到更小的优先级或者空栈为止
            {
                if (priStarck != 2)  // 看栈顶是不是左括号,不是的话才出栈,是的话就直接入栈
                {
                    while (1)  // 一直出栈,出到更小的优先级或者空栈为止
                    {
                        // 如果栈顶优先级小了、栈空了,栈顶是左括号(因为左括号必须有右括号才能出栈)则停止出栈
                        if (newDataPri > retPriority(temp) || isEmpty(saveOperator) || retPriority(temp) == 2) break;  
                        PopStack(saveOperator, temp);
                        data.push_back(temp);
                        if (!TopStack(saveOperator, temp)) break;  // 如果栈顶没有值了就表示,栈空了。
                    } 
                } 
                PushStack(saveOperator, start->data); // 最后把别人弹出去了,不能忘了把新操作符自己压进去
            }
        }
        // 栈为空时,直接入栈
        else PushStack(saveOperator, start->data);
        start = start->next;
    }

    // 最后把栈里面的数据都弹出来
    while (!isEmpty(saveOperator))
    {
        PopStack(saveOperator, temp);
        data.push_back(temp);
        if (!TopStack(saveOperator, temp)) break;
    }
    DestroyListNode(saveOperator);  // 清除栈
    cout << "曾经用过最大的栈的深度为:" << maxLength << endl;
    return true;
}

完整代码

下面这是直接可以跑的C++完整代码:

#include <vector>
#include <iostream>
using namespace std;

struct ListNode
{
    char data;
    ListNode* next;
};
// 栈是否为空
bool isEmpty(ListNode* &head)
{
    if(!head->next) return true;
    return false;
}
// 初始化 栈
void InitStack(ListNode* &head)
{
    ListNode* start = new ListNode;  // 创建一个头结点
    start->data = '#';
    start->next = nullptr;
    head = start;
}
// 压栈(带头结点)
bool PushStack(ListNode* &head, char &data)
{
    if (!head) return false;
    ListNode* temp = new ListNode;
    temp->data = data;
    temp->next = head->next;
    head->next = temp;
    return true;
}
// 出栈(带头结点)
bool PopStack(ListNode* &head, char &data)
{
    if (!head || !head->next) return false;
    ListNode *p = head->next;
    data = p->data;
    head->next = p->next;
    delete p;
    return true;
}
// 查看栈顶值
bool TopStack(ListNode* &head, char &data)
{
    if (!head || !head->next) return false;
    data = head->next->data;
    return true;
}
// 栈深度
int StackLength(ListNode* &head)
{
    if (!head || !head->next) return -1;
    int length = 0;
    ListNode* start = head->next;
    while (start)
    {
        length++;
        start = start->next;
    }
    return length; 
}
// 销毁链表
void DestroyListNode(ListNode* &L)
{
    if (!L) return;
    ListNode* pNext = L->next;
    while (pNext != nullptr)
    {
        delete L;
        L = pNext;
        pNext = L->next;
    }

    delete L;
    L = nullptr;  
}

// 返回优先级(+-为0,*/为1, ()为2, 3)
int retPriority(char c)
{
    int temp = -1;
    switch (c)
    {
    case '+': case '-':
        temp = 0;
        break;
    case '*': case '/':
        temp = 1;
        break;   
    case '(':
        temp = 2;
        break;   
    case ')': 
        temp = 3;
        break;            
    default:
        temp = -1;
    }
    return temp;
}
// 中缀表达式转后缀表达式
bool midToBehind(ListNode* head, vector<char> &data)
{
    if (!head || !head->next) return false;
    int maxLength = -1;  // 曾经用过的最大栈深度
    char temp;  // 临时存储栈顶元素的值
    // 新建一个临时栈用来 保存操作符
    ListNode* saveOperator = nullptr;
    InitStack(saveOperator); // 初始化栈
    ListNode *start = head->next;
    while (start)
    {
    	maxLength = maxLength < StackLength(saveOperator) ? StackLength(saveOperator) : maxLength;
        if (retPriority(start->data) == -1) data.push_back(start->data); // 操作数直接输出
        else if (!isEmpty(saveOperator))  // 栈是否为空
        {
            TopStack(saveOperator, temp);  // 查看栈顶元素是啥
            int priStarck = retPriority(temp); // 栈顶元素优先级
            int newDataPri = retPriority(start->data); // 新来操作符的优先级

            if (newDataPri > priStarck)  // 新来的优先级高的话
            {
                if (newDataPri == 3)  // 看是不是右括号来了,如果是,出栈一直出到遇到第一个左括号
                {
                    bool isRun = true;
                    while (isRun)
                    {
                        if (retPriority(temp) == 2) isRun = false;  // 遇到了第一个左括号
                        PopStack(saveOperator, temp);
                        if (temp != '(') data.push_back(temp);  // 出栈并输出,左括号也出栈,但是不输出
                        TopStack(saveOperator, temp);   // 重新查看栈顶元素
                    }  
                }
                else PushStack(saveOperator, start->data); // 如果新来的不是右括号直接压栈
            }
            else if (newDataPri == priStarck) // 如果和栈顶拥有相同的优先级
            {
                // 优先级相同,看是不是左括号(左括号比较特殊,因为上面还有左括号的话是不出栈的,但是假如新来的操作符是+,栈顶也是+,就得出栈)
                if (newDataPri == 2) PushStack(saveOperator, start->data); // 是的话,直接压栈
                else
                {
                    PopStack(saveOperator, temp);
                    data.push_back(temp);
                    PushStack(saveOperator, start->data);
                }  // 不是,就栈顶出栈, 新操作符压栈
            }
            else  // 新来的优先级小,这个要一直出栈,出到更小的优先级或者空栈为止
            {
                if (priStarck != 2)  // 看栈顶是不是左括号,不是的话才出栈,是的话就直接入栈
                {
                    while (1)  // 一直出栈,出到更小的优先级或者空栈为止
                    {
                        // 如果栈顶优先级小了、栈空了,栈顶是左括号(因为左括号必须有右括号才能出栈)则停止出栈
                        if (newDataPri > retPriority(temp) || isEmpty(saveOperator) || retPriority(temp) == 2) break;  
                        PopStack(saveOperator, temp);
                        data.push_back(temp);
                        if (!TopStack(saveOperator, temp)) break;  // 如果栈顶没有值了就表示,栈空了。
                    } 
                } 
                PushStack(saveOperator, start->data); // 最后把别人弹出去了,不能忘了把新操作符自己压进去
            }
        }
        // 栈为空时,直接入栈
        else PushStack(saveOperator, start->data);
        start = start->next;
    }

    // 最后把栈里面的数据都弹出来
    while (!isEmpty(saveOperator))
    {
        PopStack(saveOperator, temp);
        data.push_back(temp);
        if (!TopStack(saveOperator, temp)) break;
    }
    DestroyListNode(saveOperator);  // 清除栈
    cout << "曾经用过最大的栈的深度为:" << maxLength << endl;
    return true;
}

int main()
{
    /* *****************************************************************
    *  构造一个 链表 
    */
    cout << "请输入中缀表达式(结尾加$):"; // $作为输入的结束符号,不会保存或参与运算
    char tmp;

    ListNode* head = new ListNode;
    head->data = '#';
    head->next = nullptr;  // 这个是保存原表达式链表的头结点
    ListNode* p = head;

    while (cin >> tmp && tmp != '$')
    {
        ListNode* ac = new ListNode;
        ac->data = tmp;
        ac->next = nullptr;

        p->next = ac;
        p = p->next;
    } // 把输入存入 链表
    // PrintListNode(head);

    vector<char> result;
    /*
    *   midToBehind 只是实现了表达式的处理例如:A * (B-C) + D
    *   每一个操作数都是一个字符表示的,不能输入具体的超过9的具体值
    *   比如: 12 + 123 * (45 - 2 * 63) 这种是不行的
    */
    midToBehind(head, result);  // 这里是我们要编写的转换函数
    cout << "计算结果为:";
    if (!result.empty())
    {
        for(const auto &c : result)
        {
            cout << c << " ";
        }
    }  // 这里输出结果

    return 0;
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值