当前位置:文档之家› 实验6:二叉树及其应用

实验6:二叉树及其应用

实验6:二叉树及其应用一、实验目的树是数据结构中应用极为广泛的非线性结构,本单元的实验达到熟悉二叉树的存储结构的 特性,以及如何应用树结构解决具体问题。

二、问题描述首先,掌握二叉树的各种存储结构和熟悉对二叉树的基本操作。

其次,以二叉树表示算术表达 式的基础上,设计一个十进制的四则运算的计算器。

三、实验要求1、 如果利用完全二叉树的性质和二叉链表结构建立一棵二叉树,分别计算a) 统计叶子结点的个数。

b)求二叉树的深度。

2、 十进制的四则运算的计算器可以接收用户来自键盘的输入。

3、 由输入的表达式字符串动态生成算术表达式所对应的二叉树。

4、 自动完成求值运算和输出结果。

四、实验环境PC 微机DOS 操作系统或Windows 操作系统 Turbo C 程序集成环境或 Visual C++程序集成环境五、实验步骤1、 根据二叉树的各种存储结构建立二叉树;2、 设计求叶子结点个数算法和树的深度算法;3、 根据表达式建立相应的二叉树,生成表达式树的模块;如算术表达式:a+b*(c-d)-e/f+/aebCd5、程序运行效果,测试数据分析算法。

