用栈来是实现表达式求解的小程序

    表达式求解有有多种解决办法,也有很多方法是先把表达式转换为后缀式在求解的。我这里是使用2个栈来直接求解的,一个栈用来保存运算符,一个用来保存数字。

基本的思路也就是,程序根据输入的字符,来分步解析,并计算。用2个数组来表示运算符和运算符的优先级,通过运算符的优先级来决定是否进行运算还是入栈。

static char operas[]={'#','+','-','*','/'};
static char priority[]={'0','1','1','2','2'};

运算符优先级就用这2个字符数组表示,其中#号作为一个标记符用来表示最小优先级的运算符,在运算符栈初始化的时候就先存一个#运算符入栈,并且将#运算符作为输入的字符结尾表示结束。

 

    比如输入一个字符串:12+56/7*65#    遇到数字,就用一个length变量来保存数字长度,当遇到下一个运算符的时候。使用字符串截取函数,截取前面的字符并转换为数字,并将这数字入栈,然后字符串指针位置在+号这里,程序判断+号和运算符栈顶的运算符优先级,因为运算符栈初始化是有一个最低级运算符#,所以+号优先级大于#号,这里就将+号也入运算符栈。指针继续指向数字,截取数字56后入运算数栈,这里/号运算符优先级大于刚入栈的+号。所以/号也继续入预算符栈。数字7入运算数栈,后面的*号和运算数栈顶的/号同优先级,所以这里程序先不把*号入栈,进行出栈计算函数操作。由于运算数栈栈顶和栈顶下一个数据,就是/号运算符的2个运算数,所以将运算数栈出栈2次,运算符栈出栈一次,得到56/7,进行计算,将得到的结果8进行运算数入栈操作,然后在执行*号和运算符栈顶进行比较,*号优先级大于+号,入运算符栈,并且读取数字65,入运算数栈,最后读取的#号优先级小于所有运算符,所以进行出栈运算操作,同样是运算数栈出栈2次,而运算符栈出栈一次,得到8*65.计算后入运算数栈。栈计算函数进行递归判断,#号优先级继续小于第一次入栈的+号,在执行出栈运算,知道运算符栈也只有最先初始化的#号运算符结束。

上面就是这个表达式基本运算的步骤,这里实现的也只是简单的+-/*。并没有加入()等界定符。用栈来进行表达式求解的基本思路也就是:当前运算符优先级比运算符栈顶的优先级大的时候,进行运算符入栈操作,等于或小于的时候,进行出栈计算操作,直到遇到#号运算符。下面有一个c写的例子,没有找到c语言中如何实现可以存储任意数据类型的栈表示方法,就暂且用void*指针表示了,所以代码中有很多强制类型转换的代码。

栈的定义

 

#ifndef STACK_S
#define STACK_S
#define Type double

typedef Type ElemType;
typedef struct _stack{
    ElemType data;
    int size;
    struct _stack* top;
}stack;
//定义一个栈数据结构,size栈大小,data存储数据。top表示栈顶指针。
extern stack* newstack();
//分配栈内存
extern stack* StackCreate();
//创建一个栈
extern void push(stack* s,ElemType data);
extern ElemType peek(stack* s);
extern ElemType pop(stack* s);
//栈的放入,查看,和出栈操作

#endif//STACK_S



demo.c 

 

/*
** Copyright (C) QPSOFT.COM All rights reserved.
static char operas[]={'#','+','-','*','/'};
static char priority[]={'0','1','1','2','2'};
定义2个字符数组,用来表示运算符优先级,2个字符数组想对应。可以使用二维数组,不过2个一维比较直观。
static int len=sizeof(operas)/sizeof(char);
返回运算符数组长度

int Inopera(char ch,char* chs);
判断ch字符是不是运算符
int Comopera(char o1,char o2,int len);
比较运算符和运算符栈的栈顶运算符优先级
double calc(double oa,double ob,char opera);
计算,oa,ob分别为运算数栈的栈顶和下一个数据,opera为运算符栈顶数据表示的运算符
char* substring(char* ch,int pos,int length);
字符串截取
void stack_opera(char* pch,stack* o_stack,stack* n_stack);
栈处理函数,用来判断表达式入栈后的结果
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"

#define TRUE 1
//预处理,
static char operas[]={'#','+','-','*','/'};
static char priority[]={'0','1','1','2','2'};
static int len=sizeof(operas)/sizeof(char);

/*函数声明*/
int Inopera(char ch,char* operas);
int Comopera(char o1,char o2,int len);
double calc(double oa,double ob,char opera);
char* substring(char* ch,int pos,int length);
void stack_opera(char* pch,stack* o_stack,stack* n_stack);

