表达式用叉树表示.docx
《表达式用叉树表示.docx》由会员分享,可在线阅读,更多相关《表达式用叉树表示.docx(12页珍藏版)》请在冰豆网上搜索。
![表达式用叉树表示.docx](https://file1.bdocx.com/fileroot1/2022-12/14/437015c3-5aa5-4d4a-bf15-73b96541f14a/437015c3-5aa5-4d4a-bf15-73b96541f14a1.gif)
表达式用叉树表示
数据结构程序报告(3)
2011.3.29
2.需求分析:
(1)功能:
表达式可以用二叉树表示,对于简单的四则运算,请实现以下功能
【1】对于任意给出的前缀表达式(不带括号)、中缀表达式(可以带括号)或后缀表达式(不带括号),能够在计算机内部构造出一棵表达式二叉树,并且图示出来(图形的形式)。
【2】对于构造好的内部表达式二叉树,按照用户的要求输出相应的前缀表达式(不带括号)、中缀表达式(可以带括号,但不允许冗余括)或后缀表达式(不带括号)。
提示:
所谓中缀表达式中的冗余括号,就是去掉括号后不影响表达式的计算顺序。
例如:
“(c+b)+a”中的括号是冗余的,可以表示成不冗余的“c+b+a”。
(2)输入输出要求:
请输入字符串表达式:
树形二叉树(图形显示)
中缀表达式为:
前缀表达式为:
后缀表达式为:
3.概要设计:
(算法)
分成两部分完成:
【1】前缀、中缀、后缀表达式->二叉树表达式
前缀表达式->二叉树表达式:
(a)碰到操作数则把其值赋给相应的新申请的二叉树结点,地址压栈;(b)碰到操作符则把其值赋给相应的新申请的二叉树,并从栈中弹出两个地址,分别作为其右指针和左指针,然后再把其地址压栈,最后一个地址即为二叉树的根结点地址。
中缀表达式->二叉树表达式:
把中缀表达式转换成后缀表达式,然后再建立二叉树。
后缀表达式->二叉树表达式:
(a)碰到操作数则把其值赋给相应的新申请的二叉树结点,若栈为空则地址压栈,若非空则取栈顶元素,若栈顶元素的左孩子为空则当前结点设为其左孩子,左孩子为满则设为其右孩子再压栈;(b)碰到操作数则把其值赋给相应的新申请的二叉树结点,取栈顶元素,若栈顶元素的左孩子为空则设为其左孩子,左孩子为满则设为其右孩子开始那个元素地址为根结点地址,开始时用变量root保存。
【1】二叉树表达式->前缀、中缀、后缀表达式
二叉树表达式->前缀表达式:
对二叉树表达式进行前序遍历。
二叉树表达式->中缀表达式:
对二叉树表达式进行中序遍历,若结点操作符的优先级高于其左或右子树,在打印相应的子树之前先打印开括号,在打印相应的子树最后在打印一个闭括号。
二叉树表达式->后缀表达式:
对二叉树表达式进行后序遍历。
建立表达式树就是建立树中的每一个结点,将每一个结点链接起来就是整棵树。
而在建立深度低的结点时要将其左右指针指向之前建立的深度比它高一级的结点(如’*’要指向’2’和’3’,而’+’又要指向’*’)。
这样我们可以用栈来存放每次建立的结点,按照优先级(表达式为中缀型)或顺序扫描表达式(表达式为波兰式与逆波兰式)建立每一个结点。
建立结点的顺序即为表达式求值的顺序。
如果扫描到操作数则直接新建一个左右指针为空的结点,并压入结点栈中(存放结点指针)。
遇到运算符时首先新建一个结点,然后从栈中依次弹出两个结点,并让新建立的结点的左右指针域指向它们。
当所有结点建立完毕时,如果表达式没有错误(这里假设输入表达式正确),这时栈中应该只剩下一个结点,它就是所建立的
表达式的根结点。
4.详细设计:
(具体方法)
首先创建一个节点类TNode:
包含操作符oper、左孩子left、右孩子right,isOper()判断是否为操作符,getOperOrder()返回运算符op所对应的优先级,freeTree()程序结束销毁二叉树,postOrder()先序遍历,preOrder()后序遍历,inOrder()中序遍历,ExpTree1()后缀表达式生成二叉树,ExpTree3()前缀表达式生成二叉树,ExpTree2()中后缀表达式生成二叉树,count()求值函数,paint()输出函数
附程序:
#include
#include
#include
#include
#include
usingnamespacestd;
classTNode//节点类
{public:
charoper;
TNode*left;
TNode*right;
ints;intt;
TNode()
{left=right=NULL;
oper=0;
}
TNode(charop)
{left=right=NULL;
oper=op;}};
boolisOper(charop)//判断是否为运算符
{
charoper[]={'(',')','+','-','*','/','^'};
for(inti=0;i{if(op==oper[i])
{
returntrue;
}}
returnfalse;}
intgetOperOrder(charop)//返回运算符op所对应的优先级
{switch(op)
{case'(':
return1;
case'+':
case'-':
return2;
case'*':
case'/':
return3;
case'^':
return4;
default:
//定义在栈中的右括号和栈底字符的优先级最低
return0;
}}
voidfreeTree(TNode*&p)//释放树
{if(p->left!
=NULL)
freeTree(p->left);
if(p->right!
=NULL)
freeTree(p->right);
delete(p);
cout<<"Memoryfree";}
voidpostOrder(TNode*p)//先序遍历
{if(p)
{postOrder(p->left);
postOrder(p->right);
cout<oper;
}}
voidpreOrder(TNode*p)//后序遍历
{if(p)
{cout<oper;
preOrder(p->left);
preOrder(p->right);
}}
voidinOrder(TNode*p)//中序遍历
{if(p)
{if(p->left)
{if(isOper(p->left->oper)
&&getOperOrder(p->left->oper)
oper))
{cout<<"(";
inOrder(p->left);
cout<<")";
}else{
inOrder(p->left);
}}
cout<oper;
if(p->right)
{if(isOper(p->right->oper)
&&getOperOrder(p->right->oper)
<=getOperOrder(p->oper))
{cout<<"(";
inOrder(p->right);
cout<<")";
}else{
inOrder(p->right);
}}}}
voidExpTree1(TNode*&p,stringstr)//后缀表达式生成二叉树
{stacknodeStack;
chartemp;
inti=0;
temp=str[i++];
while(temp!
='\0')
{if(temp!
='\0'&&!
isOper(temp))//不是运算符,则进栈
{p=newTNode(temp);//以temp为结点值构造二叉树结点
nodeStack.push(p);
temp=str[i++];}
else
{p=newTNode(temp);
if(nodeStack.size())
{p->right=nodeStack.top();//若非空则弹栈并设为结点的右孩子
nodeStack.pop();}
if(nodeStack.size())
{p->left=nodeStack.top();//若非空则弹栈并设为结点的左孩子
nodeStack.pop();}
nodeStack.push(p);
temp=str[i++];
}}}
voidExpTree3(TNode*&p,stringstr)//前缀表达式生成二叉树
{stacknodeStack;
chartemp;
inti=str.size()-1;
temp=str[i--];
while(temp!
='\0')
{if(temp!
='\0'&&!
isOper(temp))
{p=newTNode(temp);//以temp为内容来建立新的结点
nodeStack.push(p);
temp=str[i--];}
else
{p=newTNode(temp);
if(nodeStack.size())//若栈顶指针所指结点左孩子为空
{p->left=nodeStack.top();//则当前结点设置成其左孩子
nodeStack.pop();
}if(nodeStack.size())//若栈顶指针所指结点右孩子为空
{p->right=nodeStack.top();//则当前结点设置成其右孩子
nodeStack.pop();//栈顶元素左右孩子指针设置完毕弹出}
nodeStack.push(p);
temp=str[i--];
}}}
voidExpTree2(TNode*&p,stringstr)//中缀表达式转换成后缀表达式生成二叉树
{stacka;
chartemp;
stringPostfixexp="";
inti=0;
temp=str[i++];
while(temp!
='\0')
{if(!
isOper(temp))
{Postfixexp+=temp;
temp=str[i++];}
elseif(temp=='(')//进栈
{a.push(temp);
temp=str[i++];}
elseif(temp==')'){
while(a.top()!
='(')//脱括号
{Postfixexp+=a.top();
a.pop();//在碰到开括号和栈为空前反复弹出栈中元素}
a.pop();
temp=str[i++];
}elseif(temp=='+'||temp=='-'||temp=='*'||temp=='/')//出栈{
while(!
a.empty()&&a.top()!
='('&&getOperOrder(a.top())>=getOperOrder(temp))//若栈非空栈顶不是左括号且栈顶元素优先级不低于输入运算符时,
//将栈顶元素弹出到后缀表达式中,并且str下标加1
{Postfixexp+=a.top();
a.pop();}
a.push(temp);
temp=str[i++];
}}
while(!
a.empty())
{Postfixexp+=a.top();
a.pop();
}
ExpTree1(p,Postfixexp);}
voidcount(TNode*p,int&height,intn)//求值函数
{if(p->left==NULL&&p->right==NULL)
{if(n>height)
height=n;}
if(p->left!
=NULL)
count(p->left,height,n+1);
if(p->right!
=NULL)
count(p->right,height,n+1);}
voidpaint(TNode*p)//输出函数
{intheight=0;
inth=0;
inti;
usingstd:
:
queue;
queueaQueue;
count(p,height,1);
TNode*pointer=p;
TNode*lastpointer;
if(pointer)
{pointer->s=1;
pointer->t=1;
aQueue.push(pointer);}
while(!
aQueue.empty())
{lastpointer=pointer;
pointer=aQueue.front();
aQueue.pop();
if(pointer->s>h)
{cout<h=pointer->s;}
if(pointer->t==1)
{for(i=0;is)-1;i++)
cout<<"";}
elseif(lastpointer->s!
=pointer->s){
for(i=0;i<(pointer->t-1)*(pow(2,height-pointer->s+1)-1)+(pointer->t-1)-1+pow(2,height-pointer->s);i++)
cout<<"";}
else
{for(i=0;i<(pointer->t-lastpointer->t)*(pow(2,height-pointer->s+1)-1)+(pointer->t-lastpointer->t)-1;i++)
cout<<"";}
cout<oper;
if(pointer->left!
=NULL){
pointer->left->s=pointer->s+1;
pointer->left->t=pointer->t*2-1;
aQueue.push(pointer->left);}
if(pointer->right!
=NULL){
pointer->right->s=pointer->s+1;
pointer->right->t=pointer->t*2;
aQueue.push(pointer->right);
}}}
intmain()
{stringexpression;
TNode*tree;
cout<";
cin>>expression;
if(isOper(expression[0]))
ExpTree3(tree,expression);
elseif(isOper(expression[1]))
ExpTree2(tree,expression);
else
ExpTree1(tree,expression);
paint(tree);
cout<cout<<"中缀表达式为:
";
inOrder(tree);
cout<cout<<"前缀表达式为:
";
preOrder(tree);
cout<cout<<"后缀表达式为:
";
postOrder(tree);
cout<freeTree(tree);
cout<system("pause");
return0;}
5.测试数据:
(1)请输入字符串表达式:
-+1*234
-
+4
1*
23
中缀表达式为:
1+2*3-4
前缀表达式为:
-+1*234
后缀表达式为:
123*+4-
memoryfreememoryfreememoryfreememoryfreememoryfree
请按任意键继续………………………..
(2)请输入字符串表达式:
1+2*3-4
-
+4
1*
23
中缀表达式为:
1+2*3-4
前缀表达式为:
-+1*234
后缀表达式为:
123*+4-
memoryfreememoryfreememoryfreememoryfreememoryfree
请按任意键继续………………………..
(3)请输入字符串表达式:
123*+4-
-
+4
1*
23
中缀表达式为:
1+2*3-4
前缀表达式为:
-+1*234
后缀表达式为:
123*+4-
memoryfreememoryfreememoryfreememoryfreememoryfree
请按任意键继续………………………..
测试截图:
6.总结:
程序调试中的问题及解决方法:
前缀表达式建树,通过入栈出栈操作求出前缀表达式的逆序,针对得到的逆序表达式通过后缀表达式建立二叉树的方法,遇到操作数则入栈,遇到操作符则从栈中弹出两个操作数构建一棵小的二叉树,然后将小树的根节点入栈以便于下次操作。
经过循环,小树“长成”大树,表达式读完二叉树即建成。
心得体会:
由于之前的上机较简单,经过这次作业我才深深感受到编程的滋味,真是苦中有乐,完成之后觉得知识点掌握的更加透彻了,因为有好多问题是不上机根本想不到的,只有经过了实践才会有提高,自己还是太缺乏锻炼,应该多动手编程,从整理思路、编写代码、调试程序修改错误等各方面不断完善自己
7.使用说明:
请输入字符串表达式:
可为前缀、中缀、后缀表达式(程序自动判断)