复习笔记一篇。
- 利用广义表生成二叉森林
- 树与森林二叉遍历(树的先根、后根遍历;森林的先根、后根遍历)
- 树的广度遍历
- 树遍历的应用:求结点个数,求树的深度。
//
// 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;
}