c++ 数据结构之自定义链式栈、中缀转后缀表达式并计算

中缀表达式转后缀表达式

所谓中缀,即常见的那种表达式,如 8 + ( 3 1 ) × 5
后缀表达式则是计算机内部实际的计算方式,如 831 5 × +

转换方法

对于”8+(3-1)*5”
先创建一个用来保存符号的栈stack
从左开始遍历每个字符:
对于数字
直接输出

对于符号
遇到左括号,进栈

遇到运算符号(+-*/),与栈顶的符号进行优先级比较,如果栈顶的优先级低,符号进栈(默认栈顶若是左括号,左括号优先级最低)。若栈顶符号优先级不低,先将栈顶符号弹出并输出,之后再让当前进栈。

遇到右括号,将栈顶符号弹出并输出,直到匹配左括号。(之后也把左括号弹掉,但不输出到屏幕)

当字符串遍历完毕,把栈中所有符号弹出就结束。


计算后缀表达式

表达式:831-5* +
从左开始遍历每个字符:
对于数字
直接入栈

对于符号
从栈中弹出一个操作数
再从栈中弹出一个操作数
根据符号进行运算(左 符号 右 = 结果
结果压入栈中

当遍历结束,栈中的唯一数字为计算结果。
(注:a+b,a为左操作数,b为右操作数)


实验结果

这里写图片描述


代码示例

#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;

//c++中纯c语法


//---------------------------part1,自定义链式栈的实现
//用链表实现的后入先出的栈

//链表节点
typedef struct LINKNODE
{
    //注意是指针
    struct LINKNODE* next;
}LinkNode;
//栈,每个节点都是一个链表节点
typedef struct STACK
{
    LinkNode head;
    int size;
}Stack;
//自定义一个数据类型,且第一个元素放节点指针,也就是Person* 和 LinkNode*可以无缝互转
typedef struct PERSON
{
    LinkNode *node;
    int age;
    char name[64];
}Person;
//创建一个空栈
Stack* init()
{
    Stack* stack = (Stack*)malloc(sizeof(Stack));
    stack->size = 0;
    stack->head.next = NULL;
}

//push,栈底在最后面栈顶和head连在一起
void push(Stack* stack,LinkNode* data)
{
    if(stack==NULL || data == NULL)
    {
        return;
    }
    data->next = stack->head.next;
    stack->head.next = data;
    //每次记得size+1啊
    stack->size ++;
}
//获得栈顶
LinkNode* top(Stack* stack)
{
    if(stack==NULL || stack->size == 0)
    {
        return NULL;
    }
    return stack->head.next;
}
//出栈
void pop(Stack* stack)
{
    if(stack==NULL || stack->size ==0)
    {
        return;
    }
    stack->head.next = stack->head.next->next;
    //这里之前忘记--了
    stack->size --;
}
//栈是否为空
int isEmpty(Stack* stack)
{
    //注意了,是0返回1
    if(stack->size == 0)
    {
        return 1;
    }
    return 0;
}
//测试栈
void test()
{
    Stack* stack = init();
    Person p1;
    Person p2;
    Person p3;
    Person p4;
    Person p5;
    printf("test\n");
    strcpy(p1.name,"aaa");
    strcpy(p2.name,"bbb");
    strcpy(p3.name,"ccc");
    strcpy(p4.name,"ddd");
    strcpy(p5.name,"eee");
    p1.age = 1;
    p2.age = 2;
    p3.age = 3;
    p4.age = 4;
    p5.age = 5;
    push(stack,(LinkNode*)&p1);
    push(stack,(LinkNode*)&p2);
    push(stack,(LinkNode*)&p3);
    push(stack,(LinkNode*)&p4);
    push(stack,(LinkNode*)&p5);
    //后入先出
    for(int i = 0;i<5;i++)
    {
        printf("%d:%s\n",((Person*)top(stack))->age,((Person*)top(stack))->name);
        pop(stack);

    }
}

//---------------------------part2,中缀表达式转后缀


//一个用来存放临时的运算符,包括括号,+-*/
typedef struct MYDATA
{
    LinkNode* node;
    char c;
}MyData;

//判断是左括号
int isLeft(char c)
{   
    if(c=='(')
        return 1;
    return 0;
}
//判断右括号
int isRight(char c)
{   
    if(c==')')
        return 1;
    return 0;
}
//是否是数字
int isDigital(char c)
{
    if(c>='0' && c<='9')
    {
        return 1;
    }
    return 0;
}
//看看是否是运算符
int isOperator(char c)
{
    if(c=='+' ||c=='-' ||c=='*' ||c=='/')
    {
        return 1;
    }
    return 0;
}
//看看栈顶符号的优先级
int getPriority(char c)
{
    if(c=='+' ||c=='-')
    {
        return 1;
    }
    if(c=='*' ||c=='/')
    {
        return 2;
    }
}
//自己弄的打印
void print(char c)
{
    printf("%c",c);
}
//快速把一个字符变成栈顶
LinkNode* operatorNode(char c)
{
    MyData* data = (MyData*)malloc(sizeof(MyData));
    data->c = c;
    return (LinkNode*)data;
}
//提取栈顶元素中的字符
char extractTopChar(Stack* stack)
{
    return ((MyData*)top(stack))->c;
}

void test2()
{
    //char* str = "(8+(((3-1))*5))";//answer 831-5*+
    char* str = "1+(3*2+1*3+(5*1))";
    char* p = str;
    Stack* stack = init();
    printf("中缀表达式%s转成后缀表达式是:",str);
    while(*p!='\0')
    {
        if(isDigital(*p))
        {
            //数字直接打印
           print(*p); 
        }
        if(isLeft(*p))
        {
            //遇到左括号直接入栈
            push(stack,operatorNode(*p));
        }
        if(isRight(*p))
        {
    //printf("test\n");
            //如果是右括号,直接弹出所有栈顶元素,直到遇到左括号
            while(extractTopChar(stack)!='(')
            {
                print(extractTopChar(stack));
                pop(stack);
            }
            //把剩下的左括号也弹掉
            pop(stack);
        }
        if(isOperator(*p))
        {
            //原本的栈是空的或者是左括号直接入栈
            if(isEmpty(stack) || isLeft(extractTopChar(stack)))
            {
                push(stack,operatorNode(*p));
            }
            //还要看看栈顶是不是加减符号,不然没什么好比的
            else if(isOperator(extractTopChar(stack)))
            {
                //若栈顶的优先级较低,新来的符号入栈
                if(getPriority(*p)>getPriority(extractTopChar(stack)))
                {
                    push(stack,operatorNode(*p));
                }else
                {
                    //否则要先出栈输出再入栈
                    print(extractTopChar(stack));
                    pop(stack);
                    //入栈
                    push(stack,operatorNode(*p));
                }
            }
        }
        p++;
    }
    //把栈剩余的内容都打印出来
    while(!isEmpty(stack))
    {
        print(extractTopChar(stack));
        pop(stack);
    }
    printf("\n");
}


//---------------------------part3,求解后缀表达式的值
//简要原理,数字就压栈,遇到运算符,就出栈顶当右值,再出一次栈顶当左值
//计算后再放回去,一直到把表达式字符串遍历完,栈中剩余的元素就是最终的结果
int calc(char oper,int right,int left)
{   
    //int right = rightVal - '0';
    //int left = leftVal - '0';
    switch(oper)
    {
        case '+':return left+right;
        case '-':return left-right;
        case '*':return left*right; 
        case '/':return right==0?-10086:(left/right); 
    }
}

//栈的数据节点稍微要改下,不是存char了,是int
typedef struct DATA
{
    LinkNode* node;
    int val;
}Data;

LinkNode* dataNode(int val)
{
    Data* data = (Data*)malloc(sizeof(Data));
    data->val = val;
    return (LinkNode*)data;
}

int extractTopInt(Stack* stack)
{
    return ((Data*)(top(stack)))->val;
}

void test3()
{
    //char* str = "831-5*+";
    char* str = "132*13*51*+++";
    //主要是拷贝一份,避免在原有数据上改
    char* p = str;
    //栈的主力军变成int,part2是运算符
    Stack* stack = init();
    while(*p!='\0')
    {
        if(isDigital(*p))
        {
            int val = *p - '0';
            push(stack,dataNode(val)); 
        }
        if(isOperator(*p))
        {
            int rightVal = extractTopInt(stack);
            pop(stack);
            int leftVal = extractTopInt(stack);
            pop(stack);
            push(stack,dataNode(calc(*p,rightVal,leftVal)));
        }
        p++;
    }
    if(!isEmpty(stack))
    {
        printf("后缀表达式%s的计算结果是:%d\n",str,extractTopInt(stack));
    }
}

int main()
{
    //test();//测试栈
    test2();//中缀变后缀
    test3();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hiudawn/article/details/80195174