数据结构 二叉树 层次遍历/先序遍历/中序遍历/后序遍历/深度/叶节点数

/*****************************/
/*    二叉树和函数定义       */
/*****************************/

#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);
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值