第4章第1节练习题3 二叉树特殊节点个数统计

为了方便说明二叉树的递归传值过程,这里首先给出一个基本的二叉树结构。

二叉树

图中值为NULL的节点实际是不存在的,故与父亲节点之间的连接用灰色的虚线表示。只是为了便于说明,才假设了一个NULL的空节点。
以下图中,黄色的线表明了传值的方向;绿色的数值表明了子节点传到父亲节点时的值,即根据递归公式计算便可。

一.统计二叉树中度为0的节点个数(递归/非递归)

递归方式实现

二叉树中,度为0则表明该节点的左孩子、右孩子均为空,根据二叉树的特性,最容易想到的便是采用递归方式实现该答案。首先列出基本递归公式:

f(T)=0,f(T>lchild)+f(T>rchild)+1,f(T>lchild)+f(T>rchild),T=NULLTT

然后可以参考下图

叶子节点

当指针遍历到叶子节点的子节点(NULL节点)时,向父节点返回一个0,又因为该节点是本次遍历需要统计的节点,然后再向父节点返回的时候+1,这样便完成了一次简单的统计,然后再由父节点的父节点对其“汇总”一次,不断的向上递归传值,便完成了叶子节点的统计。

算法描述如下

int CntLfNode_recursive(BiTNode* T){
    if(T==NULL){
        return 0;
    }
    if(T->lchild==NULL&&T->rchild==NULL){
        return CntLfNode_recursive(T->lchild)+CntLfNode_recursive(T->rchild)+1;
    }else{
        return CntLfNode_recursive(T->lchild)+CntLfNode_recursive(T->rchild);
    }
}

非递归方式实现

非递归方式的实现就比较容易理解了,只需要使用第4章第3节 二叉树的基本操作(非递归实现)中给到的遍历二叉树的方法,在访问节点时,判断下该节点的度是否为0:如果是0,则对其计数;如果不是,跳过便可。

这里便主体使用层次遍历方式实现,后对叶子节点进行计数,返回该数目。

int CntLfNode_norecursive(BiTNode* T){
    BiTNode* p=T;
    SqQueue Q;

    InitQueue(&Q);
    EnQueue(&Q,p);

    int cnt=0;
    while(IsEmptyQueue(&Q)!=0){
        p=DeQueue(&Q);
        if(p->lchild==NULL&&p->rchild==NULL){
            cnt++;
        }
        if(p->lchild!=NULL){
            EnQueue(&Q,p->lchild);
        }
        if(p->rchild!=NULL){
            EnQueue(&Q,p->rchild);
        }
    }
    return cnt;
}

二.统计二叉树中度为1的节点个数(递归/非递归)

递归方式实现

统计度为1的节点的递归实现方式与统计度为0的类似,首先列出基本递归公式:

f(T)=0,f(T>lchild)+f(T>rchild)+1,f(T>lchild)+f(T>rchild),T=NULLTTT

然后可以参考下图

单分支节点

统计度为1的节点的传值过程与度为0的节点的传值过程类似,只是本次统计的是单分支节点而已,然后对此节点向父节点的传值的时候+1便可。

算法描述如下

int CntDONode_recursive(BiTNode* T){
    if(T==NULL||(T->lchild==NULL&&T->rchild==NULL)){
        return 0;
    }else if((T->lchild!=NULL&&T->rchild==NULL)||(T->lchild==NULL&&T->rchild!=NULL)){
        return CntDONode_recursive(T->lchild)+CntDONode_recursive(T->rchild)+1;
    }else{
        return CntDONode_recursive(T->lchild)+CntDONode_recursive(T->rchild);
    }
}

非递归方式实现

非递归方式的实现方式与统计度为0的节点方式类似,在访问节点时,判断下该节点的度是否为1:如果是1,则对其计数;如果不是,跳过便可。

这里同样主体使用层次遍历方式实现,后对单分支节点进行计数,返回该数目。

int CntDONode_norecursive(BiTNode* T){
    BiTNode* p=T;
    SqQueue Q;

    InitQueue(&Q);
    EnQueue(&Q,p);

    int cnt=0;
    while(IsEmptyQueue(&Q)!=0){
        p=DeQueue(&Q);
        if((p->lchild!=NULL&&p->rchild==NULL)||(p->lchild==NULL&&p->rchild!=NULL)){
            cnt++;
        }
        if(p->lchild!=NULL){
            EnQueue(&Q,p->lchild);
        }
        if(p->rchild!=NULL){
            EnQueue(&Q,p->rchild);
        }
    }
    return cnt;
}

