第四章第4节 二叉树特殊节点个数统计

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

图中值为NULL的节点实际是不存在的,故与父亲节点之间的连接用灰色的虚线表示。只是为了便于说明,才假设了一个NULL的空节点。

以下图中,黄色的线表明了传值的方向;绿色的数值表明了子节点传到父亲节点时的值,即根据递归公式计算便可。

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

递归方式实现

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

f(T)=? ? ? 0,f(T?>lchild)+f(T?>rchild)+1,f(T?>lchild)+f(T?>rchild), 若T=NULL若T为叶子节点其他情况,若T为单分支节点,或双分支节点

然后可以参考下图

当指针遍历到叶子节点的子节点(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=NULL或T为叶子节点若T为单分支节点其他情况,若T为双分支节点

然后可以参考下图

统计度为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=NULL若T为双分支节点其他情况,若T为单分支节点,或叶子节点

然后可以参考下图

与统计度为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;
    }
}
时间: 2024-08-10 08:13:17

第四章第4节 二叉树特殊节点个数统计的相关文章

C++算法之 求二叉树的节点个数、深度、四种遍历方法

//节点的数据结构 class BTree { public: int m_nValue; BTree* m_nLeft; BTree* m_nRight; public: BTree(int value) { m_nValue = value; } }; 一:求二叉树的节点个数: /* 求二叉数中的节点个数 递归解法: 1:如果二叉树为空,节点的个数为0 2:如果二叉树不为空,二叉树节点的个数 = 左子树节点个数+右子树节点的个数+1: */ int GetNodeCount(BTree* p

六:二叉树中第k层节点个数与二叉树叶子节点个数

二叉树中第k层节点个数 递归解法: (1)如果二叉树为空或者k<1返回0 (2)如果二叉树不为空并且k==1,返回1 (3)如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和 代码如下: int GetNodeNumKthLevel(BinaryTreeNode *pRoot, int k) { if(pRoot == NULL || k < 1) return 0; if(k == 1) return 1; int numLeft = GetNodeN

第4章第3节 二叉树的基本操作(非递归实现)

二叉树的非递归遍历 上一节二叉树的递归遍历中简单介绍了二叉树的递归遍历的实现方式,本节主要介绍二叉树的非递归遍历实现,继续引用上节的例子来说明下. 一.先序遍历 二叉树先序遍历的访问顺序为:根结点->左孩子->右孩子.简单的说,对于任意一个结点,均可以看作是根结点,直接对其访问,如果访问完成后,左孩子不为空,则可以将该左孩子再次看成一个新的根结点,那么就又回到开始,访问根结点,访问左孩子,如果左孩子为空时,访问它的右孩子.对于一般程序而言,递归程序转为非递归程序需要引入栈这个数据结构,可以参考

二叉树(7)----求二叉树叶子节点个数,递归和非递归

1.二叉树定义: typedef struct BTreeNodeElement_t_ { void *data; } BTreeNodeElement_t; typedef struct BTreeNode_t_ { BTreeNodeElement_t *m_pElemt; struct BTreeNode_t_ *m_pLeft; struct BTreeNode_t_ *m_pRight; } BTreeNode_t; 2.求二叉树叶子节点数 叶子节点:即没有左右子树的结点 (1)递归方

第四章 YARN 第一节 YARN应用运行分析

Apache YARN(Yet Another Resource Negotiator)是一个HADOOP集群资源管理系统.YARN在HADOOP2 中引入,但是它足够通用,也支持其它的分布式计算程序. YARN提供了用于请求和使用集群资源的API,但是这些API不是直接由用户代码使用的.用户写更高级的由 分布式计算框架提供的API,这些框架是建立在YARN之上的,对用户隐藏了资源管理的细节.这个情况如图4-1 所示,它显示了一些作为YARN应用的分布式计算框架(MapReduce,Spark等

Learn Prolog Now 翻译 - 第四章 - 列表 - 第一节,列表定义和使用

内容提要 列表定义: 合一在列表中的使用: 匿名变量: 列表定义 正如名字暗示的,列表就是多个元素组成的集合.更精确地说,是元素的有限序列.在Prolog中的列表,有如下的一些具体例子: [mia, vincent, jules, yolanda] [mia, robber(honey_bunny), X, 2, mia] [ ] [mia, [vincent, jules], [butch, girlfriend(butch)]] [[ ], dead(z), [2, [b, c]], [ ]

Learn Prolog Now 翻译 - 第四章 - 列表 - 第二节,列表成员

内容提要 本章主要介绍使用递归操纵列表的一个实际例子:判断一个元素是否在包含在一个列表中. 是时候介绍第一个Prolog中通过递归操纵列表的程序例子了.我们最感兴趣的事情之一是,某个对象是否是列表中的元素.所以,我们想写一个程序,当假设输入是一个对象X和一个列表L, 得出结果是X是否属于L.这个程序的名字通常是:member,是Prolog程序中使用递归操纵列表最简单的例子,如下: member(X, [X|T]). member(X, [H|T]) :- member(X, T). 这就是全部

第4章第2节 二叉树的基本操作(递归实现)

二叉树的递归遍历 所谓二叉树的遍历,本质上就是沿某条搜索路径访问树中的每个结点,使得每个节点均被访问一次,而且仅被访问一次. 由二叉树的基本定义可以知道,遍历一颗二叉树首先必须决定对根结点(N),左子树(L),右子树(R)的访问顺序,按照先遍历左孩子再遍历右孩子的原则,常见的遍历次序有先序遍历(NLR),中序遍历(LNR)和后序遍历(LRN)三种遍历算法. 在这里使用做个简单的例子来说明下. 一.先序遍历 先序遍历的操作过程为: Created with Rapha?l 2.1.0开始二叉树是否

【数字电路】第四章 逻辑电路4-5节知识点

§4.4若干典型的组合逻辑电路 一. 编码器(具有编码功能的逻辑电路) (1)普通编码器:不能同时按下输入键,是根据真值表设计编码器电路. (2)优先编码器:具有一定的优先级,是根据真值表设计的优先编码器电路. 二.译码器(具有译码功能的逻辑电路) (1)译码是编码的逆过程,它的功能是将具有特定含义的二进制码转换成对应的输入信号. (2)二进制译码器:(重点了解74HC138芯片的结构,并根据逻辑函数实现功能) 74HC138芯片: 其中A0.A1.A2是信号的输入端,E1.E2A.E2B为始能