第4章第1节练习题4 二叉树高度和宽度统计

时间:2023-02-23 14:19:04

为了方便说明二叉树的递归传值过程,这里首先给出一个基本的二叉树结构。
第4章第1节练习题4 二叉树高度和宽度统计
图中值为NULL的节点实际是不存在的,故与父亲节点之间的连接用灰色的虚线表示。只是为了便于说明,才假设了一个NULL的空节点。
以下图中,黄色的线表明了传值的方向;绿色的数值表明了子节点传到父亲节点时的值,即根据递归公式计算便可。

一.计算二叉树的高度(递归/非递归)

递归方式实现

对于高度的计算,首先是从叶子结点算起,假设叶子结点下面的NULL节点高度为0,则叶子结点的高度便为1,那么叶子结点的双亲节点便为2,以此类推便可以得到根节点的高度,这样也就得到了整棵二叉树的高度。其基本的递归公式如下:

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

具体执行过程可以参考下图,
第4章第1节练习题4 二叉树高度和宽度统计
当指针遍历到叶子结点的孩子结点(NULL结点)时,向叶子结点返回0,然后由叶子结点判断来自左边的孩子结点(NULL结点)和来自右边的孩子结点(其实还是NULL结点)的返回值谁比较大,因为叶子结点处的值均由NULL结点返回,因此相等,则取右边NULL结点的值,然后+1,表示叶子结点的高度。然后再由叶子结点向其双亲节点返回值,依次类推便可以得到整棵树的高度。

算法描述如下

int CntHeight_recursive(BiTNode* T){
    int lh,rh;
    if(T==NULL){
        return 0;
    }
    lh=CntHeight_recursive(T->lchild);
    rh=CntHeight_recursive(T->rchild);
    return lh>rh?lh+1:rh+1;
}

非递归方式实现

采用层次遍历的算法,设置变量cnt表示当前结点所在层次,设置变量last指向当前层最右结点,每次层次遍历出队时与last相比较,如果两者相等,那么层数+1,并让last指向下一层最右结点,直至遍历完成。level的值即为二叉树的高度。
关于last指针的特性应该注意到,当队首指针front指向last标识符时,其队尾指针rear刚好会指向下一层的队尾元素。

算法描述如下

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

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

    int cnt=0;
    int last=1;

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

        if(Q.front==last){
            cnt++;
            last=Q.rear;
        }
    }
    return cnt;
}

二.计算二叉树的宽度(非递归)

关于递归方式,个人没有想到特别好的解决方案,这里主要以非递归方式实现。
非递归方式的实现方式与计算二叉树宽度的非递归实现方式类似,完全可以利用last指针的特性,即当队首指针front指向last时,此时队尾指针rear会刚好指向二叉树下一层的最右边结点,此时只需要用队尾指针rear减去队首指针便可以得到该层的宽度。而二叉树的宽度则指的是从根节点到叶子结点的某层中元素最多的一层,因此只需要将每层的宽度保存下来取最大值便可。

非递归方式实现

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

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

    int cnt=0;
    int last=1;

    int level[MaxSize]={0};

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

        if(Q.front==last){
            level[cnt++]=Q.rear-Q.front;
            last=Q.rear;
        }
    }

    int max=level[0];
    for(int i=0;i<cnt;i++){
        if(max<level[i]){
            max=level[i];
        }
    }

    return max;
}

具体代码见附件。


附件

//统计二叉树的高度和宽度
//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 CntHeight_recursive(BiTNode*);
int CntHeight_norecursive(BiTNode*);

int CntWidth_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;

    count=CntHeight_recursive(T);
    printf("recursive:The height of BiTree is %d\n",count);

    count=CntHeight_norecursive(T);
    printf("non-recursive:The height of BiTree is %d\n",count);

    count=CntWidth_norecursive(T);
    printf("non-recursive:The Width of BiTree is %d\n",count);

    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;
}

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

//统计二叉树的高度(递归)
int CntHeight_recursive(BiTNode* T){
    int lh,rh;
    if(T==NULL){
        return 0;
    }
    lh=CntHeight_recursive(T->lchild);
    rh=CntHeight_recursive(T->rchild);
    return lh>rh?lh+1:rh+1;
}

//统计二叉树的高度(非递归)
int CntHeight_norecursive(BiTNode* T){
    BiTNode* p=T;
    SqQueue Q;

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

    int cnt=0;
    int last=1;

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

        if(Q.front==last){
            cnt++;
            last=Q.rear;
        }
    }
    return cnt;
}

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

//统计二叉树的宽度(非递归)
int CntWidth_norecursive(BiTNode* T){
    BiTNode* p=T;
    SqQueue Q;

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

    int cnt=0;
    int last=1;

    int level[MaxSize]={0};

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

        if(Q.front==last){
            level[cnt++]=Q.rear-Q.front;
            last=Q.rear;
        }
    }

    int max=level[0];
    for(int i=0;i<cnt;i++){
        if(max<level[i]){
            max=level[i];
        }
    }

    return max;
}

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

//先序遍历
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;
    }
}