1 #include <stdio.h> 2 #include <iostream> 3 4 using namespace std; 5 6 template<typename T> class BTree; 7 8 /***************************节点类模板*********************************/ 9 template<typename T> 10 class BTreeNode{ 11 friend void BTree<T>::Print(BTreeNode<T> *t); 12 friend void BTree<T>::PreOrder(BTreeNode<T> *t); 13 friend int BTree<T>::Deepth(BTreeNode<T> *t); 14 friend void BTree<T>::Insert(BTreeNode<T> *t, int n); 15 16 public: 17 BTreeNode(){ data = NULL; left = right = NULL; } 18 BTreeNode(const T& val){ data = val; left = right = NULL; } 19 BTreeNode(const T& val, BTreeNode<T> *l, BTreeNode<T> *r){ data = val; left = l; right = r; } 20 ~BTreeNode(){ delete left; delete right; } 21 22 private: 23 T data; 24 BTreeNode<T> *left; 25 BTreeNode<T> *right; 26 }; 27 28 /***************************树类模板**********************************/ 29 template<typename T> 30 class BTree{ 31 public: 32 void Print(BTreeNode<T> *t); 33 void PreOrder(BTreeNode<T> *t); 34 int Deepth(BTreeNode<T> *t); 35 void Insert(BTreeNode<T> *t,int n); 36 private: 37 BTreeNode<T> *root; 38 }; 39 40 template<typename T> 41 void BTree<T>::Print(BTreeNode<T> *t) 42 { 43 cout << t->data << endl; 44 } 45 46 47 template<typename T> 48 void BTree<T>::PreOrder(BTreeNode<T> *t) 49 { 50 if (t != NULL) 51 { 52 Print(t); 53 PreOrder(t->left); 54 PreOrder(t->right); 55 } 56 } 57 58 template<typename T> 59 int BTree<T>::Deepth(BTreeNode<T> *t) 60 { 61 if (t == NULL) 62 { 63 return 0; 64 } 65 int left = 1; 66 int right = 1; 67 left += Deepth(t->left); 68 right += Deepth(t->right); 69 return left >= right ? left : right; 70 } 71 72 //右边的节点比左边大10 73 template<typename T> 74 void BTree<T>::Insert(BTreeNode<T> *t, int n) 75 { 76 if (n < 0) 77 { 78 return; 79 } 80 int i = ii; 81 t->left = new BTreeNode<T>(ii++); 82 //i = ii; 83 Insert(t->left, n - 1); 84 t->right = new BTreeNode<T>(i + 10); 85 Insert(t->right, n - 1); 86 }
友元函数可以访问封装好的类的私有成员,无疑破坏了类的封装性。不过确实可以提高很多发开的效率。
以前用c语言写链表等,都用结构体来定义一个点。在c++中,用类代替了结构体:确实,类和结构体差不多,只是类可以有私有变量,而结构体都是公有的。
在写二叉树时发现了这样写需要注意的。
代码在上面。main就不写了。
首先要写一个节点类:
/***************************节点类模板*********************************/ template<typename T> class BTreeNode{ friend void BTree<T>::Print(BTreeNode<T> *t); friend void BTree<T>::PreOrder(BTreeNode<T> *t); friend int BTree<T>::Deepth(BTreeNode<T> *t); friend void BTree<T>::Insert(BTreeNode<T> *t, int n); public: BTreeNode(){ data = NULL; left = right = NULL; } BTreeNode(const T& val){ data = val; left = right = NULL; } BTreeNode(const T& val, BTreeNode<T> *l, BTreeNode<T> *r){ data = val; left = l; right = r; } ~BTreeNode(){ delete left; delete right; } private: T data; BTreeNode<T> *left; BTreeNode<T> *right; };
除了基本的声明,再声明几个友元函数给之后的BTree类调用,BTreeNode只是表示节点,而树是很多节点相连的。所以下面写BTree类,实现树的一些功能。需要注意的是:声明友元的时候,不能跟普通的外部函数一样,声明类或类模板的函数,需要加上域的限制。想想也是,否则编译器怎么能之后你要调用到底是哪个函数呢?因为假如在类内还类外都有同一个名字的函数,那就出事了。所以限定域肯定是有的!!!
/***************************树类模板**********************************/ template<typename T> class BTree{ public: void Print(BTreeNode<T> *t); void PreOrder(BTreeNode<T> *t); int Deepth(BTreeNode<T> *t); void Insert(BTreeNode<T> *t,int n); private: BTreeNode<T> *root; }; template<typename T> void BTree<T>::Print(BTreeNode<T> *t) { cout << t->data << endl; } template<typename T> void BTree<T>::PreOrder(BTreeNode<T> *t) { if (t != NULL) { Print(t); PreOrder(t->left); PreOrder(t->right); } } template<typename T> int BTree<T>::Deepth(BTreeNode<T> *t) { if (t == NULL) { return 0; } int left = 1; int right = 1; left += Deepth(t->left); right += Deepth(t->right); return left >= right ? left : right; } //右边的节点比左边大10 template<typename T> void BTree<T>::Insert(BTreeNode<T> *t, int n) { if (n < 0) { return; } int i = ii; t->left = new BTreeNode<T>(ii++); //i = ii; Insert(t->left, n - 1); t->right = new BTreeNode<T>(i + 10); Insert(t->right, n - 1); }
可以看到,在类模板里还是跟正常一样声明函数,和在类外定义函数。但是当你在主函数使用这些定义的函数就会出错。那是因为在定义友元的时候没有声明类模板。
在第一个类模板就是BTreeNode之前就上很重要的一句:
template<typename T> class BTree;
就完美了。另外记住:以后在使用之前先声明,否则无论是使用和定义都会出现问题。
我写程序一直都是class什么,class什么,int main()什么。其实先写定义头是个好习惯!!!