int main()
{
    stack* n_stack=StackCreate();
    stack* o_stack=StackCreate();
    //定义运算符o_stack和运算数n_stack栈
    push(o_stack,operas[0]);//运算符栈初始化一个最低优先级运算符#
    char* text="5-2.5#";//要进行计算的运算数,这里定义类型为long
    char *pch=text;//定义一个指针指向运算数
    int pos=0,length=0;/*pos指向计算字符中的位置,length来保存其中每端数字的长度*/
    while(TRUE)
    {
        length++;
        if(*pch=='.'||(*pch<'9' && *pch>='0'))
        {
            pch++;
            continue;/*判断 *pch是否是一个数字,用length来保存连续数字的长度*/
        }
        else if(Inopera(*pch,operas))
        {
            push(n_stack,atof(substring(text,pos,length-1)));
            pos+=length;
            length=0;
            /*Inopera函数来判断是否遇到运算符,并将前面的数字截取,
            //然后入栈,atof方法转换字符为float数字*/

            stack_opera(pch,o_stack,n_stack);/*遇到运算符,stack_opera函数来判断执行那种操作*/
        }
        else
        {
            printf("%s\n","expression is error!");
            break;/*如果遇到的字符不是数字或不是指定的运算符,程序将退出*/
        }

        if((*pch)=='#'){break;}
        ++pch;/*pch指针,每循环一次递增*/
    }
    printf("%f\n",pop(n_stack));
    /*显示运算数栈最后得到的结果*/
    return 0;
}
/*计算函数,参数分别表示2个计算数,opera表示运算符*/
double calc(double oa,double ob,char opera)
{
        /*根据opera运算符来进行运算*/
        switch(opera)
        {
        case '+':
           return (oa+ob);
        case '-':
            return (oa-ob);
        case '*':
            return (oa*ob);
        case '/':
            return (oa/ob);
        }
        return 0;
}
/*运算符判断函数,ch是要判断的运算符,operas是指定的运算符数组*/
int Inopera(char ch,char* operas)
{
    while(*(operas)!='\0')
    {
        if(ch==(*operas++))
        {
            return 1;
        }
    }/*如果ch和operas字符数组中的数匹配,则返回1,否则返回0*/
    return 0;
}
/*运算符优先级判断*/
int Comopera(char o1,char o2,int len)
{
    int i,ol1,ol2=-1;/*声明几个局部变量,i是因为非c99规范,不支持for循环中声明变量,所以定义在外部保持兼容*/
    /*ol1,ol2用来表示运算符o1,o2在运算符数组中的位置,用来表示优先级*/
    for(i=0;i<len;i++)
    {
      if(o1==operas[i]){ol1=priority[i];}
      if(o2==operas[i]){ol2=priority[i];}
    }
    return ol1-ol2;

    /*operas和priority数组是大小相对应的,所以可以根据运算符
    //o1,o2在operas中的位置来定位在priority中的位置,并获得优先级大小*/
}

/*栈运算处理函数*/
void stack_opera(char* pch,stack* o_stack,stack* n_stack)
{
    /* *pch表示计算数中的当前运算符,o_stack和n_stack表示运算符,运算数栈*/

     if(Comopera(*pch,(char)peek(o_stack),len)>0)
    {
        push(o_stack,*pch);/*如果*pch表示的运算符优先级小于运算符栈顶的,就讲pch入栈*/
    }
    else                   /*当*pch表示运算符优先级小于或等于运算符栈顶时,进行出栈计算操作*/
    {
        double ob=pop(n_stack);
        double oa=pop(n_stack);   /*将运算数栈出栈2次,获取运算数,并以反顺序赋值。*/

        push(n_stack,calc(oa,ob,(char)pop(o_stack)));   /*将result入栈。*/

        if((char)peek(o_stack)=='#' && *pch=='#'){return;}    /*当运算符栈顶为#,并pch指向计算数末尾时返回*/
        stack_opera(pch,o_stack,n_stack);                       /*递归处理栈中存留数据*/
    }
}

/*字符截取函数*/
char* substring(char* ch,int pos,int length)
{
    char* pch=ch;
    char* subch=calloc(sizeof(char),length+1);
    int i;
    pch=pch+pos;    /*定义局部字符指针,初始化pch位置。并分配一个length+1长度,保存char类型的数组内存。*/

    for(i=0;i<length;i++)
    {
        subch[i]=*(pch++);
    }
    subch[length]='\0'; /*依次赋值填充subch字符数组空间,末尾加上字符串结束标志'\0'*/
    return subch;
}


代码显得比较冗长,主要是加了一点讲数字截取转字符的,c了解的不是很多,可能是没有接触过太多库,刚学,就只好用基本的东西来实现字符截取。这里使用double数据类型来进行运算。,希望有看到的可以提供一个可以保存任意数据类型的栈或链表的方法,这个程序,换java或其他语言可能会简便很多。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值