二叉树的创建以及遍历

#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,那么只需要调用nPrintNodeAtLevel()

问题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说明此层尚未被访问,因此,依次访问CurLast之间的所有节点,并依次将被访问节点的左右子节点压入数组中,那么访问完第一层的游标及数组的状态如下图所示:

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;
}
}

 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值