IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 多位数的表达式求值 -> 正文阅读

[数据结构与算法]多位数的表达式求值

这次的题是在学校课程上机实验时安排的任务,以下是几个关键步骤。

目录

问题描述

具体算法

实现优先级比较函数

整体代码

运行结果?

结语


问题描述

设计一个程序,演示用算符优先法对算术表达式求值的过程。利用算符优先关系,实现对算术四则混合运算表达式的求值。

(1)输入的形式:表达式,例如2*(3+4)#?

??????????包含的运算符只能有'+' 、'-' 、'*' 、'/' 、'('、 ')',“#”代表输入结束符;

(2)输出的形式:运算结果,例如2*(3+4)=14;
(3)程序所能达到的功能:对表达式求值并输出。

借鉴严蔚敏编的《数据结构》书上提的思路,咱们可以设置两个工作栈:用于存储运算符的栈opter,以及用于存储操作数及中间结果的栈opnd。


具体算法

(1)首先将操作数栈opnd设为空栈,而将'#'作为运算符栈opter的栈底元素,这样的目的是判断表达式是否求值完毕。

(2)依次读入表达式的每个字,表达式须以'#'结,读入字符若是操作数则入栈opnd,读入字符若是运算符,则将此运算符c与opter的栈顶元素top比较优先级后执行相应的操作,操作如下:?

  • (i)若top的优先级小于c,即top<c,则将c直接入栈opter,并读入下一字符赋值给c;
    • (ii)若top的优先级等于c,即top=c,则弹出opter的栈顶元素,并读入下一字符赋值给c,这一步目的是进行括号操作;
      • (iii)若top优先级高于c,即top>c,则表明可以计算,此时弹出opnd的栈顶两个元素,并且弹出opter栈顶的的运算符,计算后将结果放入栈opnd中。直至opter的栈顶元素和当前读入的字符均为'#',此时求值结束。

?根据运算符的优先关系:


实现优先级比较函数

? 将其代码实现为:

int getIndex(char theta)   //获取theta所对应的索引 
	{ 
	    int index = 0; 
	    switch (theta) 
	    { 
	    case '+':
	        index = 0; 
	        break; 
	    case '-': 
	        index = 1; 
	        break; 
	    case '*': 
	        index = 2; 
	        break; 
	    case '/': 
	        index = 3; 
	        break; 
	    case '(': 
	        index = 4; 
	        break; 
	    case ')': 
	        index = 5; 
	        break; 
	    case '#': 
	        index = 6; 
	    default:break; 
	    } 
	    return index; 
	} 
	 
char getPriority(char theta1, char theta2)   //获取theta1与theta2之间的优先级 
	{ 
	    const char priority[][7] =     //算符间的优先级关系 
	    { 
	        { '>','>','<','<','<','>','>' }, 
	        { '>','>','<','<','<','>','>' }, 
	        { '>','>','>','>','<','>','>' }, 
	        { '>','>','>','>','<','>','>' }, 
	        { '<','<','<','<','<','=','0' }, 
	        { '>','>','>','>','0','>','>' }, 
	        { '<','<','<','<','<','0','=' }, 
	    }; 
	 
	    int index1 = getIndex(theta1); 
	    int index2 = getIndex(theta2); 
	    return priority[index1][index2]; 
	}

有了如上定义,我们只需要向函数getPriority传入opter栈顶元素和表达式中的字符,由函数的返回值即可得到优先级。

但在正式实现代码之前,有一点值得注意的是两个栈opter和opnd需要存入的数据类型(char和int)不一样,因此各栈的相关操作也需要区别性的定义,即Opnd_Stack、Opnd_Push、Opnd_Pop等等函数均是对运算数栈Opnd操作,同理Opter_Stack、Opter_Push、Opter_Pop等等函数

均是对运算符栈Opter操作。

整体代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 20
#define ERROR 0
#define OK 1
#define Stack_Size 100 // 初始化栈的最大长度
typedef int Status;
typedef struct{
    char Elem[Stack_Size];
    int top;
}Opter_Stack;

typedef struct{
    int Elem[Stack_Size];
    int top;
}Opnd_Stack;

void InitOpter(Opter_Stack *S){//初始化运算符栈
    S->top=-1;
}
void InitOpnd(Opnd_Stack *S){//初始化操作数栈
    S->top=-1;
}

int Opter_Pop(Opter_Stack *S)//弹出运算符栈
{
    if(S->top==-1)
    {
        printf("运算符栈为空\n");
        exit(10);
    }
    S->top--;
    return 1;
}

int Opnd_Pop(Opnd_Stack *S)
{
    if(S->top==-1)
    {
        printf("运算符栈为空\n");
        exit(11);
    }
    S->top--;
    return 1;
}

int Opter_Push(Opter_Stack* S,char ch)
{
    if(S->top==Stack_Size-1)
    {
        printf("运算符栈满\n");
        exit(12);
    }
    S->top++;
    S->Elem[S->top]=ch;
    return 1;
}

int Opnd_Push(Opnd_Stack* S,int ch)//入操作数栈
{
    if(S->top==Stack_Size-1)
    {
        printf("运算符栈满\n");
        exit(13);
    }
    S->top++;
    S->Elem[S->top]=ch;
    return 1;
}

