捣腾了一天,总算有个雏形了,先发上来吧,已知的BUG:1.直接输入回车会溢出,2.表达式不完整会溢出,3.多余的)会造成未知的结果,但是如果是在式子的最后是没有问题的,4.中文的字符会报错。
目前已知的就这么多了吧
下面上代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct __stack
{
double number;
char symbol;
struct __stack *next;
struct __stack *prev;
};
typedef struct __stack* p_list;
// cdecl.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
bool priority(const char a, const char b)
{
if ((a == '+' || a == '-') && (b == '*' || b == '/'))
return 1;
else if ((a == '+' || a == '-') && (b == '-' || b == '+'))
return 0;
else if ((a == '*' || a == '/') && (b == '*' || b == '/'))
return 0;
else
return 0;
}
void BeEmpty(p_list head) //释放空间,不需要人为调用
{
p_list temp = head;
for (; temp != NULL; head = temp)
{
temp = head->next;
free(head);
}
}
void frist_time(p_list &head) //首次创建头节点时使用
{
head = (p_list)malloc(sizeof(struct __stack));
head->next = NULL;
head->prev = NULL;
}
void creat_list(p_list &node) //创建其余节点时使用
{
node->next = (p_list)malloc(sizeof(struct __stack));
node->next->prev = node;
node = node->next;
node->next = NULL;
}
double calc(p_list head) //用于计算最后的结果,其中判断运算模式可以自行按照需要修改
{
p_list stuck = NULL, temp, h_temp;
double sum;
for (h_temp = head; h_temp != NULL; h_temp = h_temp->next)
{
if (h_temp->symbol == 0)
{
if (stuck == NULL)
{
frist_time(stuck);
temp = stuck;
}
else
creat_list(temp);
temp->number = h_temp->number;
}
else
{
if (h_temp->symbol == '+')
{
temp->prev->number += temp->number;
p_list t_temp = temp->prev;
free(temp);
temp = t_temp;
}
else if (h_temp->symbol == '-')
{
temp->prev->number -= temp->number;
p_list t_temp = temp->prev;
free(temp);
temp = t_temp;
}
else if (h_temp->symbol == '*')
{
temp->prev->number *= temp->number;
p_list t_temp = temp->prev;
free(temp);
temp = t_temp;
}
else if (h_temp->symbol == '/')
{
temp->prev->number /= temp->number;
p_list t_temp = temp->prev;
free(temp);
temp = t_temp;
}
else
{
printf("\n******Unexpect symbol******\n");
BeEmpty(head);
BeEmpty(stuck);
exit(1);
}
}
}
sum = stuck->number;
stuck->next = NULL;
BeEmpty(stuck);
BeEmpty(head);
return sum;
}
p_list scan_list() //输入中缀表达式
{
p_list t_head = NULL, pl_temp;
char c_temp = '#', str_temp[10];
printf("Input the calculation method:");
for (; c_temp != '\n';)
{
if (!scanf_s("%[0-9]", str_temp, 10))
{
if ((c_temp = getchar()) == '\n');
else
{
if (t_head == NULL)
{
frist_time(t_head);
pl_temp = t_head;
}
else
creat_list(pl_temp);
pl_temp->symbol = c_temp;
pl_temp->number = (double)0xcccccccccccccccc;
}
}
else
{
if (t_head == NULL)
{
frist_time(t_head);
pl_temp = t_head;
}
else
creat_list(pl_temp);
pl_temp->number = atoi(str_temp);
pl_temp->symbol = 0;
}
}
return t_head;
}
void print_list(const p_list head) //打印链表
{
p_list temp = head;
for (; temp != NULL; temp = temp->next)
{
if (temp->number == (double)0xcccccccccccccccc)
printf("%c ", temp->symbol);
else
printf("%f ", temp->number);
}
}
p_list m_bracket(p_list p_temp,p_list &temp, char *stuck_symbol, int i, bool(*p_function)(const char a, const char b))
//遇到括号时调用的函数
{
char *temp_stuck_symbol = stuck_symbol + i; //其中第一个参数对应中缀式节点,第二个对应后缀式节点
int t_i = 0;
for (p_temp = p_temp->next; p_temp->symbol != ')'; p_temp = p_temp->next) //第三个是符号栈,第四个是地址偏移量
{
if (p_temp->symbol == '(') //第五个是优先级判断函数,此函数需要用户按照需求自定义
{
p_temp = m_bracket(p_temp, temp, temp_stuck_symbol, t_i, p_function); //递归调用括号中遇到括号时的情况
if (p_temp->symbol == ')')
break;
}
if (p_temp->symbol == 0)
{
if (temp == NULL)
frist_time(temp);
else
creat_list(temp);
temp->number = p_temp->number;
temp->symbol = 0;
continue;
}
if (t_i == 0 || p_function(stuck_symbol[t_i - 1], p_temp->symbol))
{
temp_stuck_symbol[t_i] = p_temp->symbol;
++t_i;
}
else
{
for (--t_i; t_i >= 0 && !p_function(temp_stuck_symbol[t_i], p_temp->symbol); --t_i)
{
creat_list(temp);
temp->symbol = temp_stuck_symbol[t_i];
temp->number = (double)0xcccccccccccccccc;
}
++t_i;
temp_stuck_symbol[t_i] = p_temp->symbol;
++t_i;
}
}
for (--t_i; t_i >= 0; --t_i)
{
creat_list(temp);
temp->symbol = temp_stuck_symbol[t_i];
temp->number = (double)0xcccccccccccccccc;
}
p_temp = p_temp->next;
return p_temp;
}
p_list Excange(p_list head,bool (*p_function)(const char a, const char b)) //中缀转换后缀主函数,函数指针为优先级判断函数,此函数需要用户按照需求自定义
{
p_list p_temp = head, t_head = NULL, temp;
temp = t_head;
char stuck_symbol[1024];
int i = 0;
for (; p_temp != NULL; p_temp = p_temp->next)
{
if (p_temp->symbol == '(') //遇到括号时
if (temp == t_head)
{
p_temp = m_bracket(p_temp, t_head, stuck_symbol, i, p_function);
temp = t_head;
for (; t_head->prev != NULL; t_head = t_head->prev);
if(p_temp == NULL)
break;
if (p_temp->symbol == ')') //当调用结束后的反括号处理(跳过对这个符号的处理)
break;
}
else
{
p_temp = m_bracket(p_temp, temp, stuck_symbol, i, p_function);
if (p_temp == NULL)
break;
if (p_temp->symbol == ')')
break;
}
if (p_temp->symbol == 0)
{
if (t_head == NULL)
{
frist_time(t_head);
temp = t_head;
t_head->number = p_temp->number;
t_head->symbol = 0;
continue;
}
else
creat_list(temp);
temp->number = p_temp->number;
temp->symbol = 0;
continue;
}
if (i == 0 || p_function(stuck_symbol[i-1], p_temp->symbol))
{
stuck_symbol[i] = p_temp->symbol;
++i;
}
else
{
for (--i; i >=0&&!p_function(stuck_symbol[i], p_temp->symbol); --i)
{
creat_list(temp);
temp->symbol = stuck_symbol[i];
temp->number = (double)0xcccccccccccccccc;
}
++i;
stuck_symbol[i] = p_temp->symbol;
++i;
}
}
for (--i; i >= 0; --i) //清空符号栈
{
creat_list(temp);
temp->symbol = stuck_symbol[i];
temp->number = (double)0xcccccccccccccccc;
}
BeEmpty(head);
return t_head;
}
int main(void)
{
double sum;
p_list head;
head = scan_list();
head = Excange(head,priority);
print_list(head);
sum = calc(head);
printf("\nsum is : %f", sum);
return 0;
}
大概的思路如图:
(资料出处:https://zh.wikipedia.org/wiki/调度场算法)
遇到括号时,当作输入了一个新的中缀表达式处理即可,此时符号栈偏移到之前原本占未使用的部分,并且重新定义指针,让括号处理函数误认为这个是一个新的符号栈
这样最后总转换函数出栈是没有问题的
以上提到的BUG会尽快修复更新,谢谢!