数据结构与算法——二叉树的实现(C++)

文章目录

  • 二叉树的实现
    • 1 BinNode类
    • 2 BinTree类
    • 3 程序测试
    • 4 总结

二叉树的实现

1 BinNode类

BinNode作为二叉树的节点,其定义的规范性十分基础又十分重要。以下是"BinNode.h"中的程序内容。

#pragma once
#define BinNodePosi(T) BinNode* //节点位置 
#define stature(p) ((p) ? (p)->height: -1) //节点高度

//BinNode状态与性质的判断
#define IsRoot(x) (!((x).parent))
#define IsLeaf(x) (!((x).lc || (x).rc))  
#define IsLChild(x) (!((x).parent) && (&(x) == (x).parent->lc))
#define IsRChild(x) (!((x).parent) && (&(x) == (x).parent->rc))
#define HasParent(x) ((x).parent) 
#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 sibling(p) (IsLChild(*(p)) ? (x).parent.rc: (x).parent.lc)          //兄弟 
#define uncle(p) (sibling((p).parent))                                              //叔叔 
#define FromParentTo(x)  ( IsRoot(x) ? _root : ( IsLChild(x) ? (x).parent->lc : (x).parent->rc ) )         //来自父亲的引用
 
typedef enum { RB_RED, RB_BLACK } RBColor; //节点颜色
 
template <typename T> struct BinNode{
	BinNodePosi(T) parent;
	BinNodePosi(T) lc;
	BinNodePosi(T) rc; //父亲、孩子
    int npl;
    RBColor color;
	T data; int height;  //高度、子树规模
    //构造函数
    BinNode():
        parent( nullptr ), lc( nullptr ),rc( nullptr ),height ( 0 ),npl( 1 ),color ( RB_RED ) {}
    BinNode( T e, BinNodePosi(T) p = nullptr, BinNodePosi(T) lc = nullptr, BinNodePosi(T) rc = nullptr, int h = 0, int l = 1, RBColor c = RB_RED):
        data( e ), parent( p ), lc( lc ), rc( rc ),height ( h ),npl( 1 ),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 &); //子树后序遍历
};

//作为左孩子插入
template <typename T> BinNodePosi(T) BinNode<T>::insertAsLC(T const &e)
	{return lc = new BinNode( e, this);}
//作为右孩子插入
template <typename T> BinNodePosi(T) BinNode<T>::insertAsRC(T const &e)
	{return rc = new BinNode( e, this);}

//size()
template <typename T> int BinNode<T>::size(){//后代总数,以其为根的子树的规模
	int s = 1; //计入本身
	if (lc) s += lc->size(); //递归计入左子树规模
	if (rc) s += rc->size(); //递归计入右子树规模
	return s;
}//O(n=|size|)

2 BinTree类

BinTree类是二叉树实现的主体部分,主要包括二叉树的构造,插入与遍历等功能函数。

#include "binnode.h"
#include "release.h"
#include 
#include 
#include "../dsa_queue_20200717/queue.h"

#define max(a,b) ( a > b ? a : b)

template <typename T> class BinTree{
protected:
	int _size;//规模
	
	virtual int updateHeight( BinNodePosi(T) x); //更新节点x的高度
	void updateHeightAbove( BinNodePosi(T) x); //更新x及祖先的高度
public:
	BinNodePosi(T) _root; //根节点
    //构造函数
    BinTree():_size( 0 ), _root ( nullptr ) {}
    //~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);//作为左子树接入
	BinNodePosi(T) attachAsRC(BinNodePosi(T) x, BinTree<T>* &S);//作为右子树接入

	int remove(BinNodePosi(T) x);//删除以节点x为根的子树
    template <typename VST> void travPre(BinNodePosi(T) x, VST& visit) { if (_root) _root->travPre(visit); }//先序遍历
    template <typename VST> void travPost(const VST& visit) { if (_root) _root->travPost(visit); }//后序遍历
	template <typename VST> void travLevel(const VST& visit) { if (_root) _root->travLevel(visit); }//层次遍历
	template <typename VST> void travIn( const VST& visit) { if (_root) _root->travIn(visit); }//中序遍历

	void traverse (BinNodePosi(T) x, void (*)(T&) );
};
template <typename T> void BinTree<T>::traverse ( BinNodePosi(T) x, void (*visit )( T& ))
{
    if( !x ) return;
	visit( x->data );
	traverse( x->lc, visit );

	traverse( x->rc, visit );
	
}
//先序遍历
template <typename T, typename VST> void travPre(BinNodePosi(T) x, VST& visit) {
	if( !x ) return;
	//BinNodePosi(T) x = root();
	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;
	travPost( x->lc, visit );
	travPost( x->rc, visit );
	visit( x->data );

}
//中序遍历
template <typename T, typename VST> void travIn(BinNodePosi(T) x, VST& visit) {
	if( !x ) return;
	travIn( x->lc, visit );
	visit( x->data );
	travIn( x->rc, visit );


}
//层次遍历
template <typename T> template <typename VST> void BinNode<T>::travLevel ( VST& visit){
	Queue<BinNodePosi(T)> Q;
	Q.enqueue( this );
	while( !Q.empty()){
		BinNodePosi(T) x = Q.dequeue();visit( x->data);
		if( HasLChild(*x )) Q.enqueue( x->lc);
		if( HasRChild(*x )) Q.enqueue( x->rc);
	}
}
//更新节点x的高度
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; }
}

