二叉树 Posted on 2019-09-23 | In C++ , 数据结构 | | Words count in article: 3k | Reading time ≈ 16 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667// BinNode.h// 二叉树的基本组陈实体是二叉树节点,而边则对应于节点之间的相互关系#include <iostream>#define BinNodePosi(T) BinNode<T>* //节点位置#define stature(p) ((p) ? (p)->height : -1)// 节点高度,约定空树高度为-1//BinNode 状态与性质的判断:#define IsRoot(x) ( !( (x).parent ) )#define IsLChild(x) ( ! IsRoot(x) && ( &(x) == (x).parent->lc ) )#define IsRChild(x) ( ! IsRoot(x) && ( &(x) == (x).parent->rc ) )#define HasParent(x) ( ! IsRoot(x) )#define HasLChild(x) ( (x).lc )#define HasRChild(x) ( (x).rc )#define HasChild(x) ( HasLChild(x) || HasRChild(x) )#define HasBothChild(x) ( HasLChild(x) && HasRChild(x) )#define IsLeaf(x) ( ! HasChild(x) )// 与BinNode具有特定关系的节点以及指针:#define sibling(p) ( IsLChild(*(p)) ? (p)->parent->rc: (p)->parent->lc ) //兄弟#define uncle(x) ( IsLChild(*((x)->parent)) ? (x)->parent->parent->rc: (x)->parent->parent->lc ) //叔叔#define FromParentTo(x) /*来自父亲的引用*/ ( IsRoot(x) ? _root: ( IsLChild(x) ? (x).parent->lc : (x).parent->rc ) ) //含有父指针的二叉树结点,一般会定义这样的一个宏(获取从父节点指向自己的指针)typedef enum { RE_RED, RB_BLACK} RBColor; //节点颜色template <typename T> struct BinNode{ //二叉树节点模板类// 成员 T data; BinNodePosi(T) parent; BinNodePosi(T) lc; BinNodePosi(T) rc; // 父节点以及左右孩子 int height; //高度 int npl; //Null Path Length (左式堆, 也可以用height代替) RBColor color; //颜色 红黑树// 构造函数 BinNode(): parent(NULL), lc(NULL), rc(NULL), height(0), npl(1), color(RE_RED) {} BinNode(T e, BinNodePosi(T) p = NULL, BinNodePosi(T) lc = NULL, BinNodePosi(T) rc = NULL, int h = 0, int l = 1, RBColor c = RE_RED): data(e), parent(p), lc(lc), rc(rc), height(h), npl(l), color(c){}// 操作接口 int size(); // 统计当前节点后代总数,亦即以其为根的子树的规模 BinNodePosi(T) insertAsLC( T const& ); // 作为当前节点的左孩子插入新节点 BinNodePosi(T) insertAsRC( T const& ); // 作为当前节点的右孩子插入新节点 BinNodePosi(T) succ(); //取当前节点的直接后继 template <typename VST> void travLevel( VST& ); //子树层次遍历 template <typename VST> void travPre( VST& ); //子树先序遍历 template <typename VST> void travIn( VST& ); //子树中序遍历 template <typename VST> void travPost( VST& ); //子树后序遍历// 比较器、判等器 bool operator< (BinNode const& bn) { return data < bn.data; } bool operator== (BinNode const& bn) { return data == bn.data; } bool operator> (BinNode const& bn) { return data > bn.data; } bool operator<= (BinNode const& bn) { return data <= bn.data; } bool operator>= (BinNode const& bn) { return data >= bn.data; } bool operator!= (BinNode const& bn) { return data != bn.data; }};// 插入儿子节点: 约定插入新节点之前,当前节点尚无左/右孩子template <typename T> BinNodePosi(T) BinNode<T>::insertAsLC( T const& e){ return lc = new BinNode( e, this ); /* 相当于: this->lc = new BinNode(e, this); return this->lc; */}template <typename T> BinNodePosi(T) BinNode<T>::insertAsRC( T const& e){ return rc = new BinNode( e, this );} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191// BinTree.h#include "BinNode.h"#include <queue>template <typename T> class BinTree{protected: int _size; //规模 BinNodePosi(T) _root; //根节点 virtual int updateHeight ( BinNodePosi(T) x ); //更新节点x的高度 void updateHeightAbove ( BinNodePosi(T) x ); //更新节点x及其祖先的高度public: BinTree(): _size(0), _root(NULL) {} ~BinTree() { if(0 < _size) remove( _root ); } int size() const { return _size; } bool empty() const { return !_root; } BinNodePosi(T) root() const { return _root; } BinNodePosi(T) insertAsRoot ( T const& e ); BinNodePosi(T) insertAsLC ( BinNodePosi(T) x, T const& e); BinNodePosi(T) insertAsRC ( BinNodePosi(T) x, T const& e); BinNodePosi(T) attachAsLC ( BinNodePosi(T) x, BinTree<T>* &S);//T作为x左子树插入 BinNodePosi(T) attachAsRC ( BinNodePosi(T) x, BinTree<T>* &S); int remove ( BinNodePosi(T) x); //删除以位置x处节点为根的子树,返回该子树原先的规模 BinTree<T>* secede ( BinNodePosi(T) x ); // 将子树x从当前树中摘除,并将其转换为一颗独立的子树 template <typename VST> void travLevel( VST& visit) { if(_root) _root->travLevel(visit); } // 层次遍历 template <typename VST> void travPre (VST& visit) { if(_root) _root->travPre(visit); } template <typename VST> void travIn (VST& visit) { if(_root) _root->travIn(visit); } template <typename VST> void travPost (VST& visit) { if(_root) _root->travPost(visit); } bool operator< (BinTree<T> const& t) { return _root && t._root && (_root->data < t._root->data); } bool operator== (BinTree<T> const& t) { return _root && t._root && (_root->data == t._root->data); } bool operator!= (BinTree<T> const& t) { return _root && t._root && (_root->data != t._root->data); } bool operator> (BinTree<T> const& t) { return _root && t._root && (_root->data > t._root->data); } bool operator<= (BinTree<T> const& t) { return _root && t._root && (_root->data <= t._root->data); } bool operator>= (BinTree<T> const& t) { return _root && t._root && (_root->data >= t._root->data); }};// 一旦有节点加入/离开二叉树,则更新其所有祖先的高度int max(int a,int b){ return a > b ? a : b;}template <typename T> int BinTree<T>::updateHeight(BinNodePosi(T) x){ return x->height = 1 + max(stature(x->lc), stature(x->rc));}template <typename T> void BinTree<T>::updateHeightAbove(BinNodePosi(T) x){ while(x) { updateHeight(x); x = x->parent; }} // 在某些种类的二叉树(红黑树)中,高度的定义有所不同,因此这里updateHeight()定义为保护级的虚函数,以便派生类在必要时重写(override)//节点插入:template <typename T> BinNodePosi(T) BinTree<T>::insertAsRoot( T const& e){ _size = 1; return _root = new BinNode<T>(e);}template <typename T> BinNodePosi(T) BinTree<T>::insertAsLC( BinNodePosi(T) x, T const& e){ _size++; x->insertAsLC(e); updateHeightAbove(x); return x->lc;}template <typename T> BinNodePosi(T) BinTree<T>::insertAsRC( BinNodePosi(T) x, T const& e){ _size++; x->insertAsRC(e); updateHeightAbove(x); return x->lc;}//子树接入://指针是一个存放地址的变量,而指针引用指的是这个变量的引用,众所周知C++中如果参数不是引用的话会调用参数对象的拷贝构造函数,所以如果有需求想改变指针所指的对象(换句话说,就是要改变指针里面存的地址),就要使用指针引用template <typename T>BinNodePosi(T) BinTree<T>::attachAsLC( BinNodePosi(T) x, BinTree<T>* &S){ if(x->lc = S->_root) x->lc->parent = x; _size += S->_size; updateHeightAbove(x); S->root = NULL; S->_size = 0; release( S ); S = NULL; return x;}template <typename T>BinNodePosi(T) BinTree<T>::attachAsRC( BinNodePosi(T) x, BinTree<T>* &S){ if(x->rc = S->_root) x->rc->parent = x; _size += S->_size; updateHeightAbove(x); S->root = NULL; S->_size = 0; release( S ); S = NULL; return x;}//子树删除template <typename T>int BinTree<T>::remove( BinNodePosi(T) x ){ FromParentTo(*x) = NULL; //切断来自父节点的指针 updateHeightAbove(x->parent);//更新祖先高度 int n = removeAt(x); _size -= n; return n; // 删除子树x,更新规模,返回删除节点总数}template <typename T> static int removeAt( BinNodePosi(T) x ){ if( !x ) return 0; int n = 1 + removeAt( x->lc ) + removeAt( x->rc );// release( x->data );// release( x ); delete x; return n; }// 子树分离template <typename T>BinTree<T>* BinTree<T>::secede( BinNodePosi(T) x ){ FromParentTo ( *x ) = NULL; updateHeightAbove( x->parent ); BinTree<T>* S = new BinTree<T>; S->root = x; x->parent = NULL; S->_size = x->size(); _size -= S->_size; return S;}// 遍历:template <typename T, typename VST>void travPre ( BinNodePosi(T) x, VST& visit ){ if( !x ) return; visit (x->data); travPre (x->lc, visit); travPre (x->rc, visit);} template <typename T, typename VST>void travPost ( BinNodePosi(T) x, VST& visit ){ if( !x ) return; travPre (x->lc, visit); travPre (x->rc, visit); visit (x->data);} template <typename T, typename VST>void travIn ( BinNodePosi(T) x, VST& visit ){ if( !x ) return; travPre (x->lc, visit); visit (x->data); travPre (x->rc, visit);} // 直接后继及其定位 (中序遍历)template <typename T> BinNodePosi(T) BinNode<T>::succ(){ BinNodePosi(T) s = this; if(rc) //若有右孩子,则直接后继必在右子树中 { s = rc; while(HasLChild(*s)) s = s->lc; } else // 否则,直接后继应是“将当前节点包含于其左子树中的最低祖先” { while(IsRChild(*s)) s = s->parent; s = s->parent; } return s;}// 层次遍历template <typename T> template <typename VST>void BinNode<T>::travLevel(VST& visit){ std::queue<BinNodePosi(T)> Q; Q.push (this); while( !Q.empty() ){ BinNodePosi(T) x = Q.front(); Q.pop(); visit(x->data); if(HasLChild(*x)) Q.push(x->lc); if(HasRChild(*x)) Q.push(x->rc); }} 123456789101112//test.cpp#include <iostream>#include "BinTree.h"using namespace std;int main(){ BinTree<int> test; test.insertAsRoot(1); cout << test.size(); return 0;} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160#include <iostream>#include <queue>using namespace std;template < typename T >struct TreeNode{ TreeNode(T s): data(s), left(NULL), right(NULL) {} T data; TreeNode* left; TreeNode* right;};template < typename T >class Tree {private: int size; TreeNode<T>* root;public: Tree(): size(0), root(NULL){}; Tree( T x ){ size = 1; root = new TreeNode<T>(x); } ~Tree(){ if(size > 0){ queue<TreeNode<T>*> delq; delq.push(root); while(!delq.empty()){ TreeNode<T>* x = delq.front(); delq.pop(); if(x->left) delq.push(x->left); if(x->right) delq.push(x->right); delete( x ); } } } Tree<T>& operator= (Tree<T>& t){ if(this->root != t.root) { this->root = t.root; } return *this; } int getsize()const { return this->size; } TreeNode<T>* getroot() const { return this->root; } TreeNode<T>* insertasleft( TreeNode<T>* x, T data ){ x->left = new TreeNode<T>(data); size++; return x; } TreeNode<T>* insertasright( TreeNode<T>* x, T data ){ x->right = new TreeNode<T>(data); size++; return x; } void preorder( TreeNode<T>* root){ cout << root->data << " "; if(root->left) preorder(root->left); if(root->right) preorder(root->right); } void inorder( TreeNode<T>* root){ if(root->left) inorder(root->left); cout << root->data << " "; if(root->right) inorder(root->right); } void postorder( TreeNode<T>* root){ if(root->left) postorder(root->left); if(root->right) postorder(root->right); cout << root->data << " "; } void levelorder( TreeNode<T>* root){ queue<TreeNode<T>*> Q; Q.push(root); int levelcur = 0; while(!Q.empty()) { levelcur ++; cout << "level " << levelcur << " : "; queue<TreeNode<T>*> rem; while(!Q.empty()) { TreeNode<T>* x = Q.front(); Q.pop(); if(x->left) rem.push(x->left); if(x->right) rem.push(x->right); cout << x->data << " "; } queue<TreeNode<T>*> temp = Q; Q = rem; rem = temp; cout << endl; } } int find_leaf_size( TreeNode<T>* leaf ){ if( !leaf ) return 0; if( leaf->left == NULL && leaf->right == NULL ) return 1; return find_leaf_size( leaf->left ) + find_leaf_size( leaf->right ); } int find_leaf_depth( TreeNode<T>* leaf){ if(!leaf) return 0; int size_left = find_leaf_depth( leaf->left ); int size_right = find_leaf_depth( leaf->right ); if( size_left > size_right ) return size_left + 1; else return size_right + 1; } TreeNode<T>* find_x_leaf( TreeNode<T>* root, const T& x){ if( !root ) return NULL; if( root->data == x ) return root; TreeNode<T>* find_left = find_x_leaf ( root->left, x ); if( find_left ) return find_left; else return find_x_leaf ( root->right, x ); } int find_x_level_size( TreeNode<T>* root, const T& x){ if( !root ) return 0; if( x == 1 ) return 1; else return find_x_level_size( root->left, x-1 ) + find_x_level_size( root->right, x-1 ); } };int main(){ Tree<int> test(1); cout << "getsize: " << test.getsize() << endl; test.insertasleft( test.getroot(), 2); test.insertasright( test.getroot(), 3); cout << "getsize: " << test.getsize() << endl; cout << "preorder: "; test.preorder( test.getroot() ); cout << endl; cout << "inorder: "; test.inorder( test.getroot() ); cout << endl; cout << "postorder: "; test.postorder( test.getroot() ); cout << endl; Tree<int> test1; test1 = test; cout << "test1 after = : test1.root->data = " << test.getroot()->data << endl; cout << "leveltravel: " << endl; test.levelorder( test.getroot() ); cout << endl; cout << "find_leaf_size : " << endl; cout << " test.root : " << test.find_leaf_size( test.getroot() ) << endl; cout << " test.root->left : " << test.find_leaf_size( test.getroot()->left ) << endl; cout << " test.root->right : " << test.find_leaf_size( test.getroot()->right ) << endl; cout << "find_leaf_depth : " << endl; cout << " test.root : " << test.find_leaf_depth( test.getroot() ) << endl; cout << " test.root->left : " << test.find_leaf_depth( test.getroot()->left ) << endl; cout << " test.root->right : " << test.find_leaf_depth( test.getroot()->right ) << endl; cout << "find_x_leaf : " << endl; cout << " 1 : " << test.find_x_leaf( test.getroot(), 1 )->data << endl; cout << "find_x_level_size : " << endl; cout << " level-2 : " << test.find_x_level_size( test.getroot(), 2 ) << endl; return 0;} Donate? comment? Donate WeChat Pay Alipay