C语言实现表达式求值,支持+、-、*、/四则运算,并且支持多级括号,自定义了栈的操作。

来源:互联网 发布:三维建筑物重建软件 编辑:程序博客网 时间:2024/05/23 11:26
<span style="color: rgb(51, 255, 51); font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">以下是代码的实现使用gcc已经成功运行了,下面是效果图</span>

#include <stdio.h>#include <stdlib.h>#define N 50        //定义接收字符串大小typedef struct _node_ {    int num_ch;     //数字和符号都用int存储    struct _node_ *next;}node;/***  创建一个链栈**  注意我的栈最后一个元素无意义但必须存在**  因为方便在表达式末尾进行操作*/node *CreatNode(){    node *head = (node *)malloc(sizeof(node));    if(NULL == head) return NULL;    head->num_ch = 0;    head->next = NULL;    return head;}/***  压栈**  直接给最后一个元素赋值**  并新建一个无意义的结点作为最后元素*/int push(node *p,int num){    while(NULL != p->next) {        p = p->next;    }    p->num_ch = num;    node *q = (node *)malloc(sizeof(node));    q->num_ch = 0;    q->next = NULL;    p->next = q;    return 0;}/***  弾栈**  最后一个无意义的直接free**  倒数第二个next置空,返回倒数第二的值*/int pop(node *p){    int tmp;    if(NULL == p->next) return -1;//只有头,无值时无法pop    while(NULL != p->next->next) {        p = p->next;    }    tmp = p->num_ch;    free(p->next);    p->num_ch = 0;    p->next = NULL;    return tmp;}/***  获取栈顶元素*/int gettop(node *p){while(NULL != p->next->next) {p = p->next;}return p->num_ch;}/***  判栈空**  如果只剩一个结点(这是个无意义的)**  那么就为空*/int isEmpty(node *p){    if(NULL == p->next) return 1;    return 0;}/***  显示栈的所有元素*/void show(node *p){    if(NULL == p->next) return;//只有头,无值时无法pop    while(NULL != p->next) {        printf("%d,",p->num_ch);        p = p->next;    }    putchar(10);}/***  计算int变量的长度**  例如1234长度为4*/int sum_int(int in){    int len=0;    while(0 != in) {        len++;        in /= 10;    }    return len;}/***  符号优先级判断**  返回: 1(opt1>opt2)   -1(opt1<opt2)   0(opt1=opt2)**  注意符号的ASSIC码:43(+) 45(-) 42(*) 47(/)*/int opt_max(int opt1,int opt2){    if(42 == opt1 || 47 == opt1) {        if(43 == opt2 || 45 == opt2) {            return 1;        }        return 0;    } else {        if(42 == opt2 || 47 == opt2) {            return -1;        }        return 0;    }}/***  计算a和b在mode符号的运算结果*/int cal(int a,int b,int mode){    int re = -1;    switch(mode) {    case 43:re = a + b;break;    case 45:re = a - b;break;    case 42:re = a * b;break;    case 47:re = a / b;break;    default:           break;    }    return re;}/***  计算表达式的值**  核心关键*/int cal_str(char *str){int num1,num2,opt1,opt2;node *num,*opt;num = CreatNode();  //创建数字栈opt = CreatNode();  //创建符号栈while( 1 ) {if('\0' == *str) {// 读到字符串末尾            /*            **  如果最后一个符号是*或/则会剩下三个数字和两个符号            **  如果最后一个符号时+或-则会剩下两个数字和一个符号            **  结果只是算两次和算一次的问题            */    opt1 = gettop(opt);    if((42 == opt1) || (47 == opt1)) {        num2 = pop(num);                num1 = pop(num);                opt2 = pop(opt);                push(num, cal(num1, num2, opt2));    }    num2 = pop(num);            num1 = pop(num);            opt2 = pop(opt);            num1 = cal(num1, num2, opt2);    break;} else if('(' == *str) {// 读到(,注意压栈的时(的ASSIC码40    push(opt, (int)'(');    str++;} else if(')' == *str) {// 只是判断)不压入栈    while( 1 ) {// 本循环会计算与)匹配的最近的(地方为之        if(40 == gettop(opt)) {// 如果当前栈顶是(则弾栈退出            pop(opt);            break;        } else {// 否则弾两个数字,一个符号进行运算         // 结果入操作数栈            num2 = pop(num);                    num1 = pop(num);                    opt2 = pop(opt);                    push(num, cal(num1, num2, opt2));        }    }    str++;} else if(('9' >= *str) && ('0' <= *str)) {// 如果取到数字则将数字压入栈    sscanf(str, "%d", &num1);    push(num, num1);    //将指针移动到当前数字到后面    str = str + sum_int(num1);} else {// 取到一个符号    opt1 = (int)*str++;    while(1) {        if( (1 == isEmpty(opt)) || (40 == gettop(opt)) ) {// 如果栈不空则遇到(则压入取到的符号         // 为空时也要压栈            push(opt, opt1);            break;        } else {            //取出符号栈顶元素            opt2 = gettop(opt);                    if(0 < opt_max(opt1,opt2)) {// 当前获取的符号优先级大于栈顶符号                     // 则压栈                        push(opt,opt1);                        break;                    } else {// 栈顶优先级高或者平级则                     // 取两个数和栈顶符号进行运算                        num2 = pop(num);                        num1 = pop(num);                        opt2 = pop(opt);                        push(num, cal(num1, num2, opt2));                    }        }    }}    }    free(num);    free(opt);    return num1;}int main(int argc,char **argv){char buf[N] = {0};scanf("%s", buf); getchar();    printf("%s=%d\n",buf,cal_str(buf));return 0;}


至于原理嘛栈的操作我就不多叙述了。主要讲讲算法的事情,首先计算函数感开始的时候就创建了数字栈和符号栈。处理的时候把所有字符串里取出来的东西都在栈里用整形保存,这样可以统一数字栈和符号栈是同种结构。当遍历字符串时遇到数字字符就把当前开始的数字取出来压数字栈,当遇到左括号是总是压符号栈不管连续多少个左括号,当遇到右括号时就从数字栈和符号栈中取值计算并从新压栈,直到遇到左括号,期间还要比较运算符的优先级等。当遇到字符串结束时还没有计算完成,此时数字栈和字符栈内都有值。如果符号栈内是*、/那么要计算两次,如果是+、-则计算一次。最终得出结果。我写这个程序时思路还是清晰的,就是不知道有没有小问题,希望能给大家一些启发。测试出问题也希望大家给我说,大家一起进步嘛。

0 0
原创粉丝点击