//空树插入根节点
template <typename T>
BinNodePosi(T) BinTree<T>::insertAsRoot(T const& e)
{
	_size = 1; return _root = new BinNode<T> (e);
}

//作为节点x的左孩子插入
template <typename T>
BinNodePosi(T) BinTree<T>::insertAsLC(BinNodePosi(T) x,T const& e)
{
	_size++; x->insertAsLC(e); updateHeightAbove(x); return x->lc;
}
//作为节点x的右孩子插入
template <typename T>
BinNodePosi(T) BinTree<T>::insertAsRC(BinNodePosi(T) x,T const& e)
{
	_size++; x->insertAsRC(e); updateHeightAbove(x); return x->rc;
}
//S作为节点x的左子树插入
//S本身被置空
template <typename T>
BinNodePosi(T) BinTree<T>::attachAsLC(BinNodePosi(T) x, BinTree<T>* &S)
{
	x->lc = S->_root;
	x->lc->parent = x;

	_size += S->_size;
	updateHeightAbove(x);
	S->_root =nullptr;
	S->size = 0; dtl::release(S); S = nullptr; return x;
}
//S作为节点x的右子树插入
//S本身被置空
template <typename T>
BinNodePosi(T) BinTree<T>::attachAsRC(BinNodePosi(T) x, BinTree<T>* &S)
{
	x->rc = S->_root;
	x->rc->parent = x;

	_size += S->_size;
	updateHeightAbove(x);
	S->_root = nullptr;
	S->size = 0; dtl::release(S); S = nullptr; return x;
}

template <typename T>//二叉树删除x节点及其后代
int BinTree<T>::remove(BinNodePosi(T) x)
{
	FromParentTo( *x ) = nullptr;
	updateHeightAbove ( x->parent );
	int n = removeAt( x ); _size -=n;
	return n;
}

template <typename T>//删除x节点及其后代,返回删除节点数
static int removeAt(BinNodePosi(T) x)
{
	if (!x)return 0;//递归基
	int n = 1 + removeAt(x->lc) + removeAt(x->rc);
	dtl::release(x->data); dtl::release(x); return n;
}

3 程序测试

撰写以下的主程序对二叉树进行测试,分别测试了二叉树的基于函数指针的各种遍历与二叉树的删除子树操作,结果可见注释。

/*
* The program aims to test BinTree class
* author@Ripples
* 20200723
*/
#include 
#include 
#include 
#include "bintree.h"
#include "../dsa_vector_200622/dsa_vector.h"

using namespace std;

template<typename T> void returnValue(T& a)
{
    cout << "return_value: " << a << endl;
}

int main(int argc,char* argv[])
{
	//构造树
	BinTree<char> bt_test;
	bt_test.insertAsRoot('b');
	bt_test.insertAsLC(bt_test.root(), 'a');
	bt_test.insertAsRC(bt_test.root(), 'f');
	bt_test.insertAsLC(bt_test.root()->rc, 'd');
	bt_test.insertAsRC(bt_test.root()->rc, 'g');
	bt_test.insertAsLC(bt_test.root()->rc->lc, 'c');
	bt_test.insertAsRC(bt_test.root()->rc->lc, 'e');
	/*
						b
	     	a							f
								d				g
							c		e
	*/
	//前序遍历:b,a,f,d,c,e,g
	//后序遍历:a,c,e,d,g,f,b
	//中序遍历:a,b,c,d,e,f,g
	void (* visit)(char& ) = &returnValue;
	bt_test.traverse(bt_test.root(),visit);

	//删除右子树之后遍历
	cout << "modifed:" << endl;
	bt_test.remove(bt_test.root()->rc);
	bt_test.traverse(bt_test.root(),visit);//b,a

	return 0;
}

4 总结

二叉树作为一个承接向量、列表,启出搜索树(二叉搜索树、平衡二叉搜索树与AVL树)和高级搜索树(伸展树、B-树与红黑树)的重要节点,其研究有深远的意义。二叉树的实现基本完成,仍存在一些细节有待完善。

你可能感兴趣的:(数据结构及实现,二叉树,算法,数据结构,c++)