表达式的基本操作
Status InitBiTree(BiTree &T){
//操作结果:初始化为空树
T=NULL;
return OK;
}
Status InitStack(SqStack &S) {
S.base = (SElemType *) malloc (STACK_INIT_SIZE * sizeof(SElemType));
if(!S.base)
exit(OVERFLOW);
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}
Status Push(SqStack &S, SElemType e) { //元素e压栈
if((S.top - S.base >= S.stacksize)) {
//栈满,追加存储空间
S.base = (SElemType *) realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(SElemType));
if(!S.base) //存储分配失败
exit(OVERFLOW);
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top++ = e;
return OK;
}
Status Pop(SqStack &S, SElemType &e) {
if(S.base == S.top)
return ERROR;
e = *--S.top;
return OK;
}
Status GetTop(SqStack S, SElemType &e) {
if(S.top > S. base) {
e = *(S.top - 1);
return OK;
}
return ERROR;
}
//清空栈
Status ClearStack(SqStack &S){
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}
//判栈空, 空的话返回OK
Status StackEmpty(SqStack S){
if (S.top == S.base)
return OK;
else
return ERROR;
}
//初始化空队列
Status InitQueue(LinkQueue &Q) {
Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
//if (!Q.front) exit (OVERFLOW);//存储分配失败
Q.front->next = NULL;
return OK;
}
//入队列
Status EnQueue(LinkQueue &Q, QElemType e) {
QueuePtr p;
p = (QueuePtr)malloc(sizeof(QNode));
//if (!p) exit (OVERFLOW); //存储分配失败
p->data = e; p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return OK;
}
//出队列
Status DeQueue(LinkQueue &Q, QElemType &e) {
QueuePtr p;
if (Q.front == Q.rear)
return ERROR;
p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if (Q.rear == p)
Q.rear = Q.front;
free (p);
return OK;
}
//判断输入的表达式是否为正确的后缀表达式
Status Judge(SqStack &S){
BiTree T;
InitBiTree(T);
if(StackEmpty(S))
return ERROR;
else{
Pop(S, T);
if(StackEmpty(S)){ //如果栈为空,说明栈中只有一个元素,即是最终的那颗树
Push(S, T); //把正确结果的树入栈,以便后续使用
return OK;
}else{ //如果栈不为空,说明栈中还有许多结点或树,这将不是由正确的后缀表达式所构造出了的结果
return ERROR;
}
}
return OK;
}
//创建二叉树
Status CreateBiTree(BiTree &T, TElemTag te){
T = (BiTree)malloc(sizeof(BiTNode));
T->data = te;
T->lchild = NULL;
T->rchild = NULL;
return OK;
}
//销毁二叉树
void Destory(BiTree &T) {
if(T) {
Destory(T->lchild);
Destory(T->rchild);
free(T);
T = NULL;
}
}
//若c为'0'创建数字叶子结点 ,否则创建字母叶子结点
Status CreatLeftNode(TElemTag &te, double d, int n, char c, SqStack &S, BiTree &T){
if(c == '0'){ //整型
te.tag = INT;
te.n = n;
}else if(c == '1'){ //实型
te.tag = DOU;
te.num = d;
}else if(d == 0.0){ //字符型
if(isdigit(c)){ //当变量为a1这种形式时,取最后一位'1', 此时当做整数处理
te.tag = INT;
te.n = c - '0';
}else{ //正常的单字母变量
te.tag = CHAR;
te.c = c;
}
}
CreateBiTree(T, te);
Push(S, T); //入栈
return OK;
}
//创建分支结点
Status CreatSwitchNode(TElemTag &te, char c, SqStack &S, BiTree &T){
SElemType ST1, ST2;
te.tag = OPER;
te.c = c;
CreateBiTree(T, te);
Pop(S, ST2); //叶子结点出栈,作为分支结点的左右孩子
Pop(S, ST1);
T->lchild = ST1;
T->rchild = ST2;
Push(S, T); //入栈
return OK;
}
//输入函数,用来创建二叉树的核心函数
void Input(SqStack &S, BiTree &T){
TElemTag te;
char a[6]={0}, in[81]={0}; //in为接收键盘输入的字符数组,a为用来存放数字串的字符数组
int len1, len2, j=0;
int flag = 0, num1;
double num;
char c;
getchar(); //接收换行符,因为输入函数的缓冲区处理
gets(in);
len1 = strlen(in);
while(1){ //检查是否存在不规范字符
for(int k=0; k
if(in[k]!=' ' && in[k]!='.' && !isalnum(in[k]) && !(in[k]=='+' || in[k]=='-' || in[k]=='*' || in[k]=='/' || in[k]=='^')){
printf("对不起,你的输入有误,请重新输入!\n");
break;
}
}
if(k >= len1) //输入正确,跳出循环
break;
else{
gets(in);
len1 = strlen(in);
}
}
for(int i=0; i
if((in[i]=='-' && isdigit(in[i+1])) || isdigit(in[i])){ //负数字符串 和 正数字符串
while(in[i]!=' '){ //数字串
if(i == len1) //如果已经是最后一个字符就break
break;
a[j++] = in[i++];
}
len2 = strlen(a);
for(int r=0; r
if(a[r] == '.'){
flag = 1;
break;
}
}
if(flag == 1){
num = atof(a); //将字符串转化为浮点数 atof(a) 出自 #include
CreatLeftNode(te, num, 0, '1', S, T); //第4个参数为'1'说明要创建实数型数字叶子结点
}
else{ //转化为整数
num1 = atoi(a); //atoi(a) 出自 #include
CreatLeftNode(te, 0.1, num1, '0', S, T); //第4个参数为'0'说明要创建整型数字叶子结点
}
for(int p=0; p
a[p] = 0;
}else if(isalpha(in[i])){ //字符变量,如果输入为字符串,则取串中最后一个字符为字符变量
while(in[i]!=' '){
if(i == len1) //如果已经是最后一个字符就break
break;
c = in[i++];
}
CreatLeftNode(te, 0.0, 0, c, S, T); //第二个参数为0.0说明要创建字母叶子结点
}else if(in[i]=='+' || in[i]=='-' || in[i]=='*' || in[i]=='/' || in[i]=='^'){
c = in[i++];
CreatSwitchNode(te, c, S, T); //创建操作符分支结点
}else if(in[i] == ' '){
i++;
}
}
}
//中序遍历
void Inorder(BiTree t){
if(t){
Inorder(t->lchild);
if(t->data.tag == INT)
printf("%d\t", t->data.n);
else if(t->data.tag==CHAR || t->data.tag==OPER)
printf("%c\t", t->data.c);
else if(t->data.tag == DOU)
printf("%lf\t", t->data.num);
Inorder(t->rchild);
}
}
//前序遍历
void Perorder(BiTree t){
if(t){
if(t->data.tag == INT)
printf("%d\t", t->data.n);
else if(t->data.tag==CHAR || t->data.tag==OPER)
printf("%c\t", t->data.c);
else if(t->data.tag == DOU)
printf("%lf\t", t->data.num);
Perorder(t->lchild);
Perorder(t->rchild);
}
}
//求深度
int Depth(BiTree T){
int l=0, r=0;
if(T == NULL)
return 0;
l = Depth(T->lchild);
r = Depth(T->rchild);
if(l > r)
return l+1;
else
return r+1;
}
//创建一个空结点的树,便于在入队列2时把所有结点(包括空结点)入队列
BiTree NullBiTree(){
BiTree T;
TElemTag te;
te.tag = CHAR;
te.c = '#';
InitBiTree(T);
CreateBiTree(T, te);
return T;
//层次遍历二叉树
LinkQueue HierarchyBiTree(BiTree Root){
LinkQueue Q1, Q2; // 保存当前节点的左右孩子的队列
int cout, num = 1;
InitQueue(Q1); // 初始化队列
InitQueue(Q2);
cout = Depth(Root);
cout = (int)pow(2.0, cout*1.0)-1; //深度为K的二叉树的结点总数
if (Root == NULL) //树为空则返回空的Q2
return Q2;
BiTree p = Root; // 临时保存树根Root到指针p中
EnQueue(Q2, p); // 访问根节点,存到第二个队列中,把Visite()函数改为入队列2
if (p->lchild)
EnQueue(Q1, p->lchild); // 若存在左孩子,左孩子进队列1
if (p->rchild)
EnQueue(Q1, p->rchild); // 若存在右孩子,右孩子进队列1
while (num <= cout) { //将从树根到最后一个结都放入队列2中(包括中间的空结点)便于以树形打印二叉树
DeQueue(Q1, p); // 出队列
EnQueue(Q2, p); // 访问根节点,存到第二个队列中
if (p->lchild)
EnQueue(Q1, p->lchild); // 若存在左孩子,左孩子进队列1
else
EnQueue(Q1, NullBiTree()); //否则以空树入队列1
if (p->rchild)
EnQueue(Q1, p->rchild); // 若存在右孩子,右孩子进队列1
else
EnQueue(Q1, NullBiTree());
num++;
}
return Q2;
}
//层次遍历打印
void Print(LinkQueue Q, BiTree T){ //Q为进行层次遍历得到的队列
int i, j;
int c, n;
BiTree t;
InitBiTree(t);
c = Depth(T); //深度
printf("\n\n");
for(i=0; i
n = (int)pow(2.0, i*1.0); //每一层的结点个数
for(j=1; j<=n; j++){
DeQueue(Q, t);
if(i == 0){ //第一层
if(t->data.tag == INT)
printf("\t\t\t\t %d", t->data.n);
else if(t->data.tag==CHAR || t->data.tag==OPER)
printf("\t\t\t\t %c", t->data.c);
else if(t->data.tag == DOU)
printf("\t\t\t\t %lf", t->data.num);
}
if(i == 1){ //第二层
if(t->data.tag == INT)
printf("\t\t%d\t\t", t->data.n);
else if(t->data.tag==CHAR || t->data.tag==OPER)
printf("\t\t%c\t\t", t->data.c);
else if(t->data.tag == DOU)
printf("\t\t%lf\t\t", t->data.num);
}
if(i == 2){ //第三层
if(t->data.c == '#') //空结点
printf(" \t \t");
if(t->data.tag == INT)
printf(" \t%d\t ", t->data.n);
else if((t->data.tag==CHAR || t->data.tag==OPER) && t->data.c != '#')
printf(" \t%c\t ", t->data.c);
else if(t->data.tag == DOU)
printf(" \t%lf\t ", t->data.num);
}
if(i == 3){ //第四层
if(t->data.c == '#') //空结点
printf(" \t");
if(t->data.tag == INT)
printf(" %d\t", t->data.n);
else if((t->data.tag==CHAR || t->data.tag==OPER) && t->data.c != '#')
printf(" %c\t", t->data.c);
else if(t->data.tag == DOU)
printf(" %lf\t", t->data.num);
}
if(i == 4){ //第五层
if(t->data.c == '#') //空结点
printf(" ");
if(t->data.tag == INT)
printf(" %d", t->data.n);
else if((t->data.tag==CHAR || t->data.tag==OPER) && t->data.c != '#')
printf(" %c", t->data.c);
else if(t->data.tag == DOU)
printf(" %lf", t->data.num);
}
}
printf("\n\n\n");
}
}
//检查表达式中是否含有变量,若有返回TRUE
Status Check(BiTree T) {
BiTree t;
InitBiTree(t);
LinkQueue Q;
InitQueue(Q);
Q = HierarchyBiTree(T);
while(!(Q.front == Q.rear)){
DeQueue(Q, t);
if(t->data.tag == CHAR){
if(isalpha(t->data.c))
return TRUE;
}
}
return FALSE;
}
//后序遍历,利用栈对表达式进行运算,最后结果以结点的形式存放在栈中
Status Caculate(BiTree T, SqStack &S){
if(Check(T)){
printf("对不起,此表达式中含有变量,请全部赋值后再计算!\n");
return ERROR;
}
TElemTag te;
BiTree T1, T2, T3;
InitBiTree(T1);
InitBiTree(T2);
InitBiTree(T3);
te.tag = DOU;
te.num = 0.0;
CreateBiTree(T3, te); //T3是用来保存浮点型的运算结果的
double d1, d2;
if(T){
Caculate(T->lchild, S); //后序遍历
Caculate(T->rchild, S);
if(T->data.tag==DOU)
Push(S, T);
else if(T->data.tag == INT){
T3->data.num = (double)T->data.n;
Push(S, T3);
}
else if(T->data.tag==OPER){ //遇操作符,则进行运算
Pop(S, T2);
Pop(S, T1);
switch(T->data.c){
case '+' : if(T1->data.tag == INT) //先把int转为double
d1 = (double)T1->data.n;
else
d1 = T1->data.num;
if(T2->data.tag == INT)
d2 = (double)T2->data.n;
else
d2 = T2->data.num;
T3->data.num = d1 + d2;
Push(S, T3);
break;
case '-' : if(T1->data.tag == INT)
d1 = (double)T1->data.n;
else
d1 = T1->data.num;
if(T2->data.tag == INT)
d2 = (double)T2->data.n;
else
d2 = T2->data.num;
T3->data.num = d1 - d2;
Push(S, T3);
break;
case '*' : if(T1->data.tag == INT)
d1 = (double)T1->data.n;
else
d1 = T1->data.num;
if(T2->data.tag == INT)
d2 = (double)T2->data.n;
else
d2 = T2->data.num;
T3->data.num = d1 * d2;
Push(S, T3);
break;
case '/' : if(T1->data.tag == INT)
d1 = (double)T1->data.n;
else
d1 = T1->data.num;
if(T2->data.tag == INT)
d2 = (double)T2->data.n;
else
d2 = T2->data.num;
if(d2 == 0.0){
printf("对不起,除数不能为0,计算失败\n");
return ERROR;
}else{
T3->data.num = d1 / d2;
Push(S, T3);
break;
}
case '^' : if(T1->data.tag == INT)
d1 = (double)T1->data.n;
else
d1 = T1->data.num;
if(T2->data.tag == INT)
d2 = (double)T2->data.n;
else
d2 = T2->data.num;
T3->data.num = pow(d1, d2);
Push(S, T3);
break;
default : break;
}
}
}
return OK;
}
//对表达式中的所有变量V的赋值c,参数flag为表示是否赋值过的标志
void Assign(BiTree T, char V, int c, int *flag) {
if(T) {
if(T->data.tag==CHAR && T->data.c==V){ //如果找到要赋值的变量,赋值
T->data.tag = INT;
T->data.n = c;
*flag = 1;
}
Assign(T->lchild, V, c, flag); //递归左子树
Assign(T->rchild, V, c, flag); //递归左子树
}
}
//设计者信息
void Designer(){
printf("\t\t Design By XXX\n");
printf("\t\t _______________________\n");
printf("\t\t| 姓名 : | XXX |\n");
printf("\t\t|-----------------------\n");
printf("\t\t| 班级: | 计科1 |\n");
printf("\t\t|-----------------------\n");
printf("\t\t| 学号: | 3112005763|\n");
printf("\t\t ~~~~~~~~~~~~~~~~~~~~~~~\n");
printf("\tCopyright @CKW, All Rights Reserved\n\n");
}
//取得当地时间
void GetTime(){
char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
time_t timep; struct tm *p; time(&timep);
p = localtime(&timep); //取得当地时间
printf ("%d/%d/%d ", (1900+p->tm_year), (1+p->tm_mon), p->tm_mday);
printf("%s\t%d:%d:%d\n", wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
}
//主菜单
void Menu(){
printf("\n\t现在的时间是:");
GetTime();
printf("\n\t\t欢迎使用《表达式类型的表示》系统\n");
printf("\n\t\t请输入你想要进行的操作:\n");
printf("\t1.【输入后缀表达式创建二叉树】2.【输出二叉树的形状】\n");
printf("\t3.【输出二叉树的前缀和中缀】 4.【对表达式中的变量赋值】\n");
printf("\t5.【计算表达式的值】\t 6.【求二叉树的深度】\n");
printf("\t\t\t0.【退出系统!】\n");
}
主函数
void main(){
system("color a"); //设置字体颜色为绿色,其实颜色不重要。。。
char n;
Status flag = ERROR;
BiTree T, T1;
SqStack S, S1;
LinkQueue Q;
InitQueue(Q);
InitStack(S1);
InitStack(S);
InitBiTree(T);
InitBiTree(T1);
Designer();
while(1){
Menu();
scanf(" %c", &n); //此处输入的是字符,因为字符比数字容易处理
// %c前面有个空格是因为scanf()的缓冲区处理
if(n == '0') //如果输入0字符即退出系统
break;
else if('1'<=n && n<='6'){ //1 ~ 6之间
switch(n){
case '1': {
printf("\n请输入正确的后缀表达式(为了便于以树的形状输出二叉树,请保证构造的二叉树深度不超过4):\n");
printf("如果输入多字母的变量,即系统只取最后一个字符作为变量,如果最后一个字符为数字,即当做数字处理。\n");
printf("格式为(X X X):\n");
if(!T){
Destory(T);
}
if(!StackEmpty(S))
ClearStack(S);
Input(S, T);
if(!Judge(S)){ //输入的是不正确的后缀表达式
flag = ERROR;
printf("对不起,你输入的不是正确的后缀表达式,请重新输入!\n");
}else{
flag = OK;
printf("二叉树已构建成功!\n\n\n");
}
break;
}
case '2': {
if(flag != OK){
printf("表达式还没有构造, 请先构造表达式!\n");
break;
}
printf("此二叉树的形状为:\n");
GetTop(S, T); //此二叉树放在一个栈当中,现在取出来
Q = HierarchyBiTree(T); //利用队列对此二叉树进行层次遍历,并把结果放在队列中
Print(Q, T); //按形状打印出来
break;
}
case '3': {
if(flag != OK){
printf("表达式还没有构造, 请先构造表达式!\n");
break;
}
printf("二叉树的前缀序列为:\n");
Perorder(T);
printf("\n\n");
printf("二叉树的中缀序列为:\n");
Inorder(T);
printf("\n\n");
break;
}
case '4': {
if(flag != OK){
printf("表达式还没有构造, 请先构造表达式!\n");
break;
}
int Assign_tag = ERROR; //是否赋值成功的标记
char ch; //保存要赋值的变量的名
int n; //保存要赋的值(为了方便,统一赋值为整型)
printf("请输入要赋值的变量名: ");
ch = getchar();
ch = getchar();
printf("\n要赋值为(为了方便,统一赋值为整型): ");
scanf("%d", &n);
Assign(T, ch, n, &Assign_tag);
if(Assign_tag == OK){
printf("赋值成功!\n");
printf("赋值后表达式为:\n");
GetTop(S, T); //此二叉树放在一个栈当中,现在取出来
Q = HierarchyBiTree(T); //利用队列对此二叉树进行层次遍历,并把结果放在队列中
Print(Q, T); //按树形状打印出来
}else
printf("表达式里没有 %c 这个变量!\n", ch);
break;
}
case '5': {
if(flag != OK){
printf("表达式还没有构造, 请先构造表达式!\n");
break;
}
if(Caculate(T, S1) == OK){ //最终结果作为一个结点放在栈S1中
GetTop(S1, T1); //把结果取出放在树根T1中
printf("表达式的结果是:");
printf("%lf\n", T1->data.num);
}
break;
}
case '6': {
if(flag != OK){
printf("表达式还没有构造, 请先构造表达式!\n");
break;
}
int d = Depth(T);
printf("二叉树的深度为: %d\n", d);
break;
}
default: break;
}
}else{
printf("对不起,您输入的操作有误,请重新输入!\n");
}
}
printf("\t\t\t已安全退出,感谢使用!\n");
}