利用栈实现逆波兰计算器

下面利用栈实现了逆波兰计算器,将用户输入的中缀表达式转换为后缀表达式,再计算出结果。
使用了两个链栈,一个栈内的元素为字符型,用于处理用户输入的数据,将其转换为后缀表达式,储存在字符型数组中,再利用另一个栈,栈内元素为整型,利用栈处理后缀表达式再进行输出。
PS.只能进行整数运算,处理小数的话需要将处理后缀表达式的栈内的元素类型改为float或者double,而且需对小数点进行处理。

算法步骤:
step1:中缀表达式转换为后缀表达式
从头到尾读取中缀表达式中的每个对象:,对每个对象进行处理:
1.运算数:直接输出
2.左括号:入栈
3.右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
4.运算符:(优先级为:括号 > 乘除 > 加减)
若优先级大于栈顶运算符,则入栈
若优先级小于等于栈顶运算符,将栈顶运算符弹出并输出,再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后该运算符入栈(简单来说就是如果读取到加减号就一直pop到栈空或者pop出来是左括号,然后加减号入栈;如果读取到乘除符号,直接入栈)
5.对象处理完毕后,栈内运算符全部输出
step2:计算后缀表达式
1.从左到右遍历中缀表达式的每一个数字和符号
2.若是数字,则进栈
3.若是符号,则把处于栈顶的两个数字出栈,进行运算
4.运算结果进栈
5.直到获得最终结果并将最后结果出栈

代码如下:

#include
#include
#include
#include

#define DATASIZE 50//存放后缀表达式的数组长度
#define MAXBUFFER 10//最大缓冲区大小 

typedef char ElemType;
typedef int elemtype;

typedef enum Status 
{
    error, 
	success
} Status;

typedef struct StackNode
{
	ElemType data;
	struct StackNode *next;
}StackNode, *LinkStackPtr;

typedef struct LinkStack
{
	LinkStackPtr top;
	int	count;
}LinkStack;

typedef struct stacknode
{
	elemtype data;
	struct stacknode *next;
}stacknode, *linkstackptr;

typedef struct linkstack
{
	linkstackptr top;
	int	count;
}linkstack;

//函数的声明(链栈)
//栈内元素为字符型,用于处理输入的数据 
Status initLStack(LinkStack *s);//初始化栈
Status notEmptyLStack(LinkStack *s);//判断栈是否为空
void Push(LinkStack *s,ElemType data);//入栈
void Pop(LinkStack *s,ElemType *data);//出栈
//栈内元素为整型,用于处理输出的数据 
Status initlstack(linkstack *s);//初始化栈
void push(linkstack *s,elemtype data);//入栈
void pop(linkstack *s,elemtype *data);//出栈

//下面是字符型链栈基本操作的函数 
Status initLStack(LinkStack *s)
{
    s->top = NULL;
    s->count = 0;
    return success;
}

Status notEmptyLStack(LinkStack *s)
{
    if(s->top != NULL)//非空返回1
    {
        return success;
    }
    else
    {
        return error;
    }
}

void Push(LinkStack *s,ElemType data)
{
    LinkStackPtr new = (LinkStackPtr)malloc(sizeof(StackNode));
    if(new == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        exit(0);
    }
    new->data = data;
    new->next = s->top;
    s->top = new;
    s->count++;
}
 
void Pop(LinkStack *s,ElemType *data)
{
    if(s->top == NULL)
    {
        printf("栈空\n");
        system("pause");
        exit(0);
    }
    else
    {
        LinkStackPtr temp;
        *data = s->top->data;
        temp = s->top;
        s->top = s->top->next;
        free(temp);
        s->count--;
    }
}

//下面是整型链栈基本操作的函数
Status initlstack(linkstack *s)
{
    s->top = NULL;
    s->count = 0;
    return success;
}

void push(linkstack *s,elemtype data)
{
    linkstackptr new = (linkstackptr)malloc(sizeof(stacknode));
    if(new == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        exit(0);
    }
    new->data = data;
    new->next = s->top;
    s->top = new;
    s->count++;
}

void pop(linkstack *s,elemtype *data)
{
    if(s->top == NULL)//栈空,对应错误:如用户输入:1+= 
    {
        printf("\n出错:输入格式错误!\n");
        printf("请切换成英文,匹配好括号或者不要输入空格等等\n");
        system("pause");
        exit(0);
    }
    else
    {
        linkstackptr temp;
        *data = s->top->data;
        temp = s->top;
        s->top = s->top->next;
        free(temp);
        s->count--;
    }
}

