二叉森林

这篇博客是关于二叉森林的复习笔记,涵盖了从广义表生成二叉森林的方法,以及森林和树的先根、后根遍历。此外,还讨论了树的广度遍历,并探讨了遍历在计算结点个数和求解树深度等应用中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

复习笔记一篇。

  • 利用广义表生成二叉森林
  • 树与森林二叉遍历(树的先根、后根遍历;森林的先根、后根遍历)
  • 树的广度遍历
  • 树遍历的应用:求结点个数,求树的深度。
//
//  main.cpp
//  二叉森林
//
//  Created by scnulpc on 2018/10/21.
//  Copyright © 2018年 scnulpc. All rights reserved.
//

#include <iostream>
#include <queue>
#define size 100
using namespace std;
struct treeNode
{
    char value;
    treeNode* firstChild;
    treeNode* nextBrother;
    treeNode(char a):value(a),firstChild(NULL),nextBrother(NULL){}
};
//通过广义表将棵原始森林转为二叉树森林(长子-兄弟链)
treeNode* createTreeByList(char * &s,char end)
{
    
    if (*s==end) return NULL;
    if (*s==')'){s++;return NULL;}
    if (*s=='(') s++;
    treeNode* root = new treeNode(*s);
    s++;
    root->firstChild = createTreeByList(s,end);
    root->nextBrother = createTreeByList(s,end);
    return root;
}
//先根遍二叉树(森林)(递归)
void preOrderPrint(treeNode *p)
{
    if (p==NULL) return;
    cout<<p->value<<" ";
    preOrderPrint(p->firstChild);
    preOrderPrint(p->nextBrother);
}
//课本中关于树的先根遍历描述如下(递归):其实这两种算法实质上都是一样的,只是递归描述的角度
//不太一样,课本描述的是,先把根节点访问,再把左孩子访问,最后把左孩子的所有兄弟访问。这样想
//很符合逻辑,但细想,由于树已经用长子-兄弟链的形式存储起来,实质上就是一棵二叉树,一次,我们
//也可以用普通二叉树前序遍历的算法去描述。对比发现,下面算法中的那个for循环可以隐藏在递归中。
void preOrderPrint2(treeNode *p)
{
    if (p!=NULL) {
        cout<<p->value<<" ";
        treeNode* q;
        for (q=p->firstChild; q!=NULL; q=q->nextBrother)
        {
            preOrderPrint2(q);
        }
    }
}
//后根遍历二叉树(递归):和一般二叉树后序遍历无异
void postOrderPrint(treeNode* p)
{
    if (p==NULL) return;
    postOrderPrint(p->firstChild);
    postOrderPrint(p->nextBrother);
    cout<<p->value<<" ";
}
//课本的方法:        关于一棵树的后序遍历算法的差异,分析与先根遍历一样。
void postOrderPrint2(treeNode* p)
{
    if (p!=NULL) {
        treeNode* q ;
        for (q=p->firstChild; q!=NULL; q=q->nextBrother) {
            postOrderPrint2(q);
        }
        cout<<p->value<<" ";
    }
}

//森林的后根遍历
//森林由很多棵树组成,每棵树都是后根遍历,但对于整个森林来说,对应于二叉深林的中序遍历
void postOrderPrintForest(treeNode* p)
{
    if (p==NULL) return;
    postOrderPrintForest(p->firstChild);
    cout<<p->value<<" ";
    postOrderPrintForest(p->nextBrother);
}
///////至此,森林的深度遍历(先根遍历,后根遍历)描述完,下面描述森林的广度遍历/////

void  bfs(treeNode* p)
{
    if (p==NULL) return;
    queue<treeNode*> q;
    q.push(p);
    treeNode* temp;
    while (!q.empty()) {
        temp = q.front();
        q.pop();
        cout<<temp->value<<" ";
        for (temp=temp->firstChild; temp!=NULL; temp=temp->nextBrother) {
            q.push(temp);
        }
    }
}

//树遍历的应用
//统计节点的个数
 int countNode(treeNode* p)
{
    if (p==NULL) return 0;
    int sum = 1;
    sum += countNode(p->firstChild);
    sum += countNode(p->nextBrother);
    return  sum;
}
//求树的高度
//计算自己的高度,计算兄弟树的高度,返回两者中的较大值。
int countDepth(treeNode* p)
{
    if (p==NULL) return 0;
    int itselfDepth = countDepth(p->firstChild)+1;
    int brotherDepth = countDepth(p->nextBrother);
    return (itselfDepth>brotherDepth)? itselfDepth:brotherDepth;
}
//test data: (R(A(D)(E))(B)(C(F(G)(H)(K))))#
int main(int argc, const char * argv[])
{
    
    cout << "输入树的广义表,以#结束,eg: (R(A(D)(E))(B)(C(F(G)(H)(K))))#\n";
    char s[size] ;
    for (int i=0; i<size; i++) {
        cin>>s[i];
        if (s[i]=='#') break;
    }
    char * p = s;
    treeNode* root = createTreeByList(p,'#');
    cout<<"树先根"<<endl;
    preOrderPrint(root);
    cout<<endl;
    cout<<"森林先根"<<endl;
    preOrderPrint2(root);
    cout<<endl;
    cout<<"树后根"<<endl;
    postOrderPrint(root);
    cout<<"森林后根"<<endl;
    postOrderPrintForest(root);
    cout<<endl;
    cout<<"森林广度"<<endl;
    bfs(root);
    cout<<endl;
    cout<<"节点个数为:"<<countNode(root)<<endl;
    cout<<"树的深度:"<<countDepth(root)<<endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值