树结点
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());
}