二叉树的建立与功能实现

树结点

template<class T>
struct BinTreeNode  //结点
{
	T data;
	BinTreeNode<T>* leftChild, * rightChild;
	BinTreeNode() :leftChild(NULL), rightChild(NULL) {}                //默认构造函数
	BinTreeNode(T x) :data(x), leftChild(NULL), rightChild(NULL) {}  //有参构造函数(赋予结点值)
};

定义树

template<class T>
class BinaryTree
{
public:
	BinaryTree() :root(NULL) {}
	BinaryTree(T value) :RefValue(value), root(NULL) {}
	BinTreeNode<T>* &getRoot() { return root; }                     //取根//注意这一个代码
	~BinaryTree() { Destory(root); }
	void Destory(BinTreeNode<T>*& subTree);                             
	void CreatBinTree(BinTreeNode<T>*& subTree);
	void PreOrder(BinTreeNode<T>* subTree);                            //先序
	void InOrder(BinTreeNode<T>* subTree);                             //中序
	void Leaf(BinTreeNode<T>* subTree);
	int  Height(BinTreeNode<T>* subTree);
	int Size(BinTreeNode<T>*subTree);
	
protected:
	T RefValue;                                                       //识别叶节点
	BinTreeNode<T>* root;                                                                                                
};
  • 传入的subTree一定要是一个引用的形式,不然内部我们用形参指针接收时,对形参的改变不会影响到实参。
  • 一定注意取根的那一个函数,getRoot,书上的代码没有前面的&,结果我在main函数里传都传不进去。取根是非常关键的一步,我们的指向根结点的指针*root是放在protected成员里面的,如果取不到根是无法进行后面操作。而我们取根返回的是一个指向根结点的指针,大家知道函数的返回值是一个右值,但是我们上一步传入是用一个引用接收的,引用只能接收左值,这就产生了矛盾。(对右值左值如果不太清楚可以看我上一篇文章)解决的办法就是在函数前面加上&,用引用去接收,这样返回的引用就是左值啦。

创建树

template<class T>
void BinaryTree<T>::CreatBinTree(BinTreeNode<T>*&subTree)               //注意用引用接收指针  如果只传入指针 形参的指针指向改变 实参不会变
{
	T ch;
	cin >> ch;
		if (ch == RefValue) subTree = NULL;
		else
		{
			subTree = new BinTreeNode<T>(ch);                      //有参构造函数 建立结点
			CreatBinTree(subTree->leftChild);                      //递归
			CreatBinTree(subTree->rightChild);
	}
}

删除树

template<class T>
void BinaryTree<T>::Destory(BinTreeNode<T>*& subTree)
{
	if (subTree != NULL)
	{
		Destory(subTree->leftChild);
		Destory(subTree->rightChild);
		delete subTree;
	}

}

前序遍历和中序遍历

template<class T>
void BinaryTree<T>::PreOrder(BinTreeNode<T>* subTree)
{
	if (subTree != NULL)
	{
		cout << subTree->data << ' ';
		PreOrder(subTree->leftChild);
		PreOrder(subTree->rightChild);
	}
}

template<class T>
void BinaryTree<T>::InOrder(BinTreeNode<T>* subTree)
{
	if (subTree != NULL)
	{
		InOrder(subTree->leftChild);
		cout << subTree->data << ' ';
		InOrder(subTree->rightChild);
	}
}

求树叶结点个数

template<class T>
void BinaryTree<T>::Leaf(BinTreeNode<T>* subTree)
{
	if (subTree != NULL)
	{
		if (subTree->leftChild == NULL && subTree->rightChild == NULL)
			cnt2++;
		Leaf(subTree->leftChild);
		Leaf(subTree->rightChild);
	}
}
//只能用先序来写,感觉用递归return应该也行 不过暂时没想到..

求树高度

template <class T>
int  BinaryTree<T>::Height(BinTreeNode<T>* subTree)
{
	if (subTree == NULL) return 0;	//空树高度为0
	else
	{
		int i = Height(subTree->leftChild);
		int j = Height(subTree->rightChild);
		return (i < j) ? j + 1 : i + 1;
	}
}
//可能不太好理解 画一个图比划几下可能好一些

求树结点个数

template <class T>
int BinaryTree<T>::Size(BinTreeNode<T>* subTree)
{
	if (subTree == NULL) return 0;
	else return 1 + (Size(subTree->leftChild) + Size(subTree->rightChild));
}
  • 补充几点

  • subTree是任意一个结点,建立了树以后传入随意的值了,为了方便我只是传了根结点,所以理解为求树~~~,应该是根为subTree的树的函数。

  • 我们不难发现,树的一些函数的实现也就是在先序or中序or后序上加了一些特有的功能,比如求叶节点的时候我们就先序了一遍,求树高度和树结点个数的过程其实也是后序的过程。

main函数

int main()
{
	BinaryTree<char>Tree1('@');
	Tree1.CreatBinTree(Tree1.getRoot());
	cout << "先序遍历:";
	Tree1.PreOrder(Tree1.getRoot());
	cout << endl;
	cout << "中序遍历:";
	Tree1.InOrder(Tree1.getRoot());
	cout << endl;
	Tree1.Leaf(Tree1.getRoot());
	cout << "该树叶节点个数为:" << cnt2 << endl;
	cout << "该树高" << Tree1.Height(Tree1.getRoot());
	cout << "该树的结点个数为" << Tree1.Size(Tree1.getRoot());
}

