二叉树的基本操作
实验内容
设计一个与二叉树基本操作相关的演示程序,要求实现以下功能:
(1)创建二叉树。按照用户需要的二叉树,构建二叉树。
(2)将创建的二叉树以树状形式输出。
(3)分别以先序,中序,后序三种遍历方式访问二叉树。
(4)输出二叉树的叶子结点以及叶子结点的个数。
(5)输出二叉树的高度。
存储结构设计
本程序采用二叉链式存储结构(BiTNode)存储二叉树的结点信息。二叉树的链表中的结点至少包括三个域:数据域(data),左孩子指针域(LChild),右孩子指针域(RChild)。
系统功能设计
本程序除了完成二叉树的创建功能外,还设置了8个子功能菜单。由于这8个子功能都是建立在二叉树的构造上,所以二叉树的创建由主函数main()完成。8个子功能设计描述如下:
(1)树状输出二叉树。树状输出二叉树由函数TranslevelPrint()实现。当用户选择该功能时,系统以树状的形式输出用户所创建的二叉树。
(2)先序遍历二叉树。由函数PreOrder()实现。该功能按照先序遍历访问二叉树的方法输出先序序列。
(3)中序遍历二叉树。由函数InOrder()实现。该功能按照中序遍历访问二叉树的方法输出中序序列。
(4)后序遍历二叉树。由函数PostOrder()实现。该功能按照后序遍历访问二叉树的方法输出后序序列。
(5)输出叶子结点。该功能采用先序遍历二叉树的方法,依次输出叶子结点。由函数PreOrderLeaf()实现。
(6)输出叶子结点个数。该功能计算并输出二叉树叶子结点的个数,由LeafCount()函数实现。采用递归算法计算二叉树叶子结点的个数,算法思想是:当二叉树为空时,叶子总结点数为0;当二叉树只有一个结点时,叶子结点个数为1;否则,叶子结点总数为左右子树结点之和。
(7)输出二叉树的深度。该功能即输出二叉树结点所在层次的最大值。由函数PostOrderDepth()实现。
(8)退出。由函数exit()实现。
1 #include<conio.h> 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<math.h> 5 #define MAXLEN 100 6 #define NLAYER 4 7 typedef struct BiTNode 8 { 9 /* data */ 10 char data; 11 struct BiTNode *LChild,*RChild; 12 }BiTNode,*BiTree; 13 BiTree T; 14 //建立二叉树 15 void CreatBiTree(BiTree *bt)//按照先序序列建造二叉树 16 { 17 char ch; 18 scanf("%c",&ch); 19 if(ch=='#') *bt=NULL; 20 else 21 { 22 *bt=(BiTree)malloc(sizeof(BiTNode));//生成一个新的结点 23 (*bt)->data=ch; 24 CreatBiTree(&((*bt)->LChild));//生成左子树 25 CreatBiTree(&((*bt)->RChild)); 26 } 27 } 28 //树形打印二叉树 29 void TranslevelPrint(BiTree bt) 30 { 31 //本算法实现二叉树的按层打印 32 struct node 33 { 34 /* data */ 35 BiTree vec[MAXLEN];//存放树结点 36 int layer[MAXLEN];//结点所在的层 37 int locate[MAXLEN];//打印结点的位置 38 int front,rear; 39 }q; //定义队列q 40 int i,j=1,k=0,nlocate; 41 q.front=0; q.rear=0;//初始化队列q队头,队尾 42 printf(" "); 43 q.vec[q.rear]=bt;//将二叉树根节点入队列 44 q.layer[q.rear]=1; 45 q.locate[q.rear]=20; 46 q.rear=q.rear+1; 47 while(q.front<q.rear) 48 { 49 bt=q.vec[q.front]; 50 i=q.layer[q.front]; 51 nlocate=q.locate[q.front]; 52 if (j<i) //进层打印时换行 53 { 54 printf("\n\n"); 55 j=j+1; k=0; 56 while(k<nlocate) 57 { 58 printf(" "); 59 k++; 60 } 61 } 62 while(k<(nlocate-1)) 63 { 64 printf(" "); 65 k++; 66 } 67 printf("%c",bt->data ); 68 q.front=q.front+1; 69 if(bt->LChild !=NULL)//存在左子树,将左子树根节点入队列 70 { 71 q.vec[q.rear]=bt->LChild; 72 q.layer[q.rear]=i+1; 73 q.locate[q.rear]=(int)(nlocate-pow(2,NLAYER-i-1)); 74 q.rear=q.rear+1; 75 } 76 if(bt->RChild !=NULL) 77 { 78 q.vec[q.rear]=bt->RChild; 79 q.layer[q.rear]=i+1; 80 q.locate[q.rear]=(int)(nlocate+pow(2,NLAYER-i-1)); 81 q.rear=q.rear+1; 82 } 83 } 84 } 85 //输出结点 86 void Visit(char ch) 87 { 88 printf("%c",ch ); 89 } 90 //先序遍历二叉树 91 void PreOrder(BiTree root) 92 { 93 //先序遍历二叉树,root为指向二叉树跟结点的指针 94 if(root!=NULL) 95 { 96 Visit(root->data);//访问根结点 97 PreOrder(root->LChild);//先序遍历左子树 98 PreOrder(root->RChild);//先序遍历右子树 99 } 100 } 101 //中序遍历二叉树 102 void InOrder(BiTree root) 103 { 104 if(root!=NULL) 105 { 106 InOrder(root->LChild); 107 Visit(root->data); 108 InOrder(root->RChild); 109 } 110 } 111 //后序遍历二叉树 112 void PostOrder(BiTree root) 113 { 114 if(root!=NULL) 115 { 116 PostOrder(root->LChild); 117 PostOrder(root->RChild); 118 Visit(root->data); 119 } 120 } 121 //输出叶子结点 122 void PreOrderLeaf(BiTree root) 123 { 124 //先序遍历二叉树并输出叶子结点 125 if(root!=NULL) 126 { 127 if(root->LChild==NULL&& root->RChild==NULL) 128 printf("%c",root->data );//输出叶子结点 129 PreOrderLeaf(root->LChild); 130 PreOrderLeaf(root->RChild); 131 } 132 } 133 //输出叶子结点的个数 134 int LeafCount(BiTree root) 135 { 136 int LeafNum; 137 if(root==NULL) LeafNum=0; 138 else if((root->LChild==NULL)&&(root->RChild==NULL)) LeafNum=1; 139 else LeafNum=LeafCount(root->LChild)+LeafCount(root->RChild); 140 //叶子数为左右子树数目之和 141 return LeafNum; 142 } 143 //输出二叉树的深度 144 int PostTreeDepth(BiTree root) 145 { 146 //后序遍历求二叉树的深度递归算法 147 int hl,hr,max; 148 if(root!=NULL) 149 { 150 hl=PostTreeDepth(root->LChild);//求左子树的深度 151 hr=PostTreeDepth(root->RChild);//求右子树的深度 152 max=hl>hr?hl:hr;//得到左右子树深度较大者 153 return(max+1); 154 } 155 else 156 return 0; 157 } 158 //主要工作函数,操作区用户界面 159 void mainwork() 160 { 161 int yourchoice; 162 printf("\n-------------------------欢迎使用二叉树基本操作程序-------------------\n"); 163 printf("\n 菜 单 选 择 \n\n"); 164 printf(" 1.树状输出二叉树 2.先序遍历二叉树 \n"); 165 printf(" 3.中序遍历二叉树 4.后序遍历二叉树 \n"); 166 printf(" 5.输出叶子结点 6.输出叶子结点的个数 \n"); 167 printf(" 7.输出二叉树的深度 8.退出 \n"); 168 printf("\n----------------------------------------------------------------------\n"); 169 printf("请输入您的选择:"); 170 scanf("%d",&yourchoice); 171 while(!(yourchoice==1||yourchoice==2||yourchoice==3||yourchoice==4 172 ||yourchoice==5||yourchoice==6||yourchoice==7||yourchoice==8)) 173 { 174 printf("输入选择不明确,请重新输入:\n"); 175 scanf("%d",&yourchoice); 176 } 177 while(1) 178 { 179 switch(yourchoice) 180 { 181 case 1:printf("树的形状为:\n"); TranslevelPrint(T);getch();break; 182 case 2:printf("先序遍历序列:\n"); PreOrder(T);getch(); break; 183 case 3:printf("中序遍历序列:\n"); InOrder(T); getch();break; 184 case 4:printf("后序遍历序列:\n"); PostOrder(T); getch();break; 185 case 5:printf("叶子结点为:\n"); PreOrderLeaf(T); getch();break; 186 case 6:printf("叶子结点的个数为:%d",LeafCount(T)); getch();break; 187 case 7:printf("二叉树的深度为:%d",PostTreeDepth(T)); getch();break; 188 case 8:system("cls");exit(0);break; 189 } 190 printf("\n-------------------------欢迎使用二叉树基本操作程序-------------------\n"); 191 printf("\n 菜 单 选 择 \n\n"); 192 printf(" 1.树状输出二叉树 2.先序遍历二叉树 \n"); 193 printf(" 3.中序遍历二叉树 4.后序遍历二叉树 \n"); 194 printf(" 5.输出叶子结点 6.输出叶子结点的个数 \n"); 195 printf(" 7.输出二叉树的深度 8.退出 \n"); 196 printf("\n----------------------------------------------------------------------\n"); 197 printf("请输入您的选择:"); 198 scanf("%d",&yourchoice); 199 } 200 } 201 //主函数 202 int main() 203 { 204 205 printf("首先请输入二叉树的结点序列:\n"); 206 CreatBiTree(&T); 207 printf("请按菜单提示操作:\n"); 208 mainwork(); 209 return 0; 210 }
测试结果
(1)首先输入二叉树结点:
(2)出现主界面:
(3)分别选择不同的功能即可得到不同的结果:
树状输出: 先序,中序,后序遍历分别显示如下:
(4)选择功能5,6,7即可出现叶子结点,叶子结点的个数,和该二叉树的深度
最后,选择功能8,退出该系统。