用链表写一个简单计算器

问题描述:假设计算器只能进行加减乘除运算,运算数和结果都是整数。
输入样例:1+12/2*3-12=
输出样例:7
思路:1.先将用户输入全部作为字符串存入一个链表中,再将此链表中的数字字符转换为数字,同运算符一起,存入另一个链表中。
2.遍历链表,先乘除后加减。
实现:1.存储用户输入的字符

typedef struct ch{//将用户的输入全部做为字符串存储到此链表中 
	int ch;
	struct ch *next;
}Char;

2.输入字符,存入链表:

char ch;
	Char *heads=NULL;
	Char *currents,*previouss;
	while(true)
	{
		currents=(Char*)malloc(sizeof(Char));
		scanf("%c",&ch);
		if(ch!='=')
		{
			if(heads==NULL)
				heads=currents;
			else
				previouss->next=currents;
			previouss=currents;
			currents->ch=ch;
			currents->next=NULL;	
		}
		else
		{
			if(heads==NULL)
				heads=currents;
			else
				previouss->next=currents;
			previouss=currents;
			currents->ch=ch;
			currents->next=NULL;
			break;
		}	
	}
	

3.将字符转为数学表达式存储:

typedef struct cal{
	int count;//交替存储数字和运算符 
	char oper;
	int emm;//用来标记本节点存储的是数字还是运算字符,1为数字,-1为运算字符 
	struct cal *next;
	struct cal *front;//加减乘除法都需要用到运算符下一位和前一位的数据 
}Cal;

4.将字符链表的值经过整理后存入数学表达式链表:

while(true)
	{
		current=(Cal*)malloc(sizeof(Cal));
		argu=s_gets(current,&heads,emm);
		if(argu)
		{
			if(head==NULL)
			{
				head=current;
				head->front =NULL; 
			} 
			else
			{
				previous->next=current;
				current->front =previous;
			}
			previous=current;
			current->next=NULL;
			current->emm =emm;
			emm=-emm;
		}
		else
			break;	
	}

5.进行运算:

	current=head;
	while(current!=NULL)
	{
		if((current->oper=='/')||(current->oper=='*'))
		{
			if(current->oper=='/')
			{
				if(current->next ->count==0)
				{
					printf("ERROR");
					return 0;	
				}
				divi(&current);//将current设置为被除数的地址,删除运算符和除数
			}
			else
			{
				mul(&current);
			}
		} 
		current=current->next;	
	}
	
	current=head;	
	while(current!=NULL)
	{
		if(current->oper =='+'||current->oper =='-')
		{
			if(current->count='+')
				sum(&current);
			else
				sub(&current);
		}
		current=current->next;
	}

6.细节函数:

bool s_gets(Cal *current,Char **heads,int emm)
{
	Char *immi=*heads; //因为在后面我们会先改变heads的值,而后又需要用到heads的初值 
	if((*heads)->ch=='=')
		return false;
	if(emm==1)//存储数字 
	{
		int tally=0,sum=0;//sum存储转化的数字 
		while((*heads)->ch>='0'&&(*heads)->ch<='9')
		{
			tally++;
			(*heads)=(*heads)->next;
		}//跳出循环后获得数字位数,heads指针的值也改变成最后一位数字字符后面的 运算符的地址 
		for(int i=tally;i>=1;i--)
		{
			sum=sum+pow(10,i-1)*(immi->ch-'0');
			immi=immi->next;
		}
		current->count =sum;
		current->emm=emm;	
	}
	else
	{
		(*heads)=(*heads)->next;//指向下一位(下一位是数字字符) 
		current->oper =immi->ch;//在这里我最初写的是(*heads)忽略了其值已经改变 
		current->emm =emm;
	}
	return true;
}

void divi(Cal **current)
{
	Cal *temp1,*temp2;
	(*current)->front->count=(*current)->front->count/(*current)->next->count;
	(*current)->front->next=(*current)->next->next;
	if((*current)->next->next!=NULL) //我最初忽略了还需要把下下个节点(如果存在)的前一位节点更新
		(*current)->next->next->front=(*current)->front;
	temp1=(*current);
	temp2=(*current)->next;
	(*current)=(*current)->front;
	
	free(temp1);
	free(temp2);
}
void mul(Cal **current)
{
	Cal *temp1,*temp2;
	(*current)->front->count=((*current)->front->count)*((*current)->next->count);
	(*current)->front->next=(*current)->next->next;
	if((*current)->next->next!=NULL) 
		(*current)->next->next->front=(*current)->front;
	temp1=(*current);
	temp2=(*current)->next;
	(*current)=(*current)->front;
	
	free(temp1);
	free(temp2);
}
void sum(Cal **current)
{
	Cal *temp1,*temp2;
	(*current)->front->count=(*current)->front->count+(*current)->next->count;
	(*current)->front->next=(*current)->next->next;
	if((*current)->next->next!=NULL) 
		(*current)->next->next->front=(*current)->front;
	temp1=(*current);
	temp2=(*current)->next;
	(*current)=(*current)->front;
	
	free(temp1);
	free(temp2);
}
void sub(Cal **current)
{
	Cal *temp1,*temp2;
	(*current)->front->count=(*current)->front->count-(*current)->next->count;
	(*current)->front->next=(*current)->next->next;
	if((*current)->next->next!=NULL) 
		(*current)->next->next->front=(*current)->front;
	temp1=(*current);
	temp2=(*current)->next;
	(*current)=(*current)->front;
	
	free(temp1);
	free(temp2);
}

7.输出结果(为了更直观,不直接用head->count,而是重新遍历一遍):

current=head;
	while(current!=NULL)
	{
		if(current->emm==1)
			printf("%d",current->count );
		else
			printf("%c",current->oper);
			current=current->next ;
	}
	

