更新完毕~可以实现四则混合运算功能~还没有去优化~感觉还可以~试试效果如何~
程序代码:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<conio.h>
#include<string.h>
#define LEN_Node sizeof (Node)
#define LEN_Single sizeof (Single)
#define LEN_Ltem sizeof (Ltem)
typedef enum COM
{
NUMBER, //数字
SINGLE, //运算符号(加减乘除)
ADD, //加号
SUB, //减号
MUL, //乘号
DIV, //除法
POINT, //小数点
LEFT_PARENTHESES, //左括号
RIGHT_PARENTHESES, //右括号
WAIT_USE, //等待使用
CAN_USE, //可以使用
CANNOT_USE, //不能使用
OK, //正常
ERROR, //出错
}COM;
typedef struct Single //运算符号
{
char c; //符号标记
int level; //符号运算优先等级
}Single;
Single single[]={'(',1,')',1,'*',2,'/',2,'+','3','-',3,'.',4};
typedef struct Single_Style
{
COM num; //检查能否使用数字
COM add; //加法状态
COM sub; //减法状态
COM mul; //乘法状态
COM div; //除法状态
COM point; //小数点状态
COM left_parentheses; //左括号状态
COM right_parentheses; //右括号状态
}Single_Style;
Single_Style com={0};
typedef struct Node
{
char c;
struct Node* next;
}Node,*PNode;
typedef union Date //用共用体储存数据
{
double num;
Single single;
}Date;
typedef struct Ltem
{
COM com;
Date date;
struct Ltem* next;
}Ltem,*PLtem;
PNode New_Node(int size); //创建一个头节点
PNode Init(PNode head); //创建一个表达式
PNode Del_Node(PNode p); //删除一个节点
COM Find_Single(char c,char*ch ,int* level); //查找是否存在符号
void Single_CAN_USE(); //运算符可以使用
void Single_CANNOT_USE(); //运算符不可以使用
COM Check(PNode head); //检查表达式输入是否合法
void Print(PNode p); //输出数据
PLtem New_Ltem(); //创建一个项
PLtem Push_Ltem(PLtem h_ltem,PNode h_node); //插入一个项
PLtem Del_Ltem(PLtem p); //删除一个项
void Print_Ltem(PLtem p); //输出一个项
PLtem Del_Parentheses(PLtem h_ltem); //消去括号(原理:括号里面只有一个常数项就可以消除)
PLtem Count_Mul_Div(PLtem h_ltem); //计算乘除法运算
PLtem Count_Add_Sub(PLtem h_ltem); //计算加减法运算
int main()
{
puts("说明:输入表达式只含有+-*/四种运算符号,支持括号和浮点数运算,按ESC键退出");
while (1)
{
PNode head=NULL;
PLtem h_ltem=NULL;
head=New_Node(LEN_Node);
head=Init(head);
if (head->next==NULL)
{
free(head);
continue;
}
if (Check(head)==ERROR)
{
puts("输入表达式有误!");
free(head);
continue;
}
h_ltem=New_Ltem(h_ltem);
h_ltem=Push_Ltem(h_ltem,head);
free(head);
head=NULL;
Print_Ltem(h_ltem);
while (h_ltem->next&&h_ltem->next->next)
{
h_ltem=Del_Parentheses(h_ltem); //去除括号处理
h_ltem=Count_Mul_Div(h_ltem); //计算乘除法运算
h_ltem=Count_Add_Sub(h_ltem); //计算加减运算
}
printf("运算结果是:%g\n",h_ltem->next->date.num);
free(h_ltem->next);
free(h_ltem);
h_ltem=NULL;
puts("按ESC键退出,其余键继续");
if (getch()==27)
break;
}
return 0;
}
PNode New_Node(int Size) //创建一个头节点
{
PNode p=(PNode)malloc(Size);
if (p==NULL)
{
puts("创建失败!");
exit(0);
}
memset(p,0,Size);
return p;
}
PNode Init(PNode head) //创建一个表达式
{
PNode p=head;
char ch=0;
while (p->next) //把指针移到尾部
p=p->next;
puts("请输入表达式:");
while ((ch=getchar())!='\n')
{
p=p->next=New_Node(LEN_Node);
p->c=ch;
}
return head;
}
PNode Del_Node(PNode p) //删除一个节点,并把链表指针移动向下一个节点(相当于出队功能)
{
PNode tp=NULL;
PNode ttp=p;
if (p==NULL||p->next==NULL)
return NULL;
tp=p->next;
p=tp->next;
free(tp);
ttp->next=p;
return ttp;
}
void Print(PNode p) //输出数据
{
puts("输入表达式如下:");
for (;p=p->next;printf("%c",p->c));
puts("");
}
int Find_Single(char c,char*ch ,int* level) //查找是否存在符号
{
int i=0;
if (isdigit(c))
return NUMBER; //返回数字
for (i=0;c!=single[i].c&&i<sizeof(single)/sizeof(*single);++i);
if (i==sizeof(single)/sizeof(*single)) //如果找不到运算符号,则显示出错
return ERROR;
*ch=single[i].c;
*level=single[i].level;
switch (single[i].c)
{
case '(':
return LEFT_PARENTHESES;
case ')':
return RIGHT_PARENTHESES;
case '+':
return ADD;
case '-':
return SUB;
case '*':
return
MUL;
case '/':
return DIV;
case '.':
return POINT;
default :
return ERROR;
}
}
void Single_CAN_USE()
{
com.add=CAN_USE; //可以使用加法
com.sub=CAN_USE; //可以使用减法
com.mul=CAN_USE; //可以使用乘法
com.div=CAN_USE; //可以使用除法
}
void Single_CANNOT_USE()
{
com.add=CANNOT_USE; //不可以使用加法
com.sub=CANNOT_USE; //不可以使用减法
com.mul=CANNOT_USE; //不可以使用乘法
com.div=CANNOT_USE; //不可以使用除法
com.point=CAN_USE;
com.left_parentheses=CAN_USE; //可以使用左括号
com.right_parentheses=CANNOT_USE;//不可以使用右括号
}
COM Check(PNode head)
{
PNode p=head;
COM cc=0;
int parentheses=0; //判断括号是否合理,初始记录括号数目为0
int point=WAIT_USE; //判断小数点是否合理
char ch=0;
char t_ch=0; //暂存单元
int level=0; //运算符优先等级记录(初始化暂不需要)
com.num=CAN_USE;
com.add=CAN_USE; //初始化加号可以用
com.sub=CAN_USE; //初始化减号可以用
com.mul=CANNOT_USE; //初始化乘号可以用
com.div=CANNOT_USE; //初始化除号可以用
com.point=WAIT_USE; //初始化小数点等待使用
com.left_parentheses=CAN_USE; //初始化左括号可以使用
com.right_parentheses=CANNOT_USE; //初始化右括号不可以使用
while (p=p->next) //判断所有字符输入都是合法数据
{
switch (Find_Single(p->c,&ch,&level))
{
case NUMBER: //数字
if (com.num==CANNOT_USE)
return ERROR;
Single_CAN_USE(); //运算符号可以使用
if (com.point==WAIT_USE)
com.point=CAN_USE;
com.right_parentheses=CAN_USE; //数字后面可以跟右括号
break;
case ADD:
if (com.add==CANNOT_USE)
return ERROR;
Single_CANNOT_USE(); //不可以连续使用运算符号
com.point=WAIT_USE; //小数点可以等待使用
com.sub=CAN_USE; //加号后面可以跟减号
com.num=CAN_USE; //符号右边可以使用数字
break;
case SUB:
if (com.sub==CANNOT_USE)
return ERROR;
Single_CANNOT_USE(); //不可以连续使用运算符号
com.point=WAIT_USE;
com.add=CAN_USE; //可以使用加号
com.num=CAN_USE;
break;
case MUL:
if (com.mul==CANNOT_USE)
return ERROR;
case DIV:
if (com.div==CANNOT_USE)
return ERROR;
Single_CANNOT_USE(); //如果遇到乘除运算符号,则该符号不能连续使用
com.point=WAIT_USE;
com.num=CAN_USE;
break;
case POINT:
if (com.point==CAN_USE)
{
Single_CANNOT_USE(); //小数点后面不能直接跟运算符号
com.left_parentheses=CANNOT_USE; //左括号不能使用
com.right_parentheses=CANNOT_USE; //右括号不能使用
com.point=CANNOT_USE;
}
else
return ERROR;
break;
case LEFT_PARENTHESES:
if (com.left_parentheses==CANNOT_USE)
return ERROR;
++parentheses; //记录括号标记个数+1
Single_CANNOT_USE(); //不可以使用运算符号
com.right_parentheses=CANNOT_USE; //右括号不能使用
com.sub=CAN_USE; //重置可以使用加号
com.add=CAN_USE; //重置可以使用减号
break;
case RIGHT_PARENTHESES:
if (com.right_parentheses==CANNOT_USE)
return ERROR;
--parentheses; //记录括号标记个数-1
if (parentheses<0) //如果括号标记小于0
return ERROR;
Single_CAN_USE(); //可以使用运算符号
com.num=CANNOT_USE; //右括号右端不能使用数字
break;
case ERROR:
return ERROR;
default :
return ERROR;
}
t_ch=p->c; //记录暂存单元
}
cc=Find_Single(t_ch,&ch,&level);
if (t_ch!='\0'&&cc!=NUMBER&&cc!=RIGHT_PARENTHESES) //考虑尾数不是数字和右括号的情况
return ERROR;
if (parentheses!=0) //如果括号不匹配
return ERROR;
return OK;
}
PLtem New_Ltem() //创建一个项
{
PLtem p=(PLtem)malloc(LEN_Ltem);
if (p==NULL)
{
puts("创建失败!");
exit(0);
}
memset(p,0,LEN_Ltem);
return p;
}
PLtem Push_Ltem(PLtem h_ltem,PNode h_node) //把合法表达式的储存数据转化为浮点型和保存运算符号
{
PLtem ltem=h_ltem;
PNode node=h_node;
int i=0;
int flag=0;
char Num_Buff[100]={0}; //数据缓冲空间
for (;node->next;i=0)
{
while (node->next->next&&isdigit(node->next->c)||(node->next->c=='.'))
{
Num_Buff[i++]=node->next->c;
node=Del_Node(node);
}
Num_Buff[i]=node->next->c;
if (i)
{
ltem=ltem->next=New_Ltem();
ltem->com=NUMBER;
ltem->date.num=atof(Num_Buff);
flag=1;
}
else if (isdigit(node->next->c)&&flag==0) //处理尾部读取数据情况
{
ltem=ltem->next=New_Ltem();
ltem->com=NUMBER;
ltem->date.num=atof(Num_Buff);
node=Del_Node(node);
}
else if (!isdigit(node->next->c))
{
ltem=ltem->next=New_Ltem();
ltem->com=SINGLE;
Find_Single(node->next->c,<em->date.single.c,<em->date.single.level);
node=Del_Node(node);
flag=0;
}
else
node=Del_Node(node);
memset(Num_Buff,0,sizeof(Num_Buff));
}
return h_ltem;
}
PLtem Del_Ltem(PLtem p) //删除一个项
{
PLtem tp=NULL;
PLtem ttp=p;
if (p==NULL||p->next==NULL)
return NULL;
tp=p->next;
p=tp->next;
free(tp);
ttp->next=p;
return ttp;
}
void Print_Ltem(PLtem p)
{
puts("您输入的表达式为:");
while (p=p->next)
{
if (p->com==NUMBER)
printf("%g",p->date.num);
else
printf("%c",p->date.single.c);
}
puts("");
}
PLtem Del_Parentheses(PLtem h_ltem) //去括号
{
PLtem p1=h_ltem->next;
PLtem p2=h_ltem->next;
double temp=0;
int this_single=0; //判断正负号
COM flag=WAIT_USE;
COM flag2=WAIT_USE;
while (p1=p2=h_ltem->next)
{
flag2=WAIT_USE; //判断有没有消除括号
while (p1&&p2)
{
p1=p2; //每次p1和p2两个指针对齐
this_single=0; //判断正负号标记初始化为0
flag=WAIT_USE; //消除括号条件待定成立
if (p2->com==NUMBER) //如果是数字就继续移动
{
p2=p2->next;
continue;
}
if (p2->date.single.c!='(') //如果是运算符号但不是左括号也继续移动
{
p2=p2->next;
continue;
}
while (p1->com!=SINGLE||p1->date.single.c!=')') //当遇到左括号时,要判断里面是否只有一个常数
{
p1=p1->next;
if (p1->com==SINGLE&&p1->date.single.c=='-') //用来判断正负号
this_single=!this_single;
if (p1->com==SINGLE&&p1->date.single.c=='(') //意味着这里面不是最内层括号
break;
if (p1->com==NUMBER&&flag==WAIT_USE)
{
temp=p1->date.num;
flag=CAN_USE;
}
else if (p1->com==NUMBER&&flag!=WAIT_USE)
flag=CANNOT_USE;
}
if (p1->com==SINGLE&&p1->date.single.c=='(')
{
p2=p1;
continue;
}
if (flag!=CAN_USE) //如果里面不只一个常数意味着不可以删除可以删除
{
p2=p1;
continue;
}
if (this_single) //这条件成立意味着里面是一个负数
temp=-temp;
p2->com=NUMBER; //把左括号的位置换成数字
p2->date.num=temp; //赋值给这个位置
while (p2->next!=p1)
p2=Del_Ltem(p2);
p2=Del_Ltem(p2);
p1=p2;
flag2=CAN_USE;
}
if (flag2!=CAN_USE)
break;
}
return h_ltem;
}
PLtem Count_Mul_Div(PLtem h_ltem) //计算乘除运算
{
PLtem p1=h_ltem->next;
while (p1->next)
{
if (p1->com==NUMBER&&p1->next->com==SINGLE&&p1->next->date.single.c=='*'&&p1->next->next->com==NUMBER)
{
p1->date.num*=p1->next->next->date.num;
p1=Del_Ltem(p1);
p1=Del_Ltem(p1);
continue;
}
if (p1->com==NUMBER&&p1->next->com==SINGLE&&p1->next->date.single.c=='/'&&p1->next->next->com==NUMBER)
{
p1->date.num/=p1->next->next->date.num;
p1=Del_Ltem(p1);
p1=Del_Ltem(p1);
continue;
}
p1=p1->next;
}
return h_ltem;
}
PLtem Count_Add_Sub(PLtem h_ltem) //计算加减法运算
{
PLtem p1=h_ltem->next;
int flag=0;
while (p1->next)
{
if (p1->com==NUMBER||p1->next->com==NUMBER)
{
p1=p1->next;
continue;
}
if (p1->date.single.c!='+'&&p1->date.single.c!='-')
{
p1=p1->next;
continue;
}
while (p1->next->com==SINGLE&&(p1->next->date.single.c=='+'||p1->next->date.single.c=='-'))
{
if (p1->next->date.single.c=='-')
flag=!flag;
p1=Del_Ltem(p1);
}
if (flag&&p1->date.single.c=='+')
p1->date.single.c='-';
else if (flag)
p1->date.single.c='+';
p1=p1->next;
}
p1=h_ltem->next;
while (p1->next)
{
if (p1->com==NUMBER&&p1->next->com==SINGLE&&p1->next->date.single.c=='+'&&p1->next->next->com==NUMBER)
{
p1->date.num+=p1->next->next->date.num;
p1=Del_Ltem(p1);
p1=Del_Ltem(p1);
continue;
}
if (p1->com==NUMBER&&p1->next->com==SINGLE&&p1->next->date.single.c=='-'&&p1->next->next->com==NUMBER)
{
p1->date.num-=p1->next->next->date.num;
p1=Del_Ltem(p1);
p1=Del_Ltem(p1);
continue;
}
p1=p1->next;
}
return h_ltem;
}
[此贴子已经被作者于2017-3-24 12:46编辑过]