C语言实现二叉树的建立、遍历以及表达式的计算
实现代码
#include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <ctype.h> #define StackInitSize 100 #define max 20 #define isNum 1 #define isCha 0 #define lenNum sizeof(struct nodeNum) #define lenCha sizeof(struct nodeCha) #define lenBiTree sizeof(struct biTreeNode) //操作数节点元素 struct nodeNum{ int number; }; //操作符节点元素 struct nodeCha{ char ch; }; //共用体 typedef union demo{ int number; char cha; }Demo; //二叉树节点 struct biTreeNode{ int flag; Demo useUnion; struct biTreeNode *lchild; struct biTreeNode *rchild; }; //二叉树节点栈 !会初始化两个二叉树节点栈! struct biTreeStack{ struct biTreeNode *base; struct biTreeNode *top; int stackSize; }; //操作数栈 struct numStack{ struct nodeNum *base; struct nodeNum *top; int stackSize; }; //操作符栈 struct chaStack{ struct nodeCha *base; struct nodeCha *top; int stackSize; }; //初始化二叉树栈 void biTreeInitStack(struct biTreeStack *stack0) { stack0->base = (struct biTreeNode *)malloc(StackInitSize * lenBiTree); if(!stack0->base) { printf("没有足够空间!\n退出程序!\n"); exit(0); } stack0->top = stack0->base; stack0->stackSize = StackInitSize; } //初始化操作数栈 void numInitStack(struct numStack *stack1) { stack1->base = (struct nodeNum *)malloc(StackInitSize * lenNum); if(!stack1->base) { printf("没有足够空间!\n退出程序!\n"); exit(0); } stack1->top = stack1->base; stack1->stackSize = StackInitSize; } //初始化操作符栈 void chaInitStack(struct chaStack *stack2) { stack2->base = (struct nodeCha *)malloc(StackInitSize * lenCha); if(!stack2->base) { printf("没有足够空间!\n退出程序!\n"); exit(0); } stack2->top = stack2->base; stack2->stackSize = StackInitSize; } //压入操作符 void chaPush(struct chaStack *stack3,char ch) { if(stack3->top - stack3->base >= stack3->stackSize) { printf("栈满!\n退出程序!\n"); exit(0); } stack3->top->ch = ch; stack3->top++; } //压入操作数 void numPush(struct numStack *stack4,int number) { if(stack4->top - stack4->base >= stack4->stackSize) { printf("栈满!\n退出程序!\n"); exit(0); } stack4->top->number = number; stack4->top++; } //压入栈节点 void biTreeNodePush(struct biTreeStack *curBiTree,struct biTreeNode curTreeNode) { if(curBiTree->top - curBiTree->base >= curBiTree->stackSize) { printf("栈满!\n退出程序!\n"); exit(0); } *curBiTree->top = curTreeNode; curBiTree->top++; } //弹出栈节点 //因为是对指针进行操作,在弹完栈后再往里压栈就会覆盖原来的内容,所以就会出现问题!!!!!! struct biTreeNode *biTreeNodePop(struct biTreeStack *curBiTree) { if(curBiTree->top != curBiTree->base) { curBiTree->top--; return curBiTree->top; } else { printf("栈已空!\n退出程序!\n"); exit(0); } } void recoverPtr(struct biTreeStack *curBiTree) { curBiTree->top++; curBiTree->top++; } //弹出操作符 char chaPop(struct chaStack *stack5) { if(stack5->top != stack5->base) { stack5->top--; return stack5->top->ch; } else { printf("栈已空!\n退出程序!\n"); exit(0); } } //弹出操作数 int numPop(struct numStack *stack6) { if(stack6->top != stack6->base) { stack6->top--; return stack6->top->number; } else { printf("栈已空!\n退出程序!\n"); exit(0); } } //运算符栈取顶 char chaGetTop(struct chaStack stack7) { if(stack7.top >= stack7.base) { stack7.top--; return stack7.top->ch; } else { printf("栈已空!\n退出程序!\n"); exit(0); } } //运算数栈取顶 int numGetTop(struct numStack stack8) { if(stack8.top >= stack8.base) { stack8.top--; return stack8.top->number; } else { printf("栈已空!\n退出程序!\n"); exit(0); } } //判断并返回算符间的优先关系 char Precede(char ch1,char ch2) { char ch = ' '; switch(ch1) { case '$': if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||'(' == ch2) { ch = '<'; } else if(')' == ch2) { printf("输入有误!\n退出程序!\n"); exit(0); } else if('$' == ch2) { ch = '='; } break; case ')': if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||')' == ch2||'$' == ch2) { ch = '>'; } else if('(' == ch2) { printf("输入有误!\n退出程序!\n"); exit(0); } break; case '(': if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||'(' == ch2) { ch = '<'; } else if(')' == ch2) { ch = '='; } else if('$' == ch2) { printf("输入有误!\n退出程序!\n"); exit(0); } break; case '/': if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||')' == ch2||'$' == ch2) { ch = '>'; } else if('(' == ch2) { ch = '<'; } break; case '*': if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||')' == ch2||'$' == ch2) { ch = '>'; } else if('(' == ch2) { ch = '<'; } break; case '-': if('+' == ch2||'-' == ch2||')' == ch2||'$' == ch2) { ch = '>'; } else if('*' == ch2||'/' == ch2||'(' == ch2) { ch = '<'; } break; case '+': if('+' == ch2||'-' == ch2||')' == ch2||'$' == ch2) { ch = '>'; } else if('*' == ch2||'/' == ch2||'(' == ch2) { ch = '<'; } break; default: { printf("非法输入!\n退出程序!\n"); exit(0); } } return ch; } //将弹出的数进行计算 int Operate(int numa,char ch,int numb) { int number = 0; switch(ch) { case '+': number = numa + numb; break; case '-': number = numa - numb; break; case '*': number = numa * numb; break; case '/': number = numa / numb; break; } return number; } //先序遍历二叉树 void preOrder(struct biTreeNode *biTree) { if(biTree->flag == isNum) { printf("%d ",biTree->useUnion.number); } else if(biTree->flag == isCha) { printf("%c ",biTree->useUnion.cha); } if(biTree->lchild != NULL) preOrder(biTree->lchild); if(biTree->rchild != NULL) preOrder(biTree->rchild); } //后序遍历二叉树 void aftOrder(struct biTreeNode *biTree) { if(biTree->lchild != NULL) aftOrder(biTree->lchild); if(biTree->rchild != NULL) aftOrder(biTree->rchild); if(biTree->flag == isNum) { printf("%d ",biTree->useUnion.number); } else if(biTree->flag == isCha) { printf("%c ",biTree->useUnion.cha); } } //显示二叉树 void outPutBiTree(struct biTreeNode *biTree) { if(biTree != NULL) { if(biTree->flag == isNum) { printf("%d ",biTree->useUnion.number); } else if(biTree->flag == isCha) { printf("%c ",biTree->useUnion.cha); } } if(biTree->lchild != NULL) { printf("("); outPutBiTree(biTree->lchild); printf(","); } if(biTree->rchild != NULL) { outPutBiTree(biTree->rchild); printf(")"); } } //表达式求值并创建二叉树 int doEvaluateExpression() { char ch,x,the; int numa,numb; int count; int i,temp; long number,num[max]; struct numStack opnd; struct chaStack optr; struct biTreeNode tempTreeNode,*finTreeNode,*treeNode_1,*treeNode_2; struct biTreeStack binaryTree,binaryTree_0; numInitStack(&opnd);//初始化操作数栈 chaInitStack(&optr);//初始化操作符栈 biTreeInitStack(&binaryTree);//初始化二叉树节点栈 biTreeInitStack(&binaryTree_0);//初始化二叉树节点栈副本 chaPush(&optr,'$'); printf("请输入表达式(以$号结束):\n"); ch = getchar(); //如果产生矛盾,可以尝试将所有数据一次性读入一个数组里, //进而可以通过对数组下标进行操作而达到目的, //或者使用ungetc()函数 while(!(ch == '$' && chaGetTop(optr) == '$')) { if(isdigit(ch)) //如果是数字就进运算数栈 { count = 0; number = 0; while(isdigit(ch))//如果getchar()得到的是数字,则连续读 { count++; num[count-1] = ch-48; ch = getchar(); } temp = count; for(i = 0; i < count; i++)//判断数字有几位 { temp--; number += num[i] * pow(10,temp); } numPush(&opnd,number); tempTreeNode.flag = isNum; tempTreeNode.useUnion.number = number; tempTreeNode.rchild = NULL; tempTreeNode.lchild = NULL; biTreeNodePush(&binaryTree,tempTreeNode); } else { //若无限循环则说明 ch 可能为空了 switch(Precede(chaGetTop(optr),ch))//判断优先级 { case '<': //栈顶元素优先权低 chaPush(&optr,ch); ch = getchar(); break; case '=': //脱括号并接收下一个字符 x = chaPop(&optr); ch = getchar(); break; case '>': //退栈并将运算结果入栈 the = chaPop(&optr); numb = numPop(&opnd); numa = numPop(&opnd); numPush(&opnd,Operate(numa,the,numb)); tempTreeNode.flag = isCha; tempTreeNode.useUnion.cha = the; treeNode_1 = biTreeNodePop(&binaryTree); treeNode_2 = biTreeNodePop(&binaryTree); biTreeNodePush(&binaryTree_0,*treeNode_1);//弹出的内容转存到另一个节点栈里,避免覆盖 biTreeNodePush(&binaryTree_0,*treeNode_2);//弹出的内容转存到另一个节点栈里,避免覆盖 tempTreeNode.lchild = biTreeNodePop(&binaryTree_0); tempTreeNode.rchild = biTreeNodePop(&binaryTree_0); recoverPtr(&binaryTree_0);//恢复副本栈里的指针指向 biTreeNodePush(&binaryTree,tempTreeNode); break; default: printf("其他字符!\n退出程序!\n"); exit(0); break; } } } finTreeNode = biTreeNodePop(&binaryTree); printf("\n显示表达式树(广义表)为:\n"); outPutBiTree(finTreeNode); printf("\n\n二叉树先序遍历:\n"); preOrder(finTreeNode);//先序遍历 printf("\n\n二叉树后序遍历:\n"); aftOrder(finTreeNode); return numGetTop(opnd); } int main() { printf("\n\n计算结果是:%d\n",doEvaluateExpression()); return 0; }
测试结果
几年前写的代码了,今天整理了下,居然发现个bug:
作者:Standby — 一生热爱名山大川、草原沙漠,还有我们小郭宝贝!
出处:http://www.cnblogs.com/standby/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://www.cnblogs.com/standby/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。