#include<stdio.h> #include<stdlib.h> #define datatype char #define M 50 #define MAXLEN 50 int num=0,counter1=0,counter2=0; typedef struct node //定义一个二叉链表结构 { datatype data; int lt,rt; struct node *lchild,*rchild; }BT; BT* createtree() // 1---创 建 树 { BT *bt; datatype x; scanf("\n%c",&x); if(x=='0') //指针为空的标志 { bt=NULL; // } else { bt=(BT*)malloc(sizeof(BT)); // 申请一个新的的结点空间 bt->data=x; bt->lchild=createtree(); // 创建结点的左子树 bt->rchild=createtree(); // 创建结点的右子树 } return bt; } ShowTree(BT *T) //2--- 显 示 树 { int i; if(T==NULL) { return; //当结点为空, } else { num++; //全局变量 num 调控结点的位置 printf("\t\t\t"); for(i=0;i<num;i++) { printf(" "); } printf("%c",T->data); for(i=0;i<20-num*2;i++) { printf("-"); } printf("\n"); ShowTree(T->lchild); // 显示结点的左子树 ShowTree(T->rchild); // 显示结点的右子树 num=num-1; } } void Preorder(BT *T) // 3---先 序 遍 历 树 { if(T==NULL) { return; } else // 本函数调用结束 { printf("%c ",T->data); // 输出结点的数据域 Preorder(T->lchild); // 先序递归遍历左子树 Preorder(T->rchild); // 先序递归遍历右子树 } } void Inorder(BT *T) // 4---中 序 遍 历 树 { if(T==NULL) { return; } else // 本函数调用结束 { Inorder(T->lchild); // 中序递归遍历左子树 printf("%c ",T->data); // 输出结点的数据域 Inorder(T->rchild); // 中序递归遍历右子树 } } void Postorder(BT *T) // 5---后 序 遍 历 树 { if(T==NULL) { return; // 本函数调用结束 } else { Postorder(T->lchild); // 后序递归遍历左子树 Postorder(T->rchild); // 后序递归遍历右子树 printf("%c ",T->data); // 输出结点的数据域 } } /* 算法思想 引用BT指针类型的数组(类似栈结构)来保存每个结点和它的左指针; 由于知道它的结点就可以知道它的左子树,所以只需要保存它的结点; 非空树 循环 1.结点指针入栈,直到结点左子树为空; 2.结点出栈,输出出栈结点的值,访问结点右子树; 3.栈和结点右子树不为空继续循环; */ void inorderse(BT *bt) //6---中序非递归遍历树 { int i=0; //栈的初始化 BT *p,*s[M]; //保存每个结点的指针的栈 p=bt; do { while(p!=NULL) { s[i++]=p; //结点的指针入栈 p=p->lchild; //进入左子树 } //左子树为空,退出 if(i>0) //如果栈不空 { p=s[--i]; //结点的指针出栈 printf("%c ",p->data); //访问出栈的结点 p=p->rchild; } }while(i>0||p!=NULL); //右子树为空同时栈空,结束循环 } /* 算法思想 从二叉树根结点开始,先将根结点指针放入队中,然后从队头取出一个结点元素, 每取出一个元素,执行以下操作 1.输出该结点元素的值。 2.若该结点左,右子树不为空,分别把该结点的左,右子树结点入队。 */ void Levelorder(BT *T) // 7----按层次遍历二叉树BT, T 为指向根结点的指针 { int i,j; BT *q[MAXLEN],*p; // q为指针数组用以模拟队列,每个元素均为指向BT类型的指针, 用来存放结点地址 p=T; if (p!=NULL) // 若二叉树非空,则根结点地址入队 { i=1; q[i]=p; j=2; } // i 指向对头,j 指向对尾 while (i!=j) // 当队列不为空时执行循环 { p=q[i]; printf("%c ",p->data); // 访问队首结点的数据域 if( p->lchild!=NULL) { q[j]=p->lchild; j++; } // 将出队结点的左孩子的地址入队 if(p->rchild!=NULL) { q[j]=p->rchild; j++; } // 将出队结点的右孩子的地址入队 i++; } } BT *zxxsh(BT *T) //8----中序非递归线索化二叉树 { BT *p,*pr,*s[M],*t; // int i=0; // 计数变量 t=(BT*)malloc(sizeof(BT)); t->lt=0; // lt 域为指针域 t->rt=1; // rt 域为线索域 t->rchild=t; // 线索后继(右)指向结点本身 if(T==NULL) { t->lchild=t; // 左子树指向结点本身 } else { t->lchild=T; // 左子树指向 bt指针 指向的结点 pr=t; p=T; // do { while(p!=NULL) { s[i++]=p; // 结点指针入栈 p=p->lchild; // 进入左子树 } if(i>0) { p=s[--i]; // 结点指针出栈 printf("%c ",p->data); if(p->lchild==NULL) { p->lt=1; // lt 域为线索域 p->lchild=pr; // 线索前驱指向 pr指针 } if(pr->rchild==NULL) { pr->rt=1; // rt 域为线索域 pr->rchild=p; // 线索前驱指针指向 p指针 } pr=p; p=p->rchild; } }while(i>0||p!=NULL); pr->rchild=t; pr->rt=1; t->rchild=pr; } return t; } void zxblxss (BT *t) // 9----中序遍历找后继线索化二叉树 { BT *p; p=t->lchild; do { while(p->lt==0) { p=p->lchild; // 最左的结点 } printf("%c ",p->data); // 输出最左结点或右子树的左链尾 while( (p->rt==1)&&(p->rchild!=t) ) // 为线索且不是中序的尾结点 { p=p->rchild; // p指向直接后继。 printf("%c ",p->data); // 输出直接后继结点 } p=p->rchild; // p指向右子树 } while( p!=t ); } /* 算法思想 从二叉树T的根结点开始,若二叉树的根结点的左,右子树都为空,该结点为叶子节点; 递归统计树T的左子树结点。 递归统计树T的右子树结点。 */ void Nodenum(BT *T) //10-----统计数总结点数 { if(T==NULL) { return; } else { counter2++; // 全局变量counter2, Nodenum(T->lchild); // 递归统计结点左子树结点个数 Nodenum(T->rchild); // 递归统计结点右子树结点个数 } } /* 算法思想 从根结点开始,若结点左,右子树都为空,该结点为树的叶子结点,counter1++ 递归统计左子树上的叶子节点; 递归统计右子树上的叶子节点; */ void Leafnum(BT *T) // 11-----叶 子 节 点 数 { if(T==NULL) // 开始时,T为根结点所在链结点的指针。 { return; // 若树为空,什么也不做,返回主调函数。 } else { if(T->lchild==NULL&&T->rchild==NULL) { counter1++; // 统计叶子结点个数的全局变量 count(初值为0)加1。 } Leafnum(T->lchild); // 递归统计 T 的左子树叶子结点数。 Leafnum(T->rchild); // 递归统计 T 的右子树叶子结点数 } } /* 算法思想 从根结点开始,结点为空,返回树层数为零。 否则 递归统计左,右子树的层次数; 返回左右子树中层次数较大的那一个; */ int TreeDepth(BT *T) // 12----树 深 度 { int ldep,rdep; // 定义两个变量,存放左、右子树的深度 if(T==NULL) { return 0; } else { ldep=TreeDepth(T->lchild); // 递归统计左子树深度 rdep=TreeDepth(T->rchild); // 递归统计右子树深度 if(ldep>rdep) { return ldep+1; } else { return rdep+1; } } } /* 算法思想 从根结点开始,在树T中查找与x相等的值,若存在则返回该结点的地址, 先从根结点开始,根结点不满足条件,则在结点的左,右子树中查找x的值; */ int mask=0; void Search(BT *T,datatype x) { if(T==NULL) { return ; } else { if(T->data==x) { mask=1; } Search(T->lchild,x); Search(T->rchild,x); } } void meau() { printf("\n\t\t\t 二 叉 树 子 系 统 \n"); printf("\t**************************************************************\n"); printf("\t* 1------建立二叉树的二叉链表存储结构 *\n"); printf("\t* 2------按凹入表显示二叉树 *\n"); printf("\t* 3------按先序遍历二叉树 *\n"); printf("\t* 4------按中序遍历二叉树 *\n"); printf("\t* 5------按后序遍历二叉树 *\n"); printf("\t* 6------按中序非递归调用算法遍历二叉树 *\n"); printf("\t* 7------按层次遍历二叉树 *\n"); printf("\t* 8------按中序非递归调用线索化二叉树 *\n"); printf("\t* 9------按找后继(或前驱)结点的算法遍历中序线索二叉树 *\n"); printf("\t* 10-----统计二叉树的结点总数 *\n"); printf("\t* 11-----统计二叉树的叶子结点总数 *\n"); printf("\t* 12-----统计二叉树的深度 *\n"); printf("\t* 13-----在二叉树中查找值为x的结点 *\n"); printf("\t* 0------返 回 *\n"); printf("\t**************************************************************\n"); printf("\t 请选择要执行的操作代号(0--13): "); } void main() { int i,chiose; datatype x; BT *T,*t; while(1) { meau(); scanf("%d",&chiose); if(chiose==1) { printf("\n\t 按先序次序输入二叉树中结点的值,以0字符表示空树\n"); printf("\t请输入: "); T=createtree(); printf("\t 数据输入完毕!\n"); } else if(chiose==2) { printf("\n\t\t\t凹入表显示二叉树\n"); ShowTree(T); } else if(chiose==3) { printf("\n\t\t先序遍历二叉树: "); Preorder(T); printf("\n"); } else if(chiose==4) { printf("\n\t\t中序遍历二叉树: "); Inorder(T); printf("\n"); } else if(chiose==5) { printf("\n\t\t后序遍历二叉树: "); Postorder(T); printf("\n"); } else if(chiose==6) { printf("\n\t\t中序非递归遍历二叉树: "); inorderse(T); printf("\n"); } else if(chiose==7) { printf("\n\t\t层次遍历二叉树: "); Levelorder(T); printf("\n"); } else if(chiose==8) { printf("\n\t\t中序非递归线索化二叉树为: "); t=zxxsh(T); printf("\n"); } else if(chiose==9) { printf("\n\t\t中序遍历找后继线索化二叉树:"); zxblxss(t); printf("\n"); } else if(chiose==10) { Nodenum(T); printf("\n\t树的节点数为: %d\n",counter2); counter2=0; } else if(chiose==11) { Leafnum(T); printf("\n\t树的叶子节点数为: %d\n",counter1); counter1=0; } else if(chiose==12) { printf("\n\t树的深度为: %d\n",TreeDepth(T)); } else if(chiose==13) { printf("\n\t 输入你要查询的数据:"); scanf("\n%c",&x); Search(T,x); if(mask==1) { printf("\n\t 你要查找的数据%c在二叉树中\n",x); } else { printf("\n\t 你要查找的数据%c不在二叉树中\n",x); } mask=0; } else if(chiose==0) { break; } else { printf("\n\t\t 输入有误,请重新选择操作代号\n"); } } }