练习(tq tree)

1.设二叉树根结点所在层次为1,树的深度d为举例根最远的叶结点所在层次

(1)试精确给出深度为d的完全二叉树的不同二叉树棵树

解:由二叉树性质,在d层最多有2^{d-1} 个结点,故深度为d的不同完全二叉树有2^{d-1} 棵

(2)试精确给出深度为d的满二叉树的不同二叉树棵树

解:深度为d的满二叉树只有1棵

2.假设二叉树采用二叉链式存储结构,设计算法

(1)计算一棵给定二叉树的所有结点数

法一:给出一棵二叉树,想求结点树,容易想到遍历整个二叉树,用一个变量记录,每经过一个结点增1。

int n=0;
void count (BTNode* p){
    if(p!=NULL){
        ++n;
        count(p->lchild);
        count(p->rchild);
    }
}

法二:若此树为空树,则直接得出其结点树为0;若非空,则先数出其左子树的结点数n1,再数出其右子树的结点数n2,最后得出其结点总数为n1+n2+1,这样对应了后序遍历

int count(BTNode* p){
    int n1,n2;
    if(p==NULL)
        return 0;
    else{
        n1=count(p->child);  //数左子树中的结点个数并返回给n1
        n2=count(p->rchild);  //数右子树中的结点个数并返回给n2
        return n1+n2+!;   //返回总的结点个数
    }
}

(2)计算一棵给定二叉树的所有叶子结点数

法一:

int n=0;
void count (BTNode* p){
    if(p!=NULL){
        if(p->lchild==NULL&& p->rchild==NULL)  //结点的左右子树都为空
        ++n;
        count(p->lchild);
        count(p->rchild);
    }
}

法二:

int count(BTNode* p){
    int n1,n2;
    if(p==NULL)
        return 0;
    else if(p->lchild==NULL && p->rchild==NULL)
    //如果左右子树为空,则返回1,代表有1个叶子结点
        return 1;
    else{
        n1=count(p->lchild);  //求出左子树的叶子结点数并返回n1
        n2=count(p->rchild);  //求出右子树的叶子结点数并返回n2
        return n1+n2;   //返回n1+n2即为总的叶子结点数
}
}

(3)利用结点的右孩子指针rchild将一棵二叉树的叶子结点按照从左往右的顺序串成一个单链表(在题目中定义两个指针,head和tail,其中head指向第一个叶子结点,head初值为NULL,tail指向最后一个叶子结点)

解:如图所示热茶书即为链接完成后的二叉树

通过遍历此树能访问到每一个结点,并在访问时对其rchild指针进行修改,以达到将叶子结点串成一条单链表的目的。通过重要技巧提示可看出,不论哪种遍历都可以对其叶子按照从左到右的顺序进行访问。我们需要在访问每个结点的过程中,判断此结点是否是叶子结点,若是则对rchild指针修改,如果不是不做操作。

  因为题目提到用head和tail指针分别来指示遍历过程中的第一个叶子结点和最后一个叶子结点,所以要对第一个叶子结点进行区分,并让head指向它,而且tail始终指向当前链表中的最后一个结点,即每当一个新结点来到时,通过tail可将这个结点链接到表尾,并将tail 指向它。

void link(BTNode *p,BTNode *&head,BTNode *&tail){
    if(p!=NULL)
    {
        if(p->lchild==NULL && p->rchild==NULL)  //判断是否为叶子
        {
            if(head==NULL){
                tail=p;
            }
        else 
        //如果head不为null,说明head已经指向第一个叶子结点,因此这不是第一个叶子结点,则将
        //此结点链接到链尾的尾部,并且将tail指向它,即指向新的表尾结点
        {
            tail->rchild=p;
            tail=p;
        }
        }
        link(p->lchild,head,tail);
        link(p->rchild,head,tail);
}
}

3.在二叉树的二叉链式存储结构中,增加一个指向双亲结点的parent指针,设计一个算法,给这个指针赋值,并输出所有结点到根结点的路径

解:(1)修改二叉链表的数据结构 (2)将所有结点的parent指针指向其双亲结点 (3)打印所有结点到根结点的路径

1.修改数据结构

typedef struct BTNode{
    char data;
    struct BTNode *parent;
    struct BTNode *lchild;
    struct BTNode  *rchild; 
}

2.给各个结点的parent赋值

因为要访问所有结点,所以要用遍历完成。在访问到一个新结点时,都要知道双亲结点的地址,才可以将parent指针 指向它,为此需要一个指针来指向其双亲结点

void triBtree(BTNode *p,BTNode *q){
    if(p=NULL){
        p->parent=q;  //将当前所访问的结点的parent指针指向q
        q=p;   //将q指向p
        triBtree(p->lchild,q);  //修改其左子树中所有结点的parent指针
        triBtree(p->rchild,q);     //修改其右子树中所有结点的parent指针   
    }
}

3.打印

(1)任给一个结点,打印出结点,然后通过parent找到其双亲,如此重复,知道parent为NULL即可

void printPath(BTNode *p){
    while(p!=NULL){
        cout<<p->data<<" "endl;
        p=p->parent;
}
}

(2)要打印所有路径必须找到所有结点并逐一打印

void allPath(BTNode *p){
    if(p!=NULL){
        printPath(p);
        allPath(p->lchild);
        allPath(p->rchild);
}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值