六、功能分析4、根据表达式树,求出表达式值,生成求值模块;存储结构typedef union{int Operator; // 操作符float Opera nd; // 操作数}ln t_Float;//表达式树typedef struct Bin aryTreeNode{In t_Float Data; // 数据域int IsOperator; // 判断是不是操作数的标志位struct Bi naryTreeNode *RChild;〃左子树struct Bi naryTreeNode *LChild;〃右子树}BiTreeNode, *lpBiTreeNode;//栈的定义typedef struct {lpBiTreeNode *base;lpBiTreeNode *top;int stacksize;}SqStack;函数一览表lpBiTreeNode GetTop( SqStack s );// 取栈顶结点函数int lsEmpty( SqStack s );// 判空函数int In itStack( SqStack &s );// 初始化栈函数int Pop( SqStack & s, lpBiTreeNode &e );// 出栈函数int Push( SqStack & s, lpBiTreeNode e );// 入栈函数int ln( int c, int* op );// 判断c 是否在op 中int Precede( int thetal, i nt theta2 );// 比较运算符号的优先级int isNum( int c );// 判断是不是数int Getl nput(l nt_Float *Result);// 读入输入的数lpBiTreeNode CreateBiTree();// 创建二叉树bool calculate(lpBiTreeNode Root, float *result);// 计算二叉树化表达式的值in t getLeafNum(lpBiTreeNode Root);// 计算二叉树的叶子结点数in t getDepth(lpBiTreeNode Root);// 计算二叉树的深度递归,核心在于num=nu mleft+ nu mright递归,核心在于depth=max(leftdepth,righydepth)+1Int num(二叉树*p){If (空树)return 0 ;Else if (一个节点的树)return 1 ;Else{Return num (num (左子树)+num (右子树));}}Int depth(二叉树*p){If (空树)return 0 ;Else if (一个节点的树)return 1 ;Else{;Retur nmax (depth (左子树),depth (右子树)+1);}}七、程序代码#i nclude <stdio.h>#i nclude <malloc.h>#defi ne STACK_INIT_SIZE 100#defi ne STACKINCREMENT 10#defi ne ERROR 0#defi ne NUMBER 1#defi ne SIMBLE 2int OP[8] = { '+', '-', '*', '/', '(', ')', '#', 0 };////共用体typedef union{int Operator; // 操作符float Opera nd; // 操作数}In t_Float;//表达式树typedef struct Bin aryTreeNode{In t_Float Data; // 数据域运算符数组int IsOperator; // 判断是不是操作数的标志位struct Bin aryTreeNode *RChild;〃左子树struct Bin aryTreeNode *LChild;〃右子树}BiTreeNode, *lpBiTreeNode;//栈的定义typedef struct {lpBiTreeNode *base;lpBiTreeNode *top;int stacksize;}SqStack;//函数声明区lpBiTreeNode GetTop( SqStack s );// 取栈顶结点函数int lsEmpty( SqStack s );// 判空函数int Ini tStack( SqStack &s );// 初始化栈函数int Pop( SqStack & s, lpBiTreeNode &e );// 出栈函数int Push( SqStack & s, lpBiTreeNode e );// 入栈函数int In( int c, int* op );// 判断c 是否在op 中int Precede( int theta1, i nt theta2 );// 比较运算符号的优先级int isNum( int c );// 判断是不是数int GetI nput(l nt_Float *Result);// 读入输入的数lpBiTreeNode CreateBiTree();// 创建二叉树bool calculate (l pBiTreeNode Root, float *result);// 计算二叉树化表达式的值in t getLeafNu m(l pBiTreeNode Root);// 计算二叉树的叶子结点数in t getDepth (l pBiTreeNode Root);// 计算二叉树的深度int mai n() //主函数{lpBiTreeNode Root;// 二叉树float result; //表达式运算结果if( Root = CreateBiTree() )// 若创建二叉树失败则不会执行if操作{printf(" 二叉树叶子数=%d\n", getLeafNum(Root));printf(" 二叉树的深度=%d\n", getDepth(Root));if( calculate(Root, & result) )// 计算结果{printf(" 表达式的值=%0.2f\n", result);prin tf("INPUT ERROR'n");return 0;IpBiTreeNode GetTop( SqStack s ) {lpBiTreeNode e;if( s.top == s.base )//栈为空情况return NULL;e = *(s.top -1);//top 指针指向栈顶兀素的后一个空间} return e;int IsEmpty( SqStack s ) {if( s.top == s.base )//栈为空return 1; elsereturn 0;}int Ini tStack( SqStack &s ) {s.base = (IpBiTreeNode *)malloc( STACK_INIT_SIZE*sizeof(lpBiTreeNode)栈基址空间if(!s.base)〃 分配空间失败return 0;s.top = s.base;// 栈顶指针s.stacksize = STACK_INIT_SIZE;〃 初始化栈大小return 1;} int Pop( SqStack &s, lpBiTreeNode &e )else printf("ERROR");} elseprintf (”********************************\n"); );//mallocif( s.top == s.base )// return 0;s.top --;//top 指针前移 e = *s.top;〃 取栈顶元素 return 1; }return 0;s.top = s.base + s.stacksize;// 栈顶指针位置 s.stacksize += STACKINCREMENT;// 新栈的大小}*s.top = e;// 元素 e 入栈 s.top ++;// 栈顶指针后移 return 1;int In( int c, int* op ) // 判断c 是否在op 中,op 为以结尾的数组{while( *op != 0 )// 比较所有元素,最后一个为{if( c == *op )// 相等,存在 return 1return 1; op ++;//op 指针后移 } return 0;int Precede( int theta1, i nt theta2 )// {int i, j;int op_look[7][7]=II, , , , , , J 5{'>''>''—>''>' }I, , , , , , J 5 {'>''>''>''>''<''>''>' }I, , , , , ,J 5{'>''>''>''>''<''>''>' }空栈int Push( SqStack & s, IpBiTreeNode e )// {if( s.top - s.base >= s.stacksize )// {s.base = (lpBiTreeNodeSTACKINCREMENT)*sizeof(lpBiTreeNode) );//if(!s.base)入栈函数空间已满 *)realloc(s.base, (s.stacksize +重新分配空间比较优先级I ,,,,,,J 5{ '<' '<' '<' '<' '<' ' = ' ' ' }I , 5 5 5 5 5 J 5{'>''>''>''>'' ''>''>' }I 5 5 5 5 5 5 J 5{ '<' '<' '<' '<' '<' ' ' ' = ' }};〃运算符优先级二维数组switch( thetal )// 定位thetal { case '+':i = 0;break;case '-':i = 1;break;case '*':i = 2;break;case '/':i = 3;break;case '(':i = 4;break;case ')':i = 5;break;case '#':i = 6;break;default:return 0;}switch( theta2 )//定位theta2 {case '+':j = 0; break;case '-':j = 1; break;j = 2; break; case '/':j = 3;break; case '(': j = 4; break; case ')': j = 5; break; case '#':j = 6; break; default:return 0;}return op_look[i][j];〃 }int isNum( int c )// 是不是数字 {if( c >= 'O' && c <= 9 )//ascii码return 1; else return 0;}int c;In t_Float result; int IsNumber = 0; // int IsFloat = 0; // int i,t=1;int GetI nput(l nt_Float *Result) // {static int buffer = 0; // 返回值:无,1数字,2符号缓存存储数字后的符号判断优先级是否为数字 是否为小数result.Opera nd = 0;if(ln( buffer, OP)) II缓存中有符号{result.Operator = buffer;buffer = 0;Result->Operator = result.Operator;return SIMBLE; II 符号}II 去前导空格c = getchar();while ( c == ' ' && c != 10 ){c = getchar();}while( c != ' ' && c != 10 ) II 不是空格和回车{if(isNum(c)) II 是数字{IsNumber = 1;c = c - 48; II 字符到整型if(IsFloat == 0)result.Opera nd = result.Opera nd*10 + c; else{result.Opera nd = result.Opera nd*10 + c; IsFloat++;}}else if(c =='.'){if(IsFloat != 0) II 两个小数点{Result->Opera nd = 0;return ERROR;}elseIsFloat = 1;}else if (In(c, OP)){}if(lsNumber) // 数字后接符号{if(lsFloat == 1){Result->Opera nd = 0;return ERROR;}else{buffer = c;for(i=0; i<lsFloat-1; i++)t*=10;Result->Opera nd = result.Opera nd/(float)t; return NUMBER; // 数字}}else{Result->Operator = c;return SIMBLE; // 符号}}c = getchar();}buffer = 0;if(IsNumber)// 处理数字{if(IsFloat == 1){Result->Opera nd = 0;return ERROR;}else{for(i=0; i<IsFloat-1; i++)t*=10;Result->Opera nd = result.Opera nd/(float)t;return NUMBER;}else if(result.Opera nd == 0)// {Result->Opera nd = 0; return ERROR; }else//处理符号 {Result->Operator = result.Operator; return SIMBLE; } }pNode = (l pBiTreeNode)malloc(sizeof(BiTreeNode)); pNode->Data.Operator = '#'; pNode->IsOperator = 1; pNode->LChild = NULL; pNode->RChild = NULL; Push( Operator, pNode );while( !( r == SIMBLE && c.Operator == '#') || GetTop(Operator)->Data.Operator# )// 处理到#{if(r == ERROR)return NULL; if( r == NUMBER ) // 是数字错误输入lpBiTreeNode CreateBiTree()〃 {SqStack Opera nd; // SqStack Operator; // lpBiTreeNode pNode; lpBiTreeNode theta,a,b; In t_Float c; printf("创建新的二叉树操作数 操作符******************************请输入一个算式并以prin tf("QAQ int r = GetI nput(&c); In itStack(Operand);//In**\n");'#'号结尾:\n")初始化操作数栈 初始化操作符栈!={}pNode = (I pBiTreeNode)malloc(sizeof(BiTreeNode)); pNode->Data.Opera nd =c.Opera nd;pNode->lsOperator = 0;pNode->LChild = NULL;pNode->RChild = NULL;Push(Opera nd,pNode);r = GetI nput(&c);}else if( r == SIMBLE ) // 是符号{switch( Precede(GetTop(Operator)->Data.Operator, c.Operator)){case '<': II栈顶元素优先权低pNode = (l pBiTreeNode)malloc(sizeof(BiTreeNode));pNode->Data.Operator = c.Operator;pNode->IsOperator = 1;pNode->LChild = NULL; pNode->RChild = NULL; Push( Operator, pNode );r = Getl nput (&c);break;case '=': II '(',')' 相遇,脱括号Pop( Operator, pNode );r = Getl nput (&c);break;case '>': II 栈顶元素优先权高,退栈并将运算结果入栈Pop( Operator, theta );Pop( Opera nd, b);Pop( Opera nd, a);theta->LChild = a;theta->RChild = b;Push(Operand, theta);break;}}}retur n GetTop(Opera nd);bool calculate (l pBiTreeNode Root, float *result)〃 { float resultLchild; float resultRchild; if( Root != NULL )// {if(Root->LChild == NULL && Root->RChild == NULL)// {非空*result = Root->Data.Opera nd; return true;计算二叉树的值叶子节点}else if(Root->LChild == NULL || Root->RChild == NULL)//return false;else//左右子树都存在的情况,递归计算 {switch (Root->Data.Operator)〃 {case '+':不可能出现单子树情况取操作符if( calculate(Root->LChild, & resultLchild)==false )return false;if( calculate(Root->RChild, &resultRchild)==false ) return false; *result = resultLchild + resultRchild;值加上右子树的值 break;case '-': // 该二叉树的值等于左子树的值减去右子树的值 if( calculate(Root->LChild, &resultLchild)==false ) return false; if( calculate(Root->RChild, & resultRchild)==false ) return false;*result = resultLchild - resultRchild; // 该二叉树的值等于左子树的break; case '*': if( calculate(Root->LChild, &resultLchild)==false )return false;if( calculate(Root->RChild, &resultRchild)==false )return false;*result = resultLchild * resultRchild;树的值乘上右子树的值//该二叉树的值等于左子break; case '/':if( calculate(Root->LChild, & resultLchild)==false )return false;if( calculate(Root->RChild, &resultRchild)==false ) return false; *result = resultLchild / resultRchild;树除以加上右子树的值break; } } }return true; }in t getLeafNu m(l pBiTreeNode Root)// { int LeafnumLchild;// int LeafnumRchild;// if( Root != NULL )// {if(Root->LChild == NULL && Root->RChild == NULL)计算叶子节点数左子树的叶子结点数 右左子树的叶子结点数 非空//该结点是叶子节点return 1;else {LeafnumLchild = getLeafNum(Root->LChild);〃 LeafnumRchild =getLeafNum(Root->RChild);〃 return LeafnumLchild + LeafnumRchild;// 递归计算左子树的 num 递归计算右子树的num 总的叶子节点数等于左子树的加上右子树的 } } return 0; } in t getDepth (l pBiTreeNode Root)// { int LeafDepthL;// int LeafDepthR;// if( Root !=NULL )//计算二叉树的深度 左子树的深度右子树的深度 非空//该二叉树的值等于左子{if(Root->LChild == NULL && Root->RChild == NULL)return 1; else {LeafDepthL = getDepth(Root->LChild);〃 左子树的深度 LeafDepthR = getDepth(Root->RChild);〃右子树的深度return 1 + (LeafDepthL>LeafDepthR?LeafDepthL:LeafDepthR);〃 左、右子树的最大深度加上1} }return 0; }六、测试数据1、输入数据:2.2* ( 3.1 + 1.20)-7.5/3正确结果:6.96CAUsers\apple-pc\Deskto p\zh r_test.exe帳输人一个算貢:K.2*(3.1+1.20>-7.5/3#I Process e K it G d after 26昏 香 wivh rctwrn请按任意键纟廉续・・・2、输入数据:(1+2)*3+(5+6*7);正确输出:56C :\UsersV ppi e-pc \Deskto p\zhr_te st.exe//叶子结点实际深度等于Bi-4 6 ■兀八、实验总结在实现int getDepth(IpBiTreeNode Root)// 计算二叉树的深度、int getLeafNum(lpBiTreeNode Root)//计算叶子节点数函数时,都用到了递归的思想。

相关主题