后续补充 层序遍历

template<class T>
void BinaryTree<T>::LevelOrder(BinTreeNode<T>* subTree)
{
	queue<BinTreeNode<T>*>Q;
	BinTreeNode<T>* p = root;
	Q.push(p);
	while (!Q.empty())
	{
			BinTreeNode<T> * t = Q.front();
			Q.pop();
			cout << t->data <<" ";
			if (t->leftChild != NULL) Q.push(t->leftChild);
			if (t->rightChild != NULL)Q.push(t->rightChild);
	}
}

代码

感兴趣的话可以调试一下,很多函数都可以自己添加,为了大家方便我把总代码放在下面:


#include<iostream>
using namespace std;

int cnt2;//统计叶节点个数

template<class T>
struct BinTreeNode  //结点
{
	T data;
	BinTreeNode<T>* leftChild, * rightChild;
	BinTreeNode() :leftChild(NULL), rightChild(NULL) {}                //默认构造函数
	BinTreeNode(T x) :data(x), leftChild(NULL), rightChild(NULL) {}  //有参构造函数(赋予结点值)
};


template<class T>
class BinaryTree
{
public:
	BinaryTree() :root(NULL) {}
	BinaryTree(T value) :RefValue(value), root(NULL) {}
	BinTreeNode<T>* &getRoot() { return root; }                         //取根
	~BinaryTree() { Destory(root); }
	void Destory(BinTreeNode<T>*& subTree);
	void CreatBinTree(BinTreeNode<T>*& subTree);
	void PreOrder(BinTreeNode<T>* subTree);                            //先序
	void InOrder(BinTreeNode<T>* subTree);                             //中序
	void Leaf(BinTreeNode<T>* subTree);
	int  Height(BinTreeNode<T>* subTree);
	int Size(BinTreeNode<T>*subTree);
	
protected:
	T RefValue;                                                       //识别叶节点
	BinTreeNode<T>* root;                                             //本来应该在protected里面                                                      
};



template<class T>
void BinaryTree<T>::CreatBinTree(BinTreeNode<T>*&subTree)               //注意!!!!传入的是指针的引用 如果只传入指针 形参的指针指向改变 实参不会变
{
	T ch;
	cin >> ch;
		if (ch == RefValue) subTree = NULL;
		else
		{
			subTree = new BinTreeNode<T>(ch);
			CreatBinTree(subTree->leftChild);
			CreatBinTree(subTree->rightChild);
	}
}

template<class T>
void BinaryTree<T>::Destory(BinTreeNode<T>*& subTree)
{
	if (subTree != NULL)
	{
		Destory(subTree->leftChild);
		Destory(subTree->rightChild);
		delete subTree;
	}

}


template<class T>
void BinaryTree<T>::PreOrder(BinTreeNode<T>* subTree)
{
	if (subTree != NULL)
	{
		cout << subTree->data << ' ';
		PreOrder(subTree->leftChild);
		PreOrder(subTree->rightChild);
	}
}

template<class T>
void BinaryTree<T>::InOrder(BinTreeNode<T>* subTree)
{
	if (subTree != NULL)
	{
		InOrder(subTree->leftChild);
		cout << subTree->data << ' ';
		InOrder(subTree->rightChild);
	}
}

template<class T>
void BinaryTree<T>::Leaf(BinTreeNode<T>* subTree)
{
	if (subTree != NULL)
	{
		if (subTree->leftChild == NULL && subTree->rightChild == NULL)
			cnt2++;
		Leaf(subTree->leftChild);
		Leaf(subTree->rightChild);
	}
}

template <class T>
int  BinaryTree<T>::Height(BinTreeNode<T>* subTree)
{
	if (subTree == NULL) return 0;	//空树高度为0
	else
	{
		int i = Height(subTree->leftChild);
		int j = Height(subTree->rightChild);
		return (i < j) ? j + 1 : i + 1;
	}
}

template <class T>
int BinaryTree<T>::Size(BinTreeNode<T>* subTree)
{
	if (subTree == NULL) return 0;
	else return 1 + (Size(subTree->leftChild) + Size(subTree->rightChild));
}

int main()
{
	BinaryTree<char>Tree1('@');
	Tree1.CreatBinTree(Tree1.getRoot());
	cout << "先序遍历:";
	Tree1.PreOrder(Tree1.getRoot());
	cout << endl;
	cout << "中序遍历:";
	Tree1.InOrder(Tree1.getRoot());
	cout << endl;
	Tree1.Leaf(Tree1.getRoot());
	cout << "该树叶节点个数为:" << cnt2 << endl;
	cout << "该树高" << Tree1.Height(Tree1.getRoot())<<endl; 
	cout << "该树的结点个数为" << Tree1.Size(Tree1.getRoot());
}

posted on 2020-06-24 01:05  The0Y  阅读(234)  评论(0编辑  收藏  举报

导航