求二叉树的每个结点的子孙数量

《数据结构》严蔚敏版习题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 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 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)。

你可能感兴趣的:(算法问题)