逆波兰表达式

求表达式(1 - 2) * (4 + 5)的值

  • 人类早就熟悉这种中缀表达式的计算公式,随便拉一个小朋友过来,他就直到这个结果是等于-9的,因为括号里面的要先进行计算。
  • 但计算机不喜欢了,因为我们有小括号中括号大括号,还允许一个嵌套一个,这样子计算机就要进行很多次if判断才能决定那里先计算。

逆波兰表达式(后缀表达式)

波兰逻辑学家Jan.Lukasiewicz,发明了一种不需要括号的后缀表达式,我们通常把它称为波兰表达式(RPN)。

  • 上面表达式(1 - 2) * (4 + 5) 的波兰表达式是这样的: 1 2 - 4 5 + *
  • 这种表达式人类是不太好接受的,不过对计算机来说,利用栈的特点,就可以将这种后缀表达式的性能发挥到极致。

用栈来求解表达式(1 - 2) * (4 + 5)的值

  • 数字1和2进栈,遇到减号运算符这弹出两个元素进行运算并把结果入栈。
图片.png
  • 4和5入栈,遇到加号运算符,4和5弹出栈,相加后将结果9入栈。
图片.png
  • 然后又遇到乘法运算符,将9和-1弹出栈进行乘法计算,此时栈空并无数据压栈,-9为最终运算结果。
图片.png
  • 正常的表达式 --->逆波兰表达式
    a + b ---> a b +
    a + (b - c) ---> a b v - +
    a + (b - c) * d ---> a b c - d * +

*代码实现(c语言)

#include<stdafx.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<ctype.h>

#define STACK_INIT_SIZE 20
#define STACKINCREMENT 10
#define MAXBUFFER 10

typedef double ElemType;
typedef struct {
    ElemType *base; //指向栈底的指针
    ElemType *top; //指向栈顶的指针
    int stackSize; //当前可使用的最大容量
}sqStack;

void InitStack(sqStack *s) {
    s->base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
    if (!s->base)
    {
        exit(0);
    }
    s->top = s->base;
    s->stackSize = STACK_INIT_SIZE;
}
//入栈操作要在栈顶进行,每次向栈中压入一个数据,top指针就要+1,直到栈满为止
void Push(sqStack *s, ElemType e) {
    if (s->top - s->base >= s->stackSize)
    {
        s->base = (ElemType *)realloc(s->base, (s->stackSize + STACKINCREMENT) * sizeof(ElemType));
        if (!s->base)
        {
            exit(0);
        }
    }
    *(s->top) = e;
    s->top++;
}
//出栈操作就是在栈顶取出数据,栈顶指针随之下移操作,每当从栈内弹出一个数据,栈的当前容量就-1
void Pop(sqStack *s, ElemType *e) {
    if (s->top == s->base)
    {
        return;
    }
    *e = *--(s->top);
}
//求栈的长度
int StackLen(sqStack s) {
    return s.top - s.base;
}

//清空栈, 将栈中的元素全部作废,但栈本身物理空间并不发生改变(不是销毁)
void ClearStack(sqStack *s) {
    s->top = s->base;
}
//销毁一个栈, 释放掉该栈所占据的物理内存空间
void DestoryStack(sqStack *s) {
    int i, len;
    len = s->stackSize;
    for (i = 0; i < len; i++)
    {
        free(s->base);
        s->base;
    }
    s->base = s->top = NULL;
    s->stackSize = 0;
}

int main() {
    sqStack s;
    char c;
    double d, e;
    char str[MAXBUFFER];
    int i = 0;

    InitStack(&s);
    printf("请按逆波兰表达式输入待计算的数据,数据与运算符之间用空格隔开,以#作为结束标志:");
    scanf_s("%c", &c);
    while (c != '#')
    {
        while (isdigit(c) || c == '.')
        {
            str[i++] = c;
            str[i] = '\0';


            if (i >= 10)
            {
                printf("出错,输入的单个数据过大!\n");
                return -1;
            }
            scanf_s("%c", &c);
            if (c == ' ')
            {
                d = atof(str);
                Push(&s, d);
                i = 0;
                break;
            }
        }


        switch (c)
        {
        case '+':
            Pop(&s, &e);
            Pop(&s, &d);
            printf("****%f***%f\n", e, d);
            Push(&s, d + e);
            break;
        case '-':
            Pop(&s, &e);
            Pop(&s, &d);
            Push(&s, d - e);
            break;
        case '*':
            Pop(&s, &e);
            Pop(&s, &d);
            Push(&s, d * e);
            break;
        case '/':
            Pop(&s, &e);
            Pop(&s, &d);
            if (e != 0)
            {
                Push(&s, d / e);
            }
            else
            {
                printf("\n出错:除数为0!\n");
            }
            break;
        default:
            break;
        }
        scanf_s("%c", &c);
    }
    Pop(&s, &d);
    printf("最终的计算结果是:%f", d);

    getchar();
    getchar();
    getchar();
    return 0;
}

中缀表达式转换成逆波兰表达式

人类喜欢这样的表达式:(1-2)*(4+5)
而不是这样的:1 2 - 4 5 + *

  • 下面我们来动手写一个中缀表达式转换成后缀表达式的计算器:
    转换规则: 从左到右遍历中缀表达式的每个数字和符号,若是数字则直接输出,若是符号,则判断其与栈顶符号的优先级,是右括号或者优先级低于栈顶符号,则栈顶元素依次出栈并输出,直到遇到左括号或栈空才将其入栈。
  • 代码实现
int main() {
    sqStack s;
    char c, e;
    InitStack(&s);
    printf("请输入中缀表达式,以#作为结束标志:");
    scanf_s("%c", &c);
    while (c != '#')
    {
        while (c >= '0' && c < '9')
        {
            printf("%c", c);
            scanf_s("%c", &c);
            if (c < '0' || c > '9')
            {
                printf(" ");
            }
        }

        if(')' == c)
        {
            Pop(&s, &e);
            while ('(' != e)
            {
                printf("%c", e);
                Pop(&s, &e);
            }
        }
        else if('+' == c || '-' == c)
        {
            if (!StackLen(s))
            {
                Push(&s, c);
            }
            else
            {
                do
                {
                    Pop(&s, &e);
                    if ('(' == e)
                    {
                        Push(&s, e);
                    }
                    else
                    {
                        printf("%c", e);
                    }
                } while (StackLen(s) && '(' != e);

                Push(&s, c);
            }
        }
        else if('*' == c || '/' == c || '(' == c)
        {
            Push(&s, c);
        }
        else if('#' == c)
        {
            break;
        }
        else
        {
            printf("\n出错,输入格式错误!\n");
            return -1;
        }
        scanf_s("%c", &c);
    }

    while (StackLen(s))
    {
        Pop(&s, &e);
        printf("%c", e);
    }
     
    getchar();
    getchar();
    getchar();
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容