【筆記】遍歷二叉樹的應用

Time-space發表於2017-10-29

1.二叉樹的計數

  二叉樹的計數也可以通過遍歷二叉樹來實現,關於二叉樹計數的演算法有求二叉樹葉子節點的個數、非葉子節點的個數。

  • 計算二叉樹葉子結點個數

  求二叉樹的葉子節點的個數遞迴定義如下。

leaf(T)=0,1,leaf(T>lchild)+leaf(T>rchild),T=NULLT
leaf(T)= \left\{\begin{array}{cc} 0, & 當T=NULL時\\ 1, & 當T的左右孩子均為空時\\ leaf(T->lchild)+leaf(T->rchild), & 其他情況 \end{array}\right.

  當二叉樹為空時,葉子節點個數為0;當二叉樹只有一個根節點時,根節點就是葉子節點,葉子節點個數為1;其他情況下,計算左子樹與右子樹中葉子節點的和。由此可得到統計葉子節點個數的演算法。

int LeafCount(BiTree T)
/*統計二叉樹中葉子結點數目*/
{
    if(!T)                                  /*如果是空二叉樹,返回0*/
      return 0;
    else
      if(!T->lchild&&!T->rchild)            /*如果左子樹和右子樹都為空,返回1*/
        return 1;
      else
        return LeafCount(T->lchild)+LeafCount(T->rchild); /*將左子樹葉子結點個數與右子樹葉子結點個數相加*/
}
  • 求二叉樹的非葉子節點個數

  二叉樹的非葉子節點的個數的遞迴定義如下:

Notleaf(T)=0,0,Notleaf(T>lchild)+Notleaf(T>rchild)+1,T=NULLT
Notleaf(T)= \left\{\begin{array}{cc} 0, & 當T=NULL時\\ 0, & 當T的左右孩子均為空時\\ Notleaf(T->lchild)+Notleaf(T->rchild)+1, & 其他情況 \end{array}\right.

  當二叉樹為空時,非葉子結點的個數為0;當二叉樹只有根節點時,根節點為葉子結點,非葉子節點個數為0;其他情況下,非葉子結點個數為左子樹與右子樹中非葉子節點的個數再加1(根結點)。

int NotLeafCount(BiTree T)
/*統計二叉樹中非葉子結點數目*/
{
    if(!T)                                  /*如果是空二叉樹,返回0*/
        return 0;
    else if(!T->lchild&&!T->rchild)         /*如果是葉子結點,返回0*/
        return 0;
    else
        return NotLeafCount(T->lchild)+NotLeafCount(T->rchild)+1; /*左右子樹的非葉子結點數目加上根結點的個數*/
}
  • 計算二叉樹的所有結點數

  二叉樹的所有結點的個數的遞迴定義如下:

Allnodes(T)=0,1,Allnodes(T>lchild)+Allnodes(T>rchild)+1,T=NULLT
Allnodes(T)= \left\{\begin{array}{cc} 0, & 當T=NULL時\\ 1, & 當T的左右孩子均為空時\\ Allnodes(T->lchild)+Allnodes(T->rchild)+1, & 其他情況 \end{array}\right.

  若二叉樹為空,則結點個數為0;在二叉樹不為空的情況下,若左、右子樹為空,則結點數為1;否則, 二叉樹的結點數為左、右子樹的結點數之和加1。

int AllNodes(BiTree T)
/*求二叉樹中所有結點的個數*/
{
    if(!T)                         /*如果是空二叉樹返回0*/
        return 0;
    else if(!T->lchild&&!T->lchild)/*如果是葉子結點返回1*/
        return 1;
    else                           /*如果是非葉子節點,也不是根節點*/
        return AllNodes(T->lchild)+AllNodes(T->rchild)+1;/*左右子樹結點個數加根節點個數*/

}
  • 計算二叉樹的深度

  二叉樹的深度遞迴定義如下:

depth(T)=0,1,max(depth(T>lchild),depth(T>rchild))+1,T=NULLT
depth(T)= \left\{\begin{array}{cc} 0, & 當T=NULL時\\ 1, & 當T的左右孩子均為空時\\ max(depth(T->lchild),depth(T->rchild))+1, & 其他情況 \end{array}\right.

  當二叉樹為空時,其深度為0;當二叉樹只有根節點時,即結點的左、右子樹均為空時,二叉樹的深度為1;在其他情況下,求二叉樹的左、右子樹的最大值再加1(根節點)。由此,得到二叉樹的深度的演算法如下:

int BitTreeDepth(BiTree T)
/*計算二叉樹的深度*/
{
    if(T == NULL)
        return 0;
    return
        BitTreeDepth(T->lchild)>BitTreeDepth(T->rchild)?1+BitTreeDepth(T->lchild):1+BitTreeDepth(T->rchild);
}

2.求葉子節點的最大最小枝長

  求二叉樹的所有葉子節點的最大枝長的遞迴模型如下:

MaxLeaf(b)={0,Max(Maxleaf(b>left),Maxleaf(b>right))+1,b=NULLbNULL
MaxLeaf(b)= \left\{\begin{array}{cc} 0, & b=NULL\\ Max(Maxleaf(b->left),Maxleaf(b->right))+1, & b\neq NULL \end{array}\right.

  求二叉樹的所有葉子節點的最小枝長的遞迴模型如下:

MinLeaf(b)={0,Min(Minleaf(b>left),Minleaf(b>right))+1,b=NULLbNULL
MinLeaf(b)= \left\{\begin{array}{cc} 0, & b=NULL\\ Min(Minleaf(b->left),Minleaf(b->right))+1, & b\neq NULL \end{array}\right.
void MaxMinLeaf(BitTree T,int *max,int *min)
{
    int m1,m2,n1,n2;
    if(T==NULL)
    {
        *max=0;
        *min=0;
    }
    else
    {
        MaxMinLeaf(T->lchild,m1,n1);
        MaxMinLeaf(T->rchild,m2,n2);
        *max=(m1>m2?m1:m2)+1;
        *min=(m1<m2?m1:m2)+1;
    }
}

3.判斷兩顆二叉樹是否相似

  兩顆二叉樹相似的定義:或者T1

T_1
T2
T_2
都是空樹,或者T1
T_1
T2
T_2
的根節點相似,且T1
T_1
T2
T_2
的左子樹和右子樹都相似。
  判斷兩顆二叉樹是否相似可在用同樣的次序遍歷這兩顆二叉樹的過程中進行,因此可用遞迴演算法實現。設t1和t2分別是指向二叉樹T1
T_1
T2
T_2
中當前結點的指標,初始時指向根節點。若t1和t2皆為空,則這兩棵二叉樹相似,返回1;若t1和t2中有一個為空,而另一個不為空,則這兩棵二叉樹不相似,返回0;否則遍歷這兩顆而二叉樹的左子樹,檢查是否相似,然後遍歷右子樹,檢查是否相似。

int BiTree_Like(BiTree t1,BiTree t2)
{
    if(t1==NULL && t2==NULL)
        return 1;
    if((t1!=NULL && t2==NULL)||(t1==NULL && t2!=NULL))
        return 0;
    if(BiTree_Like(t1->rchild,t2->rchild))
        /*若左子樹相似*/
        return (BiTree_Like(t1->rchild,t2->rchild))
    else
        return 0;
}

4.交換二叉樹的左右子樹

  同樣,在遍歷二叉樹的過程中也可以交換各個結點的左右子樹。

void Bitree_Swap(BiTree T)
{
    BiTree p;
    if(!T=NULL)
        if(T->lchild!=NULL||T->rchild!=NULL)
    {
        p=T->rchild;
        T->lchild=T->rchild;
        T->rchild=p;
    }
    if(T->lchild!=NULL)/*若T的左子樹不為空,則將左右子樹交換*/
        Bitree_Swap(T->lchild);
    if(T->rchild!=NULL)/*若T的右子樹不為空,則將左右子樹交換*/
        Bitree_Swap(T->rchild);
}

  也可以用後序遍歷的方式實現交換左右兩顆子樹,但不宜用中序遍歷的方式實現,因為若用中序遍歷的演算法,則僅交換了根節點的左右孩子。

5.求根節點到r結點之間的路徑

  假設二叉樹採用二叉連結串列方式儲存,root指向根節點,r所指結點為任一結點。由於後序遍歷的過程中,訪問到r所指結點時,此時棧中所有結點均為r所指的祖先,這些祖先便構成了一條從根節點到r所指結點之間的路徑,故可採用後序遍歷。

void path(BiTree root,BitNode *r)
{
    BitNode *p,*q;
    int i ,top=0;
    BitNode *s[StackSize];
    q=NULl;
    p=root;
    while(p!=NULL||top!=0)
    {
        while(p!NULL)
        /*遍歷左子樹*/
        {
            top++;
            if(top>=StackSize)
                exit(-1);
            s[top]=p;
            p=p->lchild;
        }
        if(top>0)/*若棧不為空*/
        {
            p=s[top];
            if(p->lchild == NULL ||p->rchild==q)/*根節點*/
            {
                if(p==r)/*找到r所指結點,則輸出從根節點到r所指結點之間的結點*/
                {
                    for(i=1;i<=top;i++)
                    {
                        printf("%4d",s[i]->data);
                        top=0;
                    }
                }
                else
                {
                    q=p;/*用q儲存剛剛遍歷過的結點*/
                    top--;
                    p=NULL;
                }
            }
            else
                p=p->rchild;/*遍歷右子樹*/
        }
    }
}

  
  
  

相關文章