三.统计二叉树中度为2的节点个数(递归/非递归)

递归方式实现

统计度为2的节点的递归实现方式与统计度为1或度为0的方式类似,首先列出基本递归公式:

f(T)=0,f(T>lchild)+f(T>rchild)+1,f(T>lchild)+f(T>rchild),T=NULLTT

然后可以参考下图

双分支节点

与统计度为0和度为1的传值过程类似,只是需要统计的是双分支节点而已,在传值的时候,需要对双分支节点特殊处理,其他一样。

算法描述如下

int CntDTNode_recursive(BiTNode* T){
    if(T==NULL){
        return 0;
    }
    if(T->lchild!=NULL&&T->rchild!=NULL){
        return CntDTNode_recursive(T->lchild)+CntDTNode_recursive(T->rchild)+1;
    }else{
        return CntDTNode_recursive(T->lchild)+CntDTNode_recursive(T->rchild);
    }
}

非递归方式实现

与度为0和度为1的节点统计方式类似,在访问节点时,判断下该节点的度是否为2:如果是2,则对其计数;如果不是,跳过便可。

同样主体使用层次遍历方式实现,后对双分支节点进行计数,返回该数目。

int CntDTNode_norecursive(BiTNode* T){
    BiTNode* p=T;
    SqQueue Q;

    InitQueue(&Q);
    EnQueue(&Q,p);

    int cnt=0;
    while(IsEmptyQueue(&Q)!=0){
        p=DeQueue(&Q);
        if(p->lchild!=NULL&&p->rchild!=NULL){
            cnt++;
        }
        if(p->lchild!=NULL){
            EnQueue(&Q,p->lchild);
        }
        if(p->rchild!=NULL){
            EnQueue(&Q,p->rchild);
        }
    }
    return cnt;
}

具体代码见附件。


附件

