/*****************************/
/* 二叉树和函数定义 */
/*****************************/
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
#define Max 20 //结点的最大个数
typedef struct node{
char data;
struct node *lchild, *rchild;
}BinTNode; //自定义二叉树的结点类型
typedef BinTNode *BinTree; //定义二叉树的指针
int NodeNum=0,leaf=0; //NodeNum
int CreatedNode=0; //记录生成的结点,防止大于Max的值
BinTree CreatBinTree(void) ; //基于先序遍历算法创建二叉树
void Preorder(BinTree T); //先序遍历二叉树
void Inorder(BinTree T); //中序遍历二叉树
void Postorder(BinTree T); //后序遍历二叉树
int TreeDepth(BinTree T); //采用后序遍历求二叉树的深度、结点数及叶子数的递归算法
void Levelorder(BinTree T); //层次遍历二叉树
int countleaf(BinTree T); //数叶子结点个数
/*****************************/
/* 主函数 */
/*****************************/
int main()
{
BinTree root;
char i;
int depth;
printf("\n");
printf("Creat Bin_Tree; Input preorder:"); //输入完全二叉树的先序序列,用#代表虚结点,如ABD###CE##F##
root=CreatBinTree(); //创建二叉树,返回根结点
do { //从菜单中选择遍历方式,输入序号。
printf("\t********** select ************\n");
printf("\t1: Preorder Traversal\n");
printf("\t2: Iorder Traversal\n");
printf("\t3: Postorder traversal\n");
printf("\t4: PostTreeDepth,Node number,Leaf number\n");
printf("\t5: Level Depth\n"); //按层次遍历之前,先选择4,求出该树的结点数。
printf("\t0: Exit\n");
printf("\t*******************************\n");
fflush(stdin);
scanf("%c",&i); //输入菜单序号(0-5)
switch (i-'0'){
case 1: printf("Print Bin_tree Preorder: ");
Preorder(root); //先序遍历
break;
case 2: printf("Print Bin_Tree Inorder: ");
Inorder(root); //中序遍历
break;
case 3: printf("Print Bin_Tree Postorder: ");
Postorder(root); //后序遍历
break;
case 4:
depth=TreeDepth(root); //求树的深度及叶子数
printf("BinTree Depth=%d BinTree Node number=%d",depth,NodeNum);
printf(" BinTree Leaf number=%d",countleaf(root));
break;
case 5: printf("LevePrint Bin_Tree: ");
Levelorder(root); //按层次遍历
break;
default: exit(1);
}
printf("\n");
} while(i!=0);
return 1;
}
// 9 代码编写
/********************************/
/* 基于先序遍历算法创建二叉树 */
/********************************/
//要求输入先序序列,其中加入虚结点"#"以示空指针的位置
BinTree CreatBinTree(void){
//创建结点,完成初始化
BinTree newNode =(BinTree)malloc(sizeof(BinTNode));
newNode->data=0;
newNode->lchild=NULL;
newNode->rchild=NULL;
//如果生成结点达到20,就直接return
if (CreatedNode==20){
newNode->data='#';
return newNode;
}
//读入数据
char ch=0;
printf("\n输入第%d结点(\"#\"节点被储存但是不被计数):",CreatedNode+1);
scanf("%c",&ch);
newNode->data=ch;
fflush(stdin);
//如果是'#' ,就返回这个新建的虚结点的地址
if(ch=='#')return newNode;
else{
//如果不是'#',就使得CreatedNode(记录生成的结点的个数++);同时创建这个结点的左右子树
CreatedNode++;
newNode->lchild=CreatBinTree();
newNode->rchild=CreatBinTree();
return newNode;
}
}
/********************************/
/* 先序遍历二叉树 */
/********************************/
void Preorder(BinTree T){
//不是虚结点的时候就先打印,这个结点,在分别先后遍历左右子树
if(T->data!='#'){
printf("\ndata=>%c",T->data);
Preorder(T->lchild);
Preorder(T->rchild);
}
}
/********************************/
/* 中序遍历二叉树 */
/********************************/
void Inorder(BinTree T){
//不是虚结点的时候就先遍历左子树,再打印这个结点,再遍历右子树
if(T->data!='#'){
Inorder(T->lchild);
printf("\ndata=>%c",T->data);
Inorder(T->rchild);
}
}
/********************************/
/* 后序遍历二叉树 */
/********************************/
void Postorder(BinTree T){
//不是虚结点的时候就先先遍历左子树,再遍历右子树,再打印这个结点,
if(T->data!='#'){
Postorder(T->lchild);
Postorder(T->rchild);
printf("\ndata=>%c",T->data);
}
}
/************************************************/
/* 采用后序遍历求二叉树的深度、结点数及叶子数 */
/************************************************/
//要求采用递归算法
int TreeDepth(BinTree T){
//如果不为虚结点
if(T->data!='#'){
//先求其左子树的深度
int left_depth=TreeDepth(T->lchild);
//再求右子树深度
int right_depth=TreeDepth(T->rchild);
//结点个数记录
NodeNum++;
//如果左子树深度大于右子树,这个结点深度为左子树深度+1;反之为右结点深度+1
if (left_depth>right_depth){
return left_depth+1;
}else{
return right_depth+1;
}
}else{
//如果是虚结点就返回0
return 0;
}
}
/**************************************************/
/* 利用"先进先出"(FIFO)队列,按层次遍历二叉树 */
/**************************************************/
void Levelorder(BinTree T){
//函数声明
void InitQueue();
void EnQueue(BinTree);
void DeQueue();
//初始化队列
InitQueue();
//先将root根结点传入
EnQueue(T);
//层次遍历二叉树
DeQueue();
}
//定义队列结点结构
typedef struct qnode{
struct node * binNode; //存储二叉树结点地址的数据域
struct qnode *next; //指向前一个队列元素的指针next
}QueueNode,*QueueNodePtr;
//队列头部和尾部指针
typedef struct queue{
struct qnode * front;
struct qnode * rear;
}*Queue;
//定义全局变量队列Q
Queue Q;
//初始化队列头指针、尾指针、生成第一个不存放数据的结点,并将队尾指针和队首指针都指向它
void InitQueue(){
Q=(Queue)malloc(sizeof(queue));
Q->front=(QueueNodePtr)malloc(sizeof(QueueNode));
Q->rear=Q->front;
Q->front->binNode=NULL;
Q->front->next=NULL;
}
//二叉树结点入队操作
void EnQueue(BinTree T){
//新建一个队列结点
QueueNodePtr newNode=(QueueNodePtr)malloc(sizeof(QueueNode));
//此时队列的数据域存储的是二叉树结点的《地址》,方便在后面递归调用的时候直接对这个结点的子结点进行查找
newNode->binNode=T;
newNode->next=NULL;
//移动指针到插入的新结点(新的队尾)
Q->rear->next=newNode;
Q->rear=Q->rear->next;
}
//队首元素出队的函数
void DeQueue(){
//函数声明
void EnQueue(BinTree);
//输出队首元素的值,当队首指针的指向的队首元素不为空
if(Q->front->next){
//输出队首的值
printf("%c",Q->front->next->binNode->data);
//如果左结点不是虚结点,就将队首元素的左结点入队
if(Q->front->next->binNode->lchild->data!='#')
EnQueue(Q->front->next->binNode->lchild);
//如果右结点不是虚结点,就将队首元素的右结点入队
if(Q->front->next->binNode->rchild->data!='#')
EnQueue(Q->front->next->binNode->rchild);
//队头元素出队
Q->front->next=Q->front->next->next;
//递归处理下一个和"原"队首结点地位相同的兄弟结点
DeQueue();
}
}
/********************************/
/* 数叶子结点个数 */
/********************************/
int countleaf(BinTree T)
{
if(!(T->lchild||T->rchild)) return 0; //如果子节点不存在(全面性考虑才加上这个,这一行可以省略)
//如果左右两个孩子的值都为'#'那么它是叶子结点
if(T->lchild->data=='#'||T->rchild->data=='#'){
return 1;
//如果不是,就递归继续寻找它的左子结点和右子结点
}else{
return countleaf(T->lchild)+countleaf(T->rchild);
}
}
数据结构 二叉树 层次遍历/先序遍历/中序遍历/后序遍历/深度/叶节点数
最新推荐文章于 2023-11-12 10:39:25 发布