#include<iostream>
#include<queue>
using namespace std;
typedef struct tnode
{
char data;
struct tnode *lchild,*rchild;
}BTNode;
///建立二叉树
BTNode *CreateTree()
{
char x;
BTNode *bt;
cin>>x;
if(x=='#')
bt=NULL;
else
{
bt=(BTNode *)malloc(sizeof(BTNode));
bt->data=x;
bt->lchild=CreateTree();
bt->rchild=CreateTree();
}
return bt;
}
BTNode *CreateTree(BTNode *&bt)
{
char ch;
ch=getchar();
if(ch=='#')
{
bt=NULL;
}
else
{
bt=(BTNode *)malloc(sizeof(BTNode));
if(NULL==bt)
{
cout<<"overflow err"<<endl;
return NULL;
}
bt->data=ch;
CreateTree(bt->lchild);
CreateTree(bt->rchild);
}
return bt;
}
//先序遍历
void PreOrder(BTNode *p)
{
if(p!=NULL)
{
cout<<p->data<<" ";
PreOrder(p->lchild);
PreOrder(p->rchild);
}
}
//中序遍历
void InOrder(BTNode *p)
{
if(p!=NULL)
{
PreOrder(p->lchild);
cout<<p->data<<" ";
PreOrder(p->rchild);
}
}
//后序遍历
void PostOrder(BTNode *p)
{
if(p!=NULL)
{
PreOrder(p->lchild);
PreOrder(p->rchild);
cout<<p->data<<" ";
}
}
//计算二叉树的深度
int Depth(BTNode *p)
{
if(p==NULL)
return 0;
int d1=Depth(p->lchild);
int d2=Depth(p->rchild);
return (d1>d2?d1:d2)+1;
}
//计算二叉树节点个数
int NodeCount(BTNode *p)
{
int num1,num2;
if(p==NULL)
return 0;
else
{
num1=NodeCount(p->lchild);
num2=NodeCount(p->rchild);
return num1+num2+1;
}
}
//求叶子节点个数
int LeafCount(BTNode *p)
{
int num1,num2;
if(p==NULL)
return 0;
else if(p->lchild==NULL&&p->rchild==NULL)
return 1;
else
{
num1=LeafCount(p->lchild);
num2=LeafCount(p->rchild);
return num1+num2;
}
}
//层次遍历,一层层的访问
void LevelOrder(BTNode *p)
{
queue<BTNode *> qu;
BTNode *temp;
qu.push(p); //根入队列
while(!qu.empty()) //队列不为空
{
temp=qu.front(); //出队头
qu.pop();//删除队头的一个元素
cout<<temp->data<<" "; //访问节点
if(temp->lchild!=NULL) //有左孩子将其入队
qu.push(temp->lchild);
if(temp->rchild!=NULL)
qu.push(temp->rchild);//有右孩子将其入队
}
}
void main()
{
BTNode *bt;
cout<<"建树将以三个#回车结束"<<endl;
cout<<"例如:1#2#3#4#5#6###"<<endl;
bt=CreateTree();
cout<<"递归先序遍历二叉树"<<endl;
PreOrder(bt);
cout<<endl;
cout<<"递归中序遍历二叉树"<<endl;
InOrder(bt);
cout<<endl;
cout<<"递归后序遍历二叉树"<<endl;
PostOrder(bt);
cout<<endl;
cout<<"树的深度为:"<<Depth(bt)<<endl;
cout<<"树的节点个数为:"<<NodeCount(bt)<<endl;
cout<<"叶子节点个数为:"<<LeafCount(bt)<<endl;
cout<<"树的层次遍历如下:"<<endl;
LevelOrder(bt);
}
运行结果:
C++描述
#ifndef _BTREE
#define _BTREE
template <class T>class BinaryTree;
template <class T>
class BinaryTreeNode {
friend class BinaryTree<T>;
public:
BinaryTreeNode() {LeftChild = RightChild = 0;}
BinaryTreeNode(const T& e)
{
data = e;
LeftChild = RightChild = 0;}
BinaryTreeNode(const T& e, BinaryTreeNode *l,
BinaryTreeNode *r)
{data = e;
LeftChild = l;
RightChild = r;}
private:
T data;
BinaryTreeNode<T> *LeftChild, //左子树
*RightChild; // 右子树
};
template<class T>
class BinaryTree {
public:
BinaryTree(){root = 0;};
~BinaryTree() { };
bool IsEmpty( ) const
{return ((root)? false:true);}
bool Root(T& x) const;
void MakeTree(const T& element,BinaryTree<T>& left,BinaryTree<T>& right);
void BreakTree(T& element,BinaryTree<T>& left,BinaryTree<T>& right);
void PreOrder(void(*Visit)(BinaryTreeNode<T> *u))
{ Preorder(Visit,root); }
void InOrder(void (*Visit)(BinaryTreeNode<T> *u))
{ Inorder(Visit,root); }
void PostOrder(void(*Visit)(BinaryTreeNode<T> *u))
{Postorder(Visit, root); }
void LevelOrder(void(*Visit)(BinaryTreeNode<T> *u));
void PreOutput(){Preorder(Output,root);}//按前序方式输出数据域
void InOutput(){Inorder(Output,root); }//按中序方式输出数据域
void PostOutput(){ Postorder(Output,root);}//按后序方式输出数据域。
void Delete( ) { Postorder(Free,root); root = 0;}//删除一棵二叉树
int Height() const {return Height(root);}
private:
BinaryTreeNode<T> *root; // 根节点指针
void Preorder(void (*Visit)(BinaryTreeNode<T> *u),BinaryTreeNode<T> *t);
void Inorder(void(*Visit)(BinaryTreeNode<T> *u),BinaryTreeNode<T> *t);
void Postorder(void(*Visit)(BinaryTreeNode<T> *u),BinaryTreeNode<T> *t);
static void Output(BinaryTreeNode<T> *t)
{ cout << t->data << ' ' ;}
static void Free(BinaryTreeNode<T> *t) {delete t;}
int Height (BinaryTreeNode<T> *t) const;//计算树的高度
};
//成员函数的实现
template<class T>
bool BinaryTree<T>::Root(T& x) const
{// 取根节点的data域,放入x
// 如果没有根节点,则返回false
if (root)
{
x = root->data;
return true;
}
else return false; // 没有根节点
}
template<class T>
void BinaryTree<T>::MakeTree(const T& element, BinaryTree<T>& left, BinaryTree<T>& right)
{// 将left, right和element 合并成一棵新树
// left, right和this必须是不同的树
// 创建新树
root = new BinaryTreeNode<T>(element, left.root, right.root);
// 阻止访问left和right
left.root = right.root = 0;
}
template<class T>
void BinaryTree<T>::BreakTree(T& element, BinaryTree<T>& left, BinaryTree<T>& right)
{// left, right和this必须是不同的树
// 检查树是否为空
if (!root) return; // 空树
// 分解树
element = root->data;
left.root = root->LeftChild;
right.root = root->RightChild;
delete root;
root=0;
}
/****************************前序,中序和后序遍历****************/
template<class T>
void BinaryTree<T>::Preorder(void (*Visit)(BinaryTreeNode<T> *u),BinaryTreeNode<T> *t)
{// 前序遍历
if (t) {
Visit(t) ;
Preorder( Visit,t->LeftChild);
Preorder( Visit, t->RightChild);
}
}
template <class T>
void BinaryTree<T>::Inorder(void(*Visit)(BinaryTreeNode<T> *u),BinaryTreeNode<T> *t)
{
if (t)
{
Inorder(Visit, t->LeftChild);
Visit(t);
Inorder(Visit, t->RightChild);
}
template <class T>
void BinaryTree<T>::Postorder(void (*Visit)(BinaryTreeNode<T> *), BinaryTreeNode<T> *t)
{// 后序遍历
if(t)
{
Postorder(Visit, t->LeftChild);
Postorder(Visit, t->RightChild);
Visit(t)
}
}
template<class T>
void BinaryTree<T>::LevelOrder(void(*Visit)(BinaryTreeNode<T> *u))
{ //逐层遍历
}
template <class T>
int BinaryTree<T>::Height(BinaryTreeNode<T> *t) const
{// 返回树* t的高度
if (!t) return 0; // 空树
int hl = Height(t->LeftChild); // 左子树的高度
int hr = Height(t->RightChild); // 右子树的高度
if (hl > hr) return ++hl;
else return ++hr;
}
}
#endif
主函数调用
#include<iostream>
#include "BinaryTree.h"
using namespace std;
void main()
{
int count=0;
BinaryTree<int> a,x,y,z;
y.MakeTree(1,a,a);
z.MakeTree(2,a,a);
x.MakeTree(3,y,z);
y.MakeTree(4,x,a);
//cout<<y.Height();
//y.InOutput();
// cout<<count<<endl;
}
Q:分层遍历二叉树
问题1:给定一颗二叉树,要求按分层遍历该二叉树,从上到下,从左到右依次输出(每一层单独输出一行)。
如下的二叉树输出为:
1
2 3
4 5 6
7 8
问题2:写一个函数,打印二叉树中某层次节点(从左到右),其中根节点为第0层,函数原型为int PrintNodeAtLevel(Node * root,int level).成功返回1,失败返回0.
分析与解法:
二叉树数据结构如下:
struct Node
{
int data;
Node * lChild;
Node *rChild;
}
1.解决问题1可以采用先解决问题2,则可以采用遍历各层次节点。
要求访问二叉树中第K层节点,那么可以转换为“以该二叉树根节点的左右子节点为根节点的两颗子树”中层次第k-1层的节点。
代码如下:
int PrintNodeAtLevel(Node * root,int level)
{
if(!root||level<0)
return 0;
If(level==0)
{
cout<<root->data<<” ”;
return 1;
}
return PrintNodeAtLevel(node->lChild,level-1)+ PrintNodeAtLevel(node->rChild,level-1);
}
如果知道二叉树的深度为n,那么只需要调用n次PrintNodeAtLevel()
问题1的代码:
void PrintNodeByLevel(Node *root,int depth)
{
for(int level=0;level<depth;level++)
{
PrintNodeAtLevel(root,level);
cout<<endl;
}
}
如果事先不知道二叉树的高度,则需要用递归算法求解二叉树的高度,也可以不求二叉树的高度,当访问二叉树某一层失败的时候返回就OK。
不求二叉树高度的方法:
void PrintNodeByLevel(Node *root)
{
for(int level=0;;level++)
{
If(!PrintNodeAtLevel(root,level))
break;
cout<<endl;
}
}
注:在解决问题1的算法中,对二叉树每一层的访问都要从根节点开始,直到访问完所有的层次,这样的效率很低。
在访问第K层的时候,我们只需要知道第K-1层节点的信息就足够了,所以在访问第K层的时候,要是能知道第K-1层节点的信息,就不要从根节点开始访问。
分析如下:从根节点出发,依次将每层的节点从左到右压入一个数组,并用一个游标Cur记录当前访问的节点,另一个游标Last指示当前层次的最后一个节点的下一个位置,以Cur==Last作为当前层次访问结束的条件,在访问完某一层次的同时将该层的所有节点的子节点压入数组,在访问完某一层之后,检查是否还有新的层次可以访问,直到访问完所有的层次。
具体步骤如下:
a.首先将节点1压入数组,并将游标Cur置于)0,游标Last置于1。
b.Cur<Last说明此层尚未被访问,因此,依次访问Cur到Last之间的所有节点,并依次将被访问节点的左右子节点压入数组中,那么访问完第一层的游标及数组的状态如下图所示:
c.当Cur==Last,说明该层已经被访问完,此时数组中还有未被访问到的节点,则输出换行符,为输出下一行做准备,并将Last定位于新一行的末尾。
如下图:
继续依次往下访问其他节点,知道访问完所有的层次。
代码如下:
void PrintNodeByLevel(Node * root)
{
if(root==NULL)
return ;
vector<Node *>vec;
vec.push_back(root);
int cur=0;
int Last=1;
while(cur<vec.size())
{
Last=vec.size();
while(cur<Last)
{
cout<<vec[cur]->data<<” ”;
if(!vec[cur]->lChild)
vec.push_back(vec[cur]->lChild);
if(!vec[cur]->rChild)
vec.push_back(vec[cur]->rChild);
Cur++;
}
cout<<endl;
}
}