int main(void)
{
    //共用变量
    int i = 0;//数组下标
    //中缀表达式转换后缀表达式的变量
    LinkStack s;
    char c, d;//处理输入的数据
    char data[DATASIZE];//存放后缀表达式
    //计算后缀表达式的变量
    linkstack s1;
    char str[MAXBUFFER];//缓冲区,用于处理连续的数字
    elemtype n1, n2;//处理输出的数据
    int n = 0;//缓冲区内计数器

    //初始化两个栈
    if(!initLStack(&s))
    {
        printf("初始化失败\n");
        system("pause");
        return -1;
    }
    if(!initlstack(&s1))
    {
        printf("初始化失败\n");
        system("pause");
        return -1;
    }

    //下面将中缀表达式转换为后缀表达式储存在数组data中
    printf("请输入中缀表达式,以=作为结束标志(只能进行整数运算):");
    scanf("%c", &c);
    while( c != '=' )//一直接收用户输入,直到读取到=为止
    {
        while(c>='0' && c<='9')//整数直接存入数组
        {
            data[i] = c;
            i++;
            scanf("%c", &c);
            if(c<'0' || c>'9')//处理连续的数字
            {
                data[i] = ' ';
                i++;
            }
        }

        if(c == ')')
        {
            Pop(&s, &d);//出栈
            while(d != '(')//不是左括号就存入数组
            {
                data[i] = d;
                i++;
                Pop(&s, &d);
            }
        }
        else if(c == '+' || c == '-')
        {
            if(!notEmptyLStack(&s))//栈空即入栈
            {
                Push(&s, c);
            }
            else//栈非空则比较栈顶元素
            {
                do
                {
                    Pop(&s, &d);
                    if(d == '(')
                    {
                        Push(&s, d);
                    }
                    else//不是左括号就存入数组
                    {
                        data[i] = d;
                        i++;
                    }
                }while(notEmptyLStack(&s) && d != '(');
                //直到栈空或者读取到左括号
                Push(&s, c);//然后再入栈
            }
        }
        else if(c == '(' || c == '*' || c == '/')
        {
            Push(&s, c);
        }
        else if(c == '=')
        {
            break;
        }
        else
        {
            printf("\n出错:输入格式错误!\n");
            printf("请切换成英文,匹配好括号或者不要输入空格等等\n");
            system("pause");
            return -1;
        }

        scanf("%c", &c);
    }
    
    //检查如果=前无运算符,eg:1=
    if(!notEmptyLStack(&s))
    {
	    printf("\n出错:输入格式错误!\n");
	    printf("请切换成英文,匹配好括号或者不要输入空格等等\n");
	    system("pause");
    	return -1;
	}

    while(notEmptyLStack(&s))//将栈内剩余对象存放到数组
    {
        
        Pop(&s, &data[i]);
        i++;
        data[i] = '=';
		data[i+1] = '\0';//字符串结束标志
    }    

    printf("\n后缀表达式:\n");
    printf("%s\n", data);
    
    //下面计算后缀表达式
    for(i = 0; data[i] != '\0'; i++)
    {
    	//下面对数字进行处理
        while(isdigit(data[i]))
        {
            str[n++] = data[i++];
            str[n] = '\0';//字符串结束
            if(n >= MAXBUFFER)
            {
                printf("输入的单个数据过大\n");
                system("pause");
                return -1;
            }
            if(data[i] == ' ')//读取到空格时对前面的所有数字进行处理
            {
                n1 = atoi(str);//将字符串转换成整型数据
                push(&s1, n1);
                n = 0;//计数器重新初始化
                break;
            }
        }
        switch(data[i])//过滤掉数字后对剩下的符号进行选择
        {
            case '+':
            {
                pop(&s1, &n1);
                pop(&s1, &n2);
                push(&s1, n1 + n2);
                break;
            }
            case '-':
            {
                pop(&s1, &n1);
                pop(&s1, &n2);
                push(&s1, n2 - n1);
                break;
            }
            case '*':
            {
                pop(&s1, &n1);
                pop(&s1, &n2);
                push(&s1, n1 * n2);
                break;
            }
            case '/':
            {
                pop(&s1, &n1);
                pop(&s1, &n2);
                if(n1 != 0)
                push(&s1, n2 / n1);
                else
                {
                    printf("\n出错:除数不能为零\n");
                    system("pause");
                    return -1;
                }
                break;
            }
        }
    }
    pop(&s1, &n1);
    printf("\n计算结果为:%d\n\n", n1);
   
    system("pause");
    
    return 0;
}

你可能感兴趣的:(数据结构(C语言))