char GetOpter(Opter_Stack *S)//获取运算符栈的栈顶元素,注意区分返回值类型
{
    if(S->top==-1)
    {
        printf("运算符栈为空\n");
        exit(17);
    }
    return S->Elem[S->top];
}

int GetOpnd(Opnd_Stack *S)
{
    if(S->top==-1)
    {
        printf("操作数栈为空\n");
        exit(18);
    }
    return S->Elem[S->top];
}


int getIndex(char theta)   //获取theta所对应的索引 
	{ 
	    int index = 0; 
	    switch (theta) 
	    { 
	    case '+':
	        index = 0; 
	        break; 
	    case '-': 
	        index = 1; 
	        break; 
	    case '*': 
	        index = 2; 
	        break; 
	    case '/': 
	        index = 3; 
	        break; 
	    case '(': 
	        index = 4; 
	        break; 
	    case ')': 
	        index = 5; 
	        break; 
	    case '#': 
	        index = 6; 
	    default:break; 
	    } 
	    return index; 
	} 
	 
char getPriority(char theta1, char theta2)   //获取theta1与theta2之间的优先级 
	{ 
	    const char priority[][7] =     //算符间的优先级关系 
	    { 
	        { '>','>','<','<','<','>','>' }, 
	        { '>','>','<','<','<','>','>' }, 
	        { '>','>','>','>','<','>','>' }, 
	        { '>','>','>','>','<','>','>' }, 
	        { '<','<','<','<','<','=','0' }, 
	        { '>','>','>','>','0','>','>' }, 
	        { '<','<','<','<','<','0','=' }, 
	    }; 
	 
	    int index1 = getIndex(theta1); 
	    int index2 = getIndex(theta2); 
	    return priority[index1][index2]; 
	}

Status IsNumber(char ch){			//判断字符是否为运算数
	if(ch>='0'&&ch<='9')		return OK;
	else	return ERROR;
}

int Operate(int a, char op, int b){			//四则运算 
	switch(op){
		case '+':	return a+b;
		case '-':	return a-b;
		case '*':	return a*b;
		case '/':	return a/b;
	}
}


Status Calculator(char exp[]){
	int i=0, x, y;
	char opt;
	Opnd_Stack *opnd;		InitOpnd(opnd);	
	Opter_Stack *opter;		InitOpter(opter);		//创建并初始化工作栈opter、opnd 
	Opter_Push(opter, '#');			//将'#'压入opter栈底作为结束标志 
	while(exp[i]!='#'||GetOpter(opter)!='#'){
		if(IsNumber(exp[i])){ 
			int data[10];
			int k=0, j, num=0;/*考虑到运算数可能为多位的问题,num作为一个中间数,
							用于将表达式中的为运算数的字符转化为整数然后入栈, k是用于将运算数存入data数组*/
			while(IsNumber(exp[i]))
			{
				data[k] =exp[i] - '0';
				k++;
				i++;
			}
			for(j=0;j<k;j++)
			{
				num = num*10+data[j];
			}
			Opnd_Push(opnd,num);
		}
		else{
			switch(getPriority(GetOpter(opter), exp[i])){		
				case '<':Opter_Push(opter,exp[i]);		/*若top的优先级小于exp[i],即top<exp[i],则将exp[i]直接入栈opter,并读入下一字符*/
						 i++;
						 break;
				case '=':Opter_Pop(opter);		/*若top的优先级等于exp[i],即top=exp[i],则弹出opter的栈顶元素,并读入下一字符,这一步目的是进行括号操作*/
						 i++;
						 break;	
				case '>':opt=GetOpter(opter);	Opter_Pop(opter);		/*若top优先级高于exp[i],即top>exp[i],则表明可以计算,此时弹出opnd的栈顶两个元素,
																		并且弹出opter栈顶的的运算符,计算后将结果放入栈opnd中*/
						 y=GetOpnd(opnd);	Opnd_Pop(opnd);
						 x=GetOpnd(opnd);	Opnd_Pop(opnd);
						 Opnd_Push(opnd,Operate(x,opt,y));
						 break;
			}
		}
	}
	/*跳出循环说明求值结束,此时opnd栈顶元素即为最终结果*/
	return GetOpnd(opnd);
}

int main(){
	int ret;
	char exp[MAXSIZE], real_exp[MAXSIZE];
	printf("Input the expression:\n");
	gets(exp);
	if(exp[strlen(exp)-1]!='#'){
		printf("表达式有误!");
		return 0; 
	}
	else{
	strcpy(real_exp,exp);
	real_exp[strlen(real_exp)-1]='\0';
	printf("%s\n", real_exp);
	ret=Calculator(exp);
	printf("= %d\n", ret);
	}
	return 0;
}

运行结果?

以下便是调试运行得到的几个结果:

?

?显然运算结果也和我们预期的一样!

结语

但程序不够完善的地方是只实现了整型运算数的计算,对于实型运算数的求值还需得在各个函数间及定义参数时做些微小的改动,迫于主修课程数量陡增的压力,不得先搁置一下,就到这吧。??

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-11-20 18:38:52  更:2021-11-20 18:41:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 12:44:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码