//AB#DG###CE##F##
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 10
typedef char ElemType;
typedef struct BiTNode{
    ElemType data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

typedef struct{
    BiTNode* data[MaxSize];
    int front, rear;
}SqQueue;

BiTNode* CreateBiTree(BiTNode*);

void InitQueue(SqQueue*);
void EnQueue(SqQueue*,BiTNode*);
BiTNode* DeQueue(SqQueue*);
int IsEmptyQueue(SqQueue*);

void PreOrder(BiTNode*);
void InOrder(BiTNode*);


int CntLfNode_recursive(BiTNode*);
int CntLfNode_norecursive(BiTNode*);
int CntDONode_recursive(BiTNode*);
int CntDONode_norecursive(BiTNode*);
int CntDTNode_recursive(BiTNode*);
int CntDTNode_norecursive(BiTNode*);

int main(int argc, char* argv[]){
    BiTNode* T=(BiTNode*)malloc(sizeof(BiTNode));
    T=CreateBiTree(T);

    PreOrder(T);printf("\n");
    InOrder(T);printf("\n");

    int count_lf;
    count_lf=CntLfNode_recursive(T);
    printf("recursive:The count of leaf node is %d\n",count_lf);
    count_lf=CntLfNode_norecursive(T);
    printf("non-recursive:The count of leaf node is %d\n",count_lf);

    int count_do;
    count_do=CntDONode_recursive(T);
    printf("recursive:The count of node of degree one is %d\n",count_do);
    count_do=CntDONode_norecursive(T);
    printf("non-recursive:The count of degree one node is %d\n",count_do);

    int count_dt;
    count_dt=CntDTNode_recursive(T);
    printf("recursive:The count of degree two node is %d\n",count_dt);
    count_dt=CntDTNode_norecursive(T);
    printf("non-recursive:The count of degree two node is %d\n",count_dt);

    return 0;
}

//-------------------------------------------------------------------------------------

BiTNode* CreateBiTree(BiTNode* T){
    ElemType ch;
    scanf("%c",&ch);
    if(ch=='#'){
        return NULL;
    }
    T=(BiTNode*)malloc(sizeof(BiTNode));
    T->data=ch;
    T->lchild=CreateBiTree(T->lchild);
    T->rchild=CreateBiTree(T->rchild);
    return T;
}

//-------------------------------------------------------------------------------------

//统计二叉树中度为0的节点个数(递归)
int CntLfNode_recursive(BiTNode* T){
    if(T==NULL){
        return 0;
    }
    if(T->lchild==NULL&&T->rchild==NULL){
        return CntLfNode_recursive(T->lchild)+CntLfNode_recursive(T->rchild)+1;
    }else{
        return CntLfNode_recursive(T->lchild)+CntLfNode_recursive(T->rchild);
    }
}

//统计二叉树中度为0的节点个数(非递归)
int CntLfNode_norecursive(BiTNode* T){
    BiTNode* p=T;
    SqQueue Q;

    InitQueue(&Q);
    EnQueue(&Q,p);

    int cnt=0;
    while(IsEmptyQueue(&Q)!=0){
        p=DeQueue(&Q);
        if(p->lchild==NULL&&p->rchild==NULL){
            cnt++;
        }
        if(p->lchild!=NULL){
            EnQueue(&Q,p->lchild);
        }
        if(p->rchild!=NULL){
            EnQueue(&Q,p->rchild);
        }
    }
    return cnt;
}

//-------------------------------------------------------------------------------------

//统计二叉树中度为1的节点个数(递归)
int CntDONode_recursive(BiTNode* T){
    if(T==NULL||(T->lchild==NULL&&T->rchild==NULL)){
        return 0;
    }else if((T->lchild!=NULL&&T->rchild==NULL)||(T->lchild==NULL&&T->rchild!=NULL)){
        return CntDONode_recursive(T->lchild)+CntDONode_recursive(T->rchild)+1;
    }else{
        return CntDONode_recursive(T->lchild)+CntDONode_recursive(T->rchild);
    }
}

//统计二叉树中度为1的节点个数(非递归)
int CntDONode_norecursive(BiTNode* T){
    BiTNode* p=T;
    SqQueue Q;

    InitQueue(&Q);
    EnQueue(&Q,p);

    int cnt=0;
    while(IsEmptyQueue(&Q)!=0){
        p=DeQueue(&Q);
        if((p->lchild!=NULL&&p->rchild==NULL)||(p->lchild==NULL&&p->rchild!=NULL)){
            cnt++;
        }
        if(p->lchild!=NULL){
            EnQueue(&Q,p->lchild);
        }
        if(p->rchild!=NULL){
            EnQueue(&Q,p->rchild);
        }
    }
    return cnt;
}

//-------------------------------------------------------------------------------------

//统计二叉树中度为2的节点个数(递归)
int CntDTNode_recursive(BiTNode* T){
    if(T==NULL){
        return 0;
    }
    if(T->lchild!=NULL&&T->rchild!=NULL){
        return CntDTNode_recursive(T->lchild)+CntDTNode_recursive(T->rchild)+1;
    }else{
        return CntDTNode_recursive(T->lchild)+CntDTNode_recursive(T->rchild);
    }
}

//统计二叉树中度为2的节点个数(非递归)
int CntDTNode_norecursive(BiTNode* T){
    BiTNode* p=T;
    SqQueue Q;

    InitQueue(&Q);
    EnQueue(&Q,p);

    int cnt=0;
    while(IsEmptyQueue(&Q)!=0){
        p=DeQueue(&Q);
        if(p->lchild!=NULL&&p->rchild!=NULL){
            cnt++;
        }
        if(p->lchild!=NULL){
            EnQueue(&Q,p->lchild);
        }
        if(p->rchild!=NULL){
            EnQueue(&Q,p->rchild);
        }
    }
    return cnt;
}

//-------------------------------------------------------------------------------------

//先序遍历
void PreOrder(BiTNode* T){
    if(T==NULL){
        return;
    }
    printf("%c",T->data);
    PreOrder(T->lchild);
    PreOrder(T->rchild);
}

//中序遍历
void InOrder(BiTNode* T){
    if(T==NULL){
        return;
    }
    InOrder(T->lchild);
    printf("%c",T->data);
    InOrder(T->rchild);
}

//-------------------------------------------------------------------------------------

//队列的基本操作

void InitQueue(SqQueue* Q){
    Q->front=0;
    Q->rear=0;
}

void EnQueue(SqQueue* Q, BiTNode* T){
    if((Q->rear+1)%MaxSize==Q->front){
        return;
    }
    Q->data[Q->rear++]=T;
}

BiTNode* DeQueue(SqQueue* Q){
    if(Q->front==Q->rear){
        return NULL;
    }
    return Q->data[Q->front++];
}

int IsEmptyQueue(SqQueue* Q){
    if(Q->rear==Q->front){
        return 0;
    }else{
        return -1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值