实验设计-利用栈实现计算器

1.实现一个简单的计算器,输入一个包含圆括号、加减乘除、求余等符号组成的算术表达式字符串,输出该算术表达式的值。要求:
(1)系统至少能实现加、减、乘、除、求余等运算;
(2)利用栈实现并将表达式结果输出。

1.算法设计及算法步骤:

程序分析:计算器功能实现,利用顺序栈实现中缀表达式到后缀表达式的转变,继而进行相应的(+,-,*,/)简单运算。
中缀表达式转后缀表达式:
申请一段连续的顺序栈字符空间进行运算符存储,以便输入输出顺序控制。
通过一个数字数组和一个字符数组保存后缀表达式。两个数组同步数组下标,当数字数组存入一个数字时候,字符数组存入一个!号作为标识,且记录数组下标的int变量++;当字符数组存入一个符号时,数字数组下标位置默认为0,不用做标识,只需把记录数组下标的int变量++。
通过flag变量记录字符解析状态,如果连续解析到数字字符,则数字拼接,如果解析到字符,如果flag标识上次读取的为数字,则先将数字输出录入数组,再对字符进行分析。
字符如果是’(‘号,或者栈顶指向-1,则字符直接录入栈中;如果遇到右括号,执行出栈操作,并将出栈符号输出(录入到数组),直到左括号也出栈,左括号不输出;遇到运算符时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将运算符入栈(即如果是乘除,则乘除出栈,新符号进栈,
如果是加减,则四则运算出栈,遇到左括号停止出栈,新符号进栈。)最终(字符值为NULL)将栈中的元素依次出栈,输出。
后缀表达式运算:
申请一段连续的顺序栈数字(int)空间存储读取到的数字,以便表达式运算。
如果数字数组下标位置不为NULL则读取到数字,并将数字入栈,如果字符数组下表位置不为!号则说明后缀表达式这个位置是一个运算符,则出栈两个数字进行数学运算,运算后将结果入栈。
当读取到数组下标位置为NULL的时候则说明后缀表达式读取,读取完毕,返回最终结果。

C语言实现:

#define OK 1
#define ERROR 0
#define MAXSIZE 50
#include<stdio.h>
#include<stdlib.h> //引入库文件 
#include<string.h>
typedef int status;  //status是函数的类型,其值是函数结果状态代码,如OK等
                     //多用来当返回值用,注意这里Status是一个整型,如果return OK 则代表返回值 1,return ERROR代表 0 

                     //栈的理解:就相当于竖起来的线性表,对于顺序存储,这种概念更深,
					 //栈(Stack)是限定仅在表尾进行插入和删除操作的线性表.栈有空栈概念,会有一个跟踪栈顶的指针top,
					 //定义当top为-1时即为空栈, top总小于StackSize,当为满栈时,top=StackSize-1   
					 //延伸:总结栈和堆的概念及区别 

					 //c语言中char以及字符串:
//	表示字符型数组a中可以存放2个字符,第1个字符用a[0]访问,第2个字符用a[1]访问,最大下标可以用0~(2-1)范围的。比如a[100]合法下标范围是0~99;
//当a需要保存字符串时,需要注意,字符串必须以0值结尾,表示成字符就是'\0',而且这个0不算在字符串中的字符,那么你用a数组最多只能保存n-1个字符组成
//的数组,如果是char a[2];的话只能保存一个字符组成的字符串;如:char a[20]={ "Hello !" };或者char a[20]={ 'H','e','l','l','o','\0' };这时字符串占
//用6个数组元素,但字符串长度为5,如果你用strlen语句计算的长度也为5,你最多可在这个数组中保存长度为19的字符串,需要自己在末尾添加0或'\0',前面语句
//char a[20]={ "Hello !" };是编译器自动帮你加了结尾符0;
//  当懒得数字符串中字符个数时,也可以让编译器帮你数:char a[]={"Hello"};这与你自己写:char a[6]={ "Hello" };是一样的。
//char a[2];
//这是声明。声明变量 a 是 char 型数组,有2个元素。
//语句里  写  a[0] 表示它是 char 型数组a 里的 第一个 元素
//a[1] 是 char 型数组a 里的 第二个 元素。 
//char a[2];  
//也可以看成 是 字符串 变量 a。  由于 字符串要用1个单元存放字符串 结束符,所以只能 存放 长度为 1 的字符串。
//声明,带初始化写法:
//char a[2]={ 'A', 'x'};   初始化 a[0]='A';  a[1]='x';  -- 单引号括起的是 字符常量
//char a[2]="A";    初始化 字符串 "A"  -- 双引号括起的是 字符串,含 字符串结束符。

/*实现一个简单的计算器,输入一个包含圆括号、加减乘除、求余等符号组成的算术表达式字符串,输出该算术表达式的值。要求:
(1)系统至少能实现加、减、乘、除、求余等运算;
(2)利用栈实现并将表达式结果输出。*/

//要想让计算机具有处理我们通常的标准(中缀)表达式的能力,必须有:
//1.将中缀表达式转化成后缀表达式(栈用来进出运算的符号)
//2.将后缀表达式进行运算得出结果(栈用来进出运算的数字)


//c语言的字符串是以字符数组组成的,不能用普通运算符去运算字符串
//指针可以保存一个字符串常量,是只读不可写的 
//栈实现利用栈的顺序存储,字符串分隔,并将数字保存到数组中,将符号保存到字符数组中

//要明白一点,数据结构,注重算法思想,过程的学习,c语言是比较基础的语言,
//虽然库中也有很多方便的封装函数,但其基础的实现也是由人编写代码实现目的的,
//且可能函数实现要比我们自己写的程序更加复杂,与我们目的相比冗余更多,
//实现功能上,尽量自己去写底层代码,而减少函数的调用使用 

//中缀表达式转后缀表达式时用到的字符栈 
typedef char ElemType; 

//声明栈类型 
typedef struct SqStack{
 ElemType data[MAXSIZE];
 int top; 
}SQTA ;
typedef struct SqStack *zhanChar;//指针,保存地址的变量 
//后缀表达式计算时用到的数字栈 
typedef int ElemTypes; 
typedef struct SqStacks{
 ElemTypes data[MAXSIZE];
 int top; 
}SQTAs ;

typedef struct SqStacks *zhanInt;//指针,保存地址的变量 
//定义的结构体如果是指针,访问成员时就用->
//如果定义的是结构体变量,访问成员时就用.
 
 int begin();//主界面,根据用户输入内容执行不同操作 
 int transform(char shizi[]); //将中缀表达式转为适合计算机运算的后缀表达式 
int count(char shiziChar[],	int shiziInt[]); //对后缀表达式进行运算并将结果返回 


int transform(char shizi[]){  //数组本身是一个表达地址 
	
	char shiziChar [100]={};//用来存储符号排序后的符号 //如果位置是数字,存储! 
	int shiziInt [100]={}; //用来存储数字数组,如果是位置是字符,则存储为0 
	char *p=shizi; //shizi本身也是一个指针,但因为名字原因,这里还是用指针p代替 
	int a =0;//用来记录分隔后的数
	int index=0;//用来记录
	int flag=1;//用来记录是否正在拼数字 即(是否在拼数字状态) 
	zhanChar zc=(zhanChar)malloc(sizeof(SQTA ));//如果分配成功则返回指向被分配内存的指针
	zc->top=-1;
	
do{
	  
	if(*p>=48&& *p<=57){  //读到一个数字字符 
       a *=10;
		a+=*p-48;
		flag=1; 
	}else{               //读到一个字符,或者字符串结束 
		if(flag==1){
			shiziInt[index]=a;  //把拼接好的数字录入数组 
			shiziChar[index]='!';//把这一位置用!标识
			index++; 
			a=0;         
						     //到此,相当于一个数录入完毕 
		}
		if(*p==NULL){    
			//printf("读取完毕");
			while(zc->top!=-1){
				shiziChar[index]=zc->data[zc->top];
				index++;
				zc->top--;
			}
			
				break;
		} else if(zc->top==-1||*p=='('){   // 如果字符是(或者zc->top==-1,直接入栈 
			zc->top++;                  
			zc->data[zc->top]=*p;
		}else if(*p==')'){
			//遇到右括号,执行出栈操作,并将出栈符号输出,直到左括号也出栈,左括号不输出
			//遇到+--/ 时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将运算符入栈
			//最终将栈中的元素依次出栈,输出 
			do{
				if(zc->data[zc->top]=='('){
					zc->top--;  // 
					break;
				}else{
					
			shiziChar[index]=zc->data[zc->top];
				index++;
			zc->top--;
				} 
			}while(1);
			
		} else if(*p=='*'||*p=='/'){  //如果是乘除,则乘除出栈,新符号进栈 
			while(zc->top>=0&&zc->data[zc->top]=='*'||zc->data[zc->top]=='/'){
				shiziChar[index]=zc->data[zc->top];
				index++;
				zc->top--;
			}
			zc->top++;
			zc->data[zc->top]=*p;
			
		}else if(*p=='+'||*p=='-'){  //如果是加减,则四则运算出栈,遇到左括号停止出栈,新符号进栈 
			while(zc->top>=0&&zc->data[zc->top]!='('){
				shiziChar[index]=zc->data[zc->top];
				index++;
				zc->top--;
			}
			
			zc->top++;  
			zc->data[zc->top]=*p;
			
		}
		     
		flag=0;
		
		
	}
	 p++;
	 //如果单单输入一个纯数字 
	 
	}while(1);
	int i=0;
	printf("\n");
	while(shiziInt[i]!=NULL||shiziChar[i]!=NULL){  //数字数组默认为0 
		if(shiziInt[i]!=NULL){
			printf("%d",shiziInt[i]);
			
		}else if(shiziChar[i]!='!'){
			printf("%c",shiziChar[i]);
		}
			i++;
		}
			printf("\n");

      int counts=0;
      counts=count(shiziChar,shiziInt);
	return counts;
}
//	printf("%\n",p); 
//	printf("%s\n",shizi); 
//	printf("%c\n",shizi[0]);
//	printf("%p\n",shizi);
//	printf("%p\n",shizi[0]);
//	printf("%p\n",shizi[1]);

 int count(char shiziChar[],int shiziInt[]){
	int i=0;//用来记录
	zhanInt zi=(zhanInt)malloc(sizeof(SQTAs ));//如果分配成功则返回指向被分配内存的指针
	zi->top=-1;
	int count=0; //运算后的值,或最终结果
	int count1=0,count2=0; 
	while(shiziInt[i]!=NULL||shiziChar[i]!=NULL){
		if(shiziInt[i]!=NULL){   //读取到数字的时候进栈 
			zi->top++;
			zi->data[zi->top]=shiziInt[i];
			
		}else if(shiziChar[i]!='!'){  //遇到字符的时候进行运算 
			      count2=zi->data[zi->top];   //记录栈顶 
				      zi->top--;
					   count1=zi->data[zi->top];  //记录栈顶-1 
			 if(shiziChar[i]=='+'){
			 	count=count1+count2;
			 }else if(shiziChar[i]=='-'){
			 	count=count1-count2;
			 }else if(shiziChar[i]=='*'){
			 	count=count1 * count2;
			 }else if(shiziChar[i]=='/'){ 
			 	count=count1 / count2;
			 }
			 zi->data[zi->top]=count;
		} 
		   
			i++;
		}
		count=zi->data[zi->top];
		    zi->top--;
		
		return count;
} 


int begin(){
	printf("------麦兜给您计算计算器--------\n");
  	char shizi[100]=""; //最终的式子 
	printf("给我要计算的式子:\n"); 
	scanf("%99s",&shizi);
  	printf("麦兜努力计算中....");
  	printf("%d",transform(shizi));
  	} 
int main() {
	 
    begin();
    return 1;
}

上一篇:如何解决PuTTY中文乱码的问题


下一篇:NiftyNet开源平台使用