C语言之四则运算表达式求值(链栈)—支持浮点型数据,负数, 整型数据运算
运算符间的优先级关系:
链栈结构体定义:
数据域使用字符串长度为20的字符数组(故需要注意判断读取的字符串是运算符还是数值)
可支持浮点型数据,负数, 整型数据的运算
float EvaluateExpression() 函数实现步骤:
1)初始化OPTR栈和OPND栈,将表达式起始符 “#” 压入OPTR栈。
2)扫描表达式,读入第一个字符串str,如果表达式没有扫描完毕至 "#" 或压入OPTR的栈顶元素不为 "#" 时,则循环执行以下操作:
——>使用 str_to_float() 函数判断输入的字符串str是否是运算符
——>如果str不是运算符,则压入OPND栈,读取下一个字符串str
——>如果字符串str是运算符,使用 Precede() 函数获取OPTR栈顶元素的运算符和字符串str的运算符的优先级:
——>若是 ‘<’ ,则字符串str压入OPTR栈,读入下一个字符串str
——>若是 ‘>’ ,则弹出OPTR栈顶的运算符字符串,从OPND栈弹出两个数值字符串,使用 Operate() 函数对两个字符串进行运算,将得到的浮点型运算结果使用 float_to_str() 函数转换成字符串型数据,压入OPND栈
——>若是 ‘=’ ,则OPTR的栈顶元素是 "(" 且 str 是 ")" ,这时弹出OPTR栈顶的 "(" ,相当于括号匹配成功,然后读入下一字符串str
3)OPND栈顶元素记为表达式求值结果,输出运算结果。
实现代码(.cpp后缀文件)
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<math.h> 5 6 #define inf float(0x3f3f3f3f) 7 #define MAXSIZE 100 8 9 char priority[7] = {'+', '-', '*', '/', '(', ')', '#'}; 10 11 char priority_relationship[7][7] = { 12 {'>', '>', '<', '<', '<', '>', '>'}, 13 {'>', '>', '<', '<', '<', '>', '>'}, 14 {'>', '>', '>', '>', '<', '>', '>'}, 15 {'>', '>', '>', '>', '<', '>', '>'}, 16 {'<', '<', '<', '<', '<', '=', ' '}, 17 {'>', '>', '>', '>', ' ', '>', '>'}, 18 {'<', '<', '<', '<', '<', ' ', '='} 19 }; // 各个运算符之间的优先级关系 20 21 int get_index(char str[]) 22 {// 获取相应运算符的索引 23 for(int i = 0; i < 7; i++) 24 { 25 if(str[0] == priority[i]) return i; 26 } 27 printf("未找到匹配的字符\n"); 28 } 29 30 char Precede(char inside_data[], char input_data[]) 31 {// 获取两个运算符之间的优先级关系 32 int inside_index = get_index(inside_data); 33 int input_index = get_index(input_data); 34 35 return priority_relationship[inside_index][input_index]; 36 } 37 38 typedef struct StackNode 39 { 40 char data[MAXSIZE]; // 压入栈里面的数据都是字符型,在进行运行时,记得将字符型数字转换为浮点型数字 41 struct StackNode *next; 42 }StackNode, *LinkStack; 43 44 void InitStack(LinkStack &S) 45 {// 构造一个空栈S,栈顶指针置空 46 S = NULL; 47 } 48 49 void Push(LinkStack &S, char data[]) 50 {// 在栈顶插入元素data 51 StackNode *p; 52 53 p = (StackNode *)malloc(sizeof(StackNode)); // 生成新的结点 54 strcpy(p->data, data); // 将新结点的数据域置为data 55 p->next = S; // 将新结点插入栈顶 56 S = p; // 修改栈顶指针为p 57 } 58 59 char *Pop(LinkStack &S) 60 {// 删除S的栈顶元素, 用data返回其值 61 char data[MAXSIZE]; 62 if(S == NULL) printf("错误!!!\n栈为空, 无法执行删除命令..."); 63 else 64 { 65 StackNode *p; 66 67 strcpy(data, S->data); // 将栈顶元素赋给data 68 p = S; // 用p临时保存栈顶元素的空间,以备释放 69 S = S->next; //修改栈顶指针 70 free(p); // 释放原栈顶元素的空间 71 return data; 72 } 73 } 74 75 char *GetTop(LinkStack &S) 76 {// 获取栈顶元素 77 if(S != NULL) 78 return S->data; 79 else 80 { 81 printf("错误!!!\n栈顶为空"); 82 return "0"; 83 } 84 } 85 86 float str_to_float(char *str) 87 {// 将字符串数据转换成浮点型数据 88 float num = 0; 89 int state_1 = 0; // 用于判断是否读取到小数点的状态值, 0代表还没有读取到 90 int state_2 = 0; //用于判断是否读取到负号的状态值, 0代表还没有读取到 91 while(( *str != '\0' && *str >= '0' && *str <= '9') || *str == '.' || (*str == '-' && *(str + 1) != '\0')) 92 {// 注意判断小数点和负号 93 if(*str == '.') state_1 = 1; // 当读取到小数点的时候, 状态值state_1赋值为1 94 else if(*str == '-') state_2 = 1; // 当读取到负号的时候, 状态值state_2赋值为1 95 else 96 { 97 if(state_1 == 0) num = num * 10 + (*str - '0'); 98 else 99 { 100 num += (*str - '0') * pow(0.1, state_1); 101 state_1++; 102 } 103 } 104 str++; 105 } 106 if(*str != '\0') return inf; 107 else if(state_2 == 1) 108 { 109 return num * -1; 110 } 111 else return num; 112 } 113 114 char *float_to_str(float num) 115 {// 将浮点型数据装换成字符串数据,保留浮点型数据小数点后4位的值 116 char str[MAXSIZE]; 117 sprintf(str, "%.4f", num); // 保留小数点后4位 118 return str; 119 } 120 121 122 float Operate(char a[], char theta[], char b[]) 123 {//执行运算 124 float a_num = str_to_float(a); 125 float b_num = str_to_float(b); 126 127 if(theta[0] == '+') return a_num + b_num; 128 else if(theta[0] == '-') return a_num - b_num; 129 else if(theta[0] == '*') return a_num * b_num; 130 else if(theta[0] == '/') return a_num / b_num; 131 else printf("错误!!!\n无该运算符"); 132 } 133 134 void EvaluateExpression() 135 { 136 StackNode *OPND, *OPTR; 137 char str[MAXSIZE]; 138 char theta[MAXSIZE]; 139 char a[MAXSIZE]; 140 char b[MAXSIZE]; 141 142 InitStack(OPND); // 初始化栈 OPND 143 InitStack(OPTR); // 初始化栈 OPTR 144 Push(OPTR, "#"); // 将 "#" 压入栈OPTR 145 146 printf("请输入算术表达式(支持负数,浮点型数据),每个值用空格隔开输入,并以#结束\n"); 147 scanf("%s", str); 148 while(str[0] != '#' || GetTop(OPTR)[0] != '#') 149 { 150 if(str_to_float(str) != inf) 151 { // 如果str不是运算符,则压入OPND栈,读取下一个字符串str 152 Push(OPND, str); // 将字符串str压入OPTR栈 153 scanf("%s", str); // 读入下一个字符串str 154 } 155 else 156 { // 如果字符串str是运算符,使用 Precede() 函数获取OPTR栈顶元素的运算符和字符串str的运算符的优先级 157 switch (Precede(GetTop(OPTR), str)) // 使用 Precede() 函数获取相应优先级 158 { 159 case '<': 160 Push(OPTR, str); // 将字符串str压入OPTR栈 161 scanf("%s", str); // 读入下一个字符串str 162 break; 163 case '>': 164 strcpy(theta, Pop(OPTR)); // 弹出OPTR栈顶的运算符字符串并赋值给变量 theta 165 strcpy(b, Pop(OPND)); // 弹出OPND栈顶的数值字符串并赋值给变量 b 166 strcpy(a, Pop(OPND)); // 弹出OPND栈顶的数值字符串并赋值给变量 a 167 char temp_str[MAXSIZE]; 168 strcpy(temp_str, float_to_str(Operate(a, theta, b))); // 根据相应的三个字符串进行运算,把结果赋给temp_str 169 Push(OPND, temp_str); // 将运算结果 temp_str 压入OPND栈 170 break; 171 case '=': 172 Pop(OPTR); // 弹出OPTR栈顶的运算符字符串 173 scanf("%s", str); // 读入下一个字符串str 174 break; 175 default: 176 printf("错误!!!\n该优先级不存在!!!"); 177 } 178 } 179 } 180 printf("%s\n", GetTop(OPND)); 181 } 182 183 int main(void) 184 { 185 EvaluateExpression(); 186 187 system("pause"); 188 return 0; 189 }
运行结果:
作者:Jony·Li
来源:https://www.cnblogs.com/lzn-2018/
版权声明:本文为博主原创文章,转载请附上博文链接!