完整代码:

#include<stdio.h> 
#include<stdlib.h>
#include<stdbool.h>
#include<math.h>
typedef struct ch{//将用户的输入全部做为字符串存储到此链表中 
	int ch;
	struct ch *next;
}Char;
typedef struct cal{
	int count;//交替存储数字和运算符 
	char oper;
	int emm;//用来标记本节点存储的是数字还是运算字符,1为数字,-1为运字符 
	struct cal *next;
	struct cal *front;//乘除法都需要用到运算符下一位和前一位的数据 
}Cal;
bool s_gets(Cal *current,Char **heads,int emm);//将Char链表的值作为输入传递给Cal链表
void divi(Cal **current);//计算除法 
void mul(Cal **current);
void sum(Cal **current);
void sub(Cal **current);
int main(void)
{
	int i,j;
	Cal *head=NULL;
	Cal *current,*previous;
	bool argu;
	int emm=1;
	
	char ch;
	Char *heads=NULL;
	Char *currents,*previouss;
	while(true)
	{
		currents=(Char*)malloc(sizeof(Char));
		scanf("%c",&ch);
		if(ch!='=')
		{
			if(heads==NULL)
				heads=currents;
			else
				previouss->next=currents;
			previouss=currents;
			currents->ch=ch;
			currents->next=NULL;	
		}
		else
		{
			if(heads==NULL)
				heads=currents;
			else
				previouss->next=currents;
			previouss=currents;
			currents->ch=ch;
			currents->next=NULL;
			break;
		}	
	}
	
	
	while(true)
	{
		current=(Cal*)malloc(sizeof(Cal));
		argu=s_gets(current,&heads,emm);
		if(argu)
		{
			if(head==NULL)
			{
				head=current;
				head->front =NULL; 
			} 
			else
			{
				previous->next=current;
				current->front =previous;
			}
			previous=current;
			current->next=NULL;
			current->emm =emm;
			emm=-emm;
		}
		else
			break;	
	}
//存储转换工作已完成,没有错误,不准在改 
/*乘除法*/
	current=head;
	while(current!=NULL)
	{
		if((current->oper=='/')||(current->oper=='*'))
		{
			if(current->oper=='/')
			{
				if(current->next ->count==0)
				{
					printf("ERROR");
					return 0;	
				}
				divi(&current);//将current设置为被除数的地址,删除运算符和除数
			}
			else
			{
				mul(&current);
			}
		} 
		current=current->next;	
	}
//加减法 
	current=head;	
	while(current!=NULL)
	{
		if(current->oper =='+'||current->oper =='-')
		{
			if(current->count='+')
				sum(&current);
			else
				sub(&current);
		}
		current=current->next;
	}
	
	current=head;
	while(current!=NULL)
	{
		if(current->emm==1)
			printf("%d",current->count );
		else
			printf("%c",current->oper);
			current=current->next ;
	}
	
}
bool s_gets(Cal *current,Char **heads,int emm)
{
	Char *immi=*heads; //因为在后面我们会先改变heads的值,而后又需要用到heads的初值 
	if((*heads)->ch=='=')
		return false;
	if(emm==1)//存储数字 
	{
		int tally=0,sum=0;//sum存储转化的数字 
		while((*heads)->ch>='0'&&(*heads)->ch<='9')
		{
			tally++;
			(*heads)=(*heads)->next;
		}//跳出循环后获得数字位数,heads指针的值也改变成最后一位数字字符后面的 运算符的地址 
		for(int i=tally;i>=1;i--)
		{
			sum=sum+pow(10,i-1)*(immi->ch-'0');
			immi=immi->next;
		}
		current->count =sum;
		current->emm=emm;	
	}
	else
	{
		(*heads)=(*heads)->next;//指向下一位(下一位是数字字符) 
		current->oper =immi->ch;//在这里我最初写的是(*heads)忽略了其值已经改变 
		current->emm =emm;
	}
	return true;
}

void divi(Cal **current)
{
	Cal *temp1,*temp2;
	(*current)->front->count=(*current)->front->count/(*current)->next->count;
	(*current)->front->next=(*current)->next->next;
	if((*current)->next->next!=NULL) 
		(*current)->next->next->front=(*current)->front;
	temp1=(*current);
	temp2=(*current)->next;
	(*current)=(*current)->front;
	
	free(temp1);
	free(temp2);
}
void mul(Cal **current)
{
	Cal *temp1,*temp2;
	(*current)->front->count=((*current)->front->count)*((*current)->next->count);
	(*current)->front->next=(*current)->next->next;
	if((*current)->next->next!=NULL) 
		(*current)->next->next->front=(*current)->front;
	temp1=(*current);
	temp2=(*current)->next;
	(*current)=(*current)->front;
	
	free(temp1);
	free(temp2);
}
void sum(Cal **current)
{
	Cal *temp1,*temp2;
	(*current)->front->count=(*current)->front->count+(*current)->next->count;
	(*current)->front->next=(*current)->next->next;
	if((*current)->next->next!=NULL) 
		(*current)->next->next->front=(*current)->front;
	temp1=(*current);
	temp2=(*current)->next;
	(*current)=(*current)->front;
	
	free(temp1);
	free(temp2);
}
void sub(Cal **current)
{
	Cal *temp1,*temp2;
	(*current)->front->count=(*current)->front->count-(*current)->next->count;
	(*current)->front->next=(*current)->next->next;
	if((*current)->next->next!=NULL) 
		(*current)->next->next->front=(*current)->front;
	temp1=(*current);
	temp2=(*current)->next;
	(*current)=(*current)->front;
	
	free(temp1);
	free(temp2);
}





评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值