题目要求
主要内容:
设计一个与二叉树基本操作相关的程序。
程序基本要求如下:
①以树状形式输出;
②以先序、中序、后序三种方式输出;
③统计输出二叉树的结点总数、叶子总数、树高。
目录
一、源代码
#include <bits/stdc++.h>
using namespace std;
#define Max 200
typedef struct Node{
char date; //结点数据域
struct Node *lchild,*rchild; //左右孩子指针
int x,y; //横纵坐标
}Node,*tree;
char t[Max][Max];//我们规定画布大小为:Max * Max
int minX=Max,maxX=0;
//函数声明
void index();
void creatTree(tree &T ,int x,int y);
void paintTree(tree T);
void DLR(tree &T);
void LDR(tree T);
void LRD(tree T);
int countNode(tree T);
int countLeaf(tree T);
int treeHigh(tree T);
int main() {
index();
tree T;
while (1)
{
cout << "请选择要执行的操作: ";
int choose;
cin >> choose;
switch (choose) {
case 0:
//创建
case 1: {
//调试用例:ab#df##g##cx##e##
cout << "请按先序输入,以#为结束: ";
creatTree(T, 0, 0);
break;
}
//画树
case 2 : {
int h=treeHigh(T);
cout << "画树如下:" <<endl;
memset(t,' ',sizeof(t));
paintTree(T);
for(int i=0;i<2*h;i++){
for(int j=minX;j<=maxX;j++){
cout << t[j][i];
}
cout << endl;
}
break;
}
//三序遍历
case 3:{
cout << "先序遍历的结果为: ";
DLR(T);
cout << endl;
cout << "中序遍历的结果为: ";
LDR(T);
cout << endl;
cout << "后序遍历的结果为: ";
LRD(T);
cout << endl;
break;
}
//树的属性
case 4:{
cout << "结点总数: "<< countNode(T) << endl;
cout << "叶子总数: "<< countLeaf(T) << endl;
cout << "树的高度: "<< treeHigh(T) << endl;
break;
}
default :cout << "请选择合法的操作" <<endl;
}
}
}
//菜单
void index()
{
cout << "********** 功能如下 **********" << endl;
cout << "\t" << "0 ----> 退出程序" << endl;
cout << "\t" << "1 ----> 先序建立一个树" << endl;
cout << "\t" << "2 ----> 画二叉树" << endl;
cout << "\t" << "3 ----> 三序遍历" << endl;
cout << "\t" << "4 ----> 树的属性" << endl;
}
//画图
void paintTree(tree T)
{
if(T){
// Max/2的使用目的是:由于原坐标是关于y轴对称的,因此我们要将整个图像沿x轴平移
if(' '== t[T->x + Max/2][2 * T->y]) t[T->x + Max/2][2 * T->y]=T->date;
//修改之后
else t[T->x + Max/2+1][2 * T->y]=T->date; //若有字符,后移
//修改之前:
// else t[T->x + Max/2][2 * T->y]='!'; //重复就显示'!'
if(T->lchild){
t[T->x + Max/2 -1][2 * T->y +1]='/';
paintTree(T->lchild);
}
if(T->rchild){
t[T->x + Max/2 +1][2 * T->y +1]='\\';
paintTree(T->rchild);
}
}
}
//先序建立二叉树,并且给出坐标
void creatTree(tree &T ,int x,int y)
{
char c;
cin >> c;
if(c == '#') T=NULL;
else{
//传值
T=new Node;
T->date=c;
T->x=x;
T->y=y;
creatTree(T->lchild,x-2,y+1); //左子树坐标,次数横坐标偏移量为2是为了方便在中间插入'/'
creatTree(T->rchild,x+2,y+1); //右子树坐标
//更新最小最大横坐标
maxX=max(maxX,x+Max/2+1);
minX=min(minX,x+Max/2-1);
}
}
//先序遍历
void DLR(tree &T)
{
if(T){
cout << T->date << " ";
DLR(T->lchild);
DLR(T->rchild);
}
}
//中序遍历
void LDR(tree T)
{
if(T){
LDR(T->lchild);
cout << T->date << " ";
LDR(T->rchild);
}
}
//后序遍历
void LRD(tree T)
{
if(T){
LRD(T->lchild);
LRD(T->rchild);
cout << T->date << " ";
}
}
//结点总数
int countNode(tree T)
{
int l,r;//左右子树的结点数
if(!T) return 0;
if(!T->rchild && T->rchild) return 1;
else{
l= countNode(T->lchild);
r= countNode(T->rchild);
return l+r+1;
}
}
//叶子总数
int countLeaf(tree T)
{
int leaf;
if(!T) return 0;
if(!T->rchild && !T->rchild) return 1;
else leaf= countLeaf(T->lchild)+ countLeaf(T->rchild);
return leaf;
}
//树高
int treeHigh(tree T)
{
int lh,rh;
if(!T) return 0;
else
{
lh= treeHigh(T->lchild);
rh= treeHigh(T->rchild);
return lh>rh ? lh+1 : rh+1;
}
}
二、分析
由于我们题目要求画图,这里我打算使用坐标,故而我们将结构体定义如下:
typedef struct Node{
char date; //结点数据域
struct Node *lchild,*rchild; //左右孩子指针
int x,y; //横纵坐标
}Node,*tree;
这里我选择用一个二维数组作为画布:
char t[Max][Max];//我们规定画布大小为:Max * Max
三、基础函数:
1、构造二叉树
//先序建立二叉树,并且给出坐标
void creatTree(tree &T ,int x,int y)
{
char c;
cin >> c;
if(c == '#') T=NULL;
else{
//传值
T=new Node;
T->date=c;
T->x=x;
T->y=y;
creatTree(T->lchild,x-2,y+1); //左子树坐标,次数横坐标偏移量为2是为了方便在中间插入'/'
creatTree(T->rchild,x+2,y+1); //右子树坐标
}
}
2、三个遍历
//先序遍历
void DLR(tree &T)
{
if(T){
cout << T->date << " ";
DLR(T->lchild);
DLR(T->rchild);
}
}
//中序遍历
void LDR(tree T)
{
if(T){
LDR(T->lchild);
cout << T->date << " ";
LDR(T->rchild);
}
}
//后序遍历
void LRD(tree T)
{
if(T){
LRD(T->lchild);
LRD(T->rchild);
cout << T->date << " ";
}
}
3、计算结点总数、叶子结点树、树高
//结点总数
int countNode(tree T)
{
int l,r;//左右子树的结点数
if(!T) return 0;
if(!T->rchild && T->rchild) return 1;
else{
l= countNode(T->lchild);
r= countNode(T->rchild);
return l+r+1;
}
}
//叶子总数
int countLeaf(tree T)
{
int leaf;
if(!T) return 0;
if(!T->rchild && !T->rchild) return 1;
else leaf= countLeaf(T->lchild)+ countLeaf(T->rchild);
return leaf;
}
//树高
int treeHigh(tree T)
{
int lh,rh;
if(!T) return 0;
else
{
lh= treeHigh(T->lchild);
rh= treeHigh(T->rchild);
return lh>rh ? lh+1 : rh+1;
}
}
基础函数的运行举例
本次用到的输入样例:AB#DF##G##C#E##
图示如下:
结果如下:(黄色部分)
4、画图部分(有需要的小伙伴可以画图分析就很好理解了)
原版:
//画图1(此函数以美观为主)
void paintTree(tree T)
{
if(T){
// Max/2的使用目的是:由于原坐标是关于y轴对称的,因此我们要将整个图像沿x轴平移
if(' '== t[T->x + Max/2][2 * T->y]) t[T->x + Max/2][2 * T->y]=T->date;
else t[T->x + Max/2][2 * T->y]='!'; //重复就显示'!'
if(T->lchild){
t[T->x + Max/2 -1][2 * T->y +1]='/';
paintTree(T->lchild);
}
if(T->rchild){
t[T->x + Max/2 +1][2 * T->y +1]='\\';
paintTree(T->rchild);
}
}
}
结果如下:
这里有误解!!!
我们更换一个测试用例:124##5##36##7##
用例结构如下:
运行结果如下:
修改之后
在次我们可以看到,这个办法会隐藏一部分的数据,当然我们也可以加以修改:
//画图1(此函数以美观为主)
void paintTree(tree T)
{
if(T){
// Max/2的使用目的是:由于原坐标是关于y轴对称的,因此我们要将整个图像沿x轴平移
if(' '== t[T->x + Max/2][2 * T->y]) t[T->x + Max/2][2 * T->y]=T->date;
//修改之后:
else t[T->x + Max/2+1][2 * T->y]=T->date;
//修改之前:
// else t[T->x + Max/2][2 * T->y]='!'; //重复就显示'!'
if(T->lchild){
t[T->x + Max/2 -1][2 * T->y +1]='/';
paintTree(T->lchild);
}
if(T->rchild){
t[T->x + Max/2 +1][2 * T->y +1]='\\';
paintTree(T->rchild);
}
}
}
运行结果如下:
再次修改:此次修改是为了不让两个元素贴在一起,但是外观还是有瑕疵
测试用例:aaaa##a##aa##a##aaa##a##aa##a##
void paintTreeplus(tree T,int l,int r)
{
int mid=(l+r)/2;
if(T){
t[mid][2 * T->y]=T->date;
if(T->lchild){
for(int i=(mid+l)/2;i<mid;i++) t[i][2 * T->y+1] ='/';
paintTreeplus(T->lchild,l,mid);
}
if(T->rchild){
for(int i=mid+1;i<=(mid+r)/2;i++) t[i][2 * T->y+1] ='\\';
paintTreeplus(T->rchild,mid,r);
}
}
}
int main()
{
int minX=0,maxX=pow(2,h)+1;
paintTreeplus(T,minX,maxX);
for(int i=0;i<2*h;i++){
for(int j=minX;j<=maxX;j++){
cout << t[j][i];
}
cout << endl;
}
}
运行结果如下:
你悟解了吗
本篇为个人学习阶段所写,请各位大佬多多斧正。