求二叉樹的每個結點的子孫數量

《數據結構》嚴蔚敏版習題6.55

爲二叉鏈表的結點增加DescNum域,表示該結點的子孫數量。編寫一個算法,求二叉樹的每個結點的子孫數目並存入其DescNum域。

思路:

  • 方案1,利用遞歸,從根節點開始對每個結點都調用一次函數來求每個節點的子孫數量
    很明顯遞歸調用肯定很慢,因爲要不斷地壓棧彈棧。
  • 方案2,與方案1的遍歷方向相反,從最下面的葉子結點開始計算每個結點的子孫數量,然後對於其雙親節點,只要將左右孩子的DescNum域加起來就可以了。那麼哪種遍歷可以滿足這種“先孩子後雙親”的遍歷順序呢?當然是後續遍歷。下面給出方案2的c++代碼
/*
求每個結點的子孫數目
*/
#include "bitree.h"

typedef struct myTNode
{
    int data;
    int descendant;
    struct myTNode* lchild;
    struct myTNode* rchild;
}myBiTree, *pmyBiTree;


void mycreat_tree(pmyBiTree &rt)
{
    char ch;
    ch=getchar();
    if('#'==ch)
    {
        rt=NULL;
    }
    else
    {
        rt=(pmyBiTree)malloc(sizeof(myBiTree));
        rt->data=ch;
        rt->descendant = 0;
        mycreat_tree(rt->lchild);        //構造左子樹
        mycreat_tree(rt->rchild);    //構造右子樹
    }
}

void DescNumber(pmyBiTree &rt)
{
    if(!rt)
        return;
    stack<pmyBiTree> s;
    pmyBiTree cur = rt;
    pmyBiTree pre = NULL;

    while(!s.empty() || cur != NULL)
    {
        while(cur)
        {
            s.push(cur);
            cur = cur->lchild;
        }
        cur = s.top();
        if(cur->rchild == NULL || cur->rchild == pre)
        {
            if(cur->lchild)
                cur->descendant += cur->lchild->descendant + 1;
            if(cur->rchild)
                cur->descendant += cur->rchild->descendant + 1;
            pre = cur;
            cur = NULL;
            s.pop();
        }
        else
        {
            cur = cur->rchild;
        }
    }
}

void PreOrderPrintDesc(pmyBiTree &rt)
{
    cout << "PreOrderPrintDesc: " << endl;
    if(!rt)
        return;
    stack<pmyBiTree> s;
    s.push(rt);
    while(!s.empty())
    {
        pmyBiTree cur = s.top();
        cout << (char)(cur->data) << " Desc: " << cur->descendant << endl;
        s.pop();
        if(cur->rchild)
            s.push(cur->rchild);
        if(cur->lchild)
            s.push(cur->lchild);
    }
    cout << '@' << endl;
}

int main(int argc, char const *argv[])
{
    pmyBiTree root;
    mycreat_tree(root);
    DescNumber(root);
    PreOrderPrintDesc(root);
    return 0;
}

函數void DescNumber(pmyBiTree &rt)計算出二叉樹rt的所有結點的DescNum域。它利用後續遍歷的思路,不同之處僅在:本來應該打印當前結點的時候,根據是否存在左右結點,計算本結點的子孫數。此題也充分說明了二叉樹的3中遍歷方法的重要性,可以讓很多問題不用遞歸,也不用很高的複雜的就能解決。此算法複雜度爲O(n)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章