真c++ 从二叉树到红黑树(2)之二叉树基类

  此文章为从二叉树到红黑树系列文章的第二节,主要介绍介绍二叉树抽象基类的基本组成。为后续BST,AVL和RedBlack做好铺垫


文章目录

  • 一、前面文章链接~(点击右边波浪线可以返回目录)
  • 二、二叉树抽象基类~
    • (一)定义变量和接口~
      • 1.需要的变量~
      • 2.需要的接口~
      • 3.重要辅助函数~
      • 4.其他辅助函数~
      • 5.BinTree.h~
    • (二)获取当前节点的父亲的孩子的引用~
    • (三)更新当前节点的高度~
    • (四)更新当前节点及其祖先节点的高度~
    • (五)删除函数~
    • (六)release.h头文件~
    • (七)完整BinTree.h~
  • 三、后序文章链接~

一、前面文章链接~(点击右边波浪线可以返回目录)

  在阅读本文前,强烈建议你看下前面的文章的目录、前言以及基本介绍,否则你无法理解后面的内容。链接如下:

  1. 基本二叉树节点,通用函数 二叉树节点

二、二叉树抽象基类~

(一)定义变量和接口~

1.需要的变量~

int _size;//二叉树的规模
BinNodePtr _root;//二叉树的树根

2.需要的接口~

构造,析构
判空
获取二叉树的规模、根节点
获取二叉树当前高度
四种遍历(结合根节点使用)

3.重要辅助函数~

获取当前节点的父亲的孩子的引用。(这句话有点拗口,但这个函数是整个流程的关键)
FromParentTo

4.其他辅助函数~

更新节点的高度 updateHeight
更新节点以及其祖先的高度 updateHeightAbove
删除所有节点 remove
插入节点insert(为了方便起见,设为纯虚函数,使这个二叉树基类不能实例化)

5.BinTree.h~

template<typename T=int>
class BinTree {
protected:
	using BinNodePtr = BinNode<T>*;
	using BinTreePtr = BinTree<T>*;

protected:
	int _size;//二叉树的规模
	BinNodePtr _root;//二叉树的树根

public:
	BinTree() :_size(0), _root(nullptr) {}
	virtual ~BinTree() {
		//std::cout << "调用析构函数" << std::endl;
		if (0 < _size)remove(_root); 
	}

public:
	constexpr int size()const { return _size; }//规模

	constexpr bool empty()const { return !_root; }//判空

	inline BinNodePtr root()const {//返回树根
		return (_root) ? _root : nullptr;
	}

	constexpr int getHeight()const {//获取树高度
		return (this->_root) ? this->_root->_height : -1;
	}

public:
	template<typename VST>//层次遍历
	void travLevel(VST visit) {
		if (_root)
			_root->travLevel(visit);
	}

	template<typename VST>//先序遍历
	void travPre(VST visit,const int&method=1) {
		if (_root)
			_root->travPre(visit, method);
	}

	template<typename VST>//中序遍历
	void travIn(VST visit, const int& method = 1) {
		if (_root)
			_root->travIn(visit, method);
	}

	template<typename VST>//后序遍历
	void travPost(VST visit, const int& method = 1) {
		if (_root)
			_root->travPost(visit, method);
	}

protected:
	virtual int updateHeight(BinNodePtr x)const;//更新节点x的高度/*vs开最新版本的c++就可以用virtual constexpr*/

	void updateHeightAbove(BinNodePtr x)const;//更新节点x及其祖先的高度

protected:
	//注意返回值为引用,不然无法作为左值
	BinNodePtr& FromParentTo(BinNodePtr x) {/*用这个更改x的父亲的左右孩子*//*接受者一般要加个引用接收*/
		return   (IsRoot(x) ? this->_root : (IsLChild(x) ? x->_parent->_lchild : x->_parent->_rchild));
	}

protected:
	virtual BinNode<T>* insert(const T& data) = 0;//插入节点,为了方便起见,设为纯虚函数,即这个基类为抽象类,没有实例

private:
	void remove(BinNodePtr x);//只用于析构函数,因此不管高度等其他因素,直接暴力全部删除

};//class BinTree

(二)获取当前节点的父亲的孩子的引用~

  这个函数对于AVL树和RedBlack树的插入和删除而言,至关重要。我会在AVL和RedBlack树的相应部分再次说明这个函数的作用。

//注意返回值为引用,不然无法作为左值
BinNodePtr& FromParentTo(BinNodePtr x) {/*用这个更改x的父亲的左右孩子*//*接受者一般要加个引用接收*/
	return   (IsRoot(x) ? this->_root : (IsLChild(x) ? x->_parent->_lchild : x->_parent->_rchild));
}

(三)更新当前节点的高度~

此处stature是本系列文章第一节的在全局区定义的函数,头文件为BInNode_Macro.h。

//更新节点x的高度
template<typename T>
int BinTree<T>::updateHeight(BinNodePtr x)const {
	//高度为左右子树的高度的最大值
	return x->_height = 1 + std::max(stature(x->_lchild), stature(x->_rchild));
}

(四)更新当前节点及其祖先节点的高度~

  通常,还需要从当前节点出发沿parent指针逆行向上,依次更新各代祖先的高度记录,直到这个祖先的高度不变时停止。

//更新节点x及其祖先的高度
template<typename T>
void BinTree<T>::updateHeightAbove(BinNodePtr x)const{
	if (x == nullptr)
		return;
	updateHeight(x);
	do {
		x = x->_parent;
		if (x == nullptr)//如果父节点为空节点,则返回
			return;
		int currentHeight = x->_height;//记录节点当前的高度
		int afterHeight = updateHeight(x);
		if (currentHeight == afterHeight)//只要其高度没有更新,那么就可以跳出循环
			break;
	} while (x);//当此节点不为空
}

(五)删除函数~

这个函数用于析构函数中,用于所有树的析构,无论是BST,AVL还是RedBlack。

//=========删除============//
template<typename T>
void BinTree<T>::remove(BinNodePtr x) {
	if (nullptr==x)
		return;
	remove(x->_lchild);
	remove(x->_rchild);/*处于方便,用递归删除*/
	release(x->_data);
	release(x);
}

(六)release.h头文件~

  在(五)中的删除代码中,可以看到用到了release函数来进行节点的删除,其位于头文件release.h中。

该删除函数用到了模板偏特化技术。
#pragma once

template<typename T>
struct Cleaner {
	static void clean(T& x) {
#ifdef DEBUG
		printf("删除了\n");
#endif // DEBUG
	}
};

template<typename T>
struct Cleaner<T*> {
	static void clean(T*& x) {//注意这里是引用,方便删除后,直接变成空指针
		if (x) {
			delete x;
			x = nullptr;
		}
	}
};

template<typename T>
static void release(T &x) {//利用模板偏特化,删除节点,若为指针,则delete,若不为指针,则不做任何操作。
	Cleaner<T>::clean(x);
}

(七)完整BinTree.h~

#pragma once
#include"BinNode.h"
#include "release.h"

namespace mytree {

	using namespace mytree_marcro;

	template<typename T=int>
	class BinTree {
	protected:
		using BinNodePtr = BinNode<T>*;
		using BinTreePtr = BinTree<T>*;

	protected:
		int _size;//二叉树的规模
		BinNodePtr _root;//二叉树的树根

	public:
		BinTree() :_size(0), _root(nullptr) {}
		virtual ~BinTree() {
			//std::cout << "调用析构函数" << std::endl;
			if (0 < _size)remove(_root); 
		}

	public:
		constexpr int size()const { return _size; }//规模

		constexpr bool empty()const { return !_root; }//判空

		inline BinNodePtr root()const {//返回树根
			return (_root) ? _root : nullptr;
		}

		constexpr int getHeight()const {//获取树高度
			return (this->_root) ? this->_root->_height : -1;
		}

	public:
		template<typename VST>//层次遍历
		void travLevel(VST visit) {
			if (_root)
				_root->travLevel(visit);
		}

		template<typename VST>//先序遍历
		void travPre(VST visit,const int&method=1) {
			if (_root)
				_root->travPre(visit, method);
		}

		template<typename VST>//中序遍历
		void travIn(VST visit, const int& method = 1) {
			if (_root)
				_root->travIn(visit, method);
		}

		template<typename VST>//后序遍历
		void travPost(VST visit, const int& method = 1) {
			if (_root)
				_root->travPost(visit, method);
		}

	protected:
		virtual int updateHeight(BinNodePtr x)const;//更新节点x的高度/*vs开最新版本的c++就可以用virtual constexpr*/

		void updateHeightAbove(BinNodePtr x)const;//更新节点x及其祖先的高度

	protected:
		//注意返回值为引用,不然无法作为左值
		BinNodePtr& FromParentTo(BinNodePtr x) {/*用这个更改x的父亲的左右孩子*//*接受者一般要加个引用接收*/
			return   (IsRoot(x) ? this->_root : (IsLChild(x) ? x->_parent->_lchild : x->_parent->_rchild));
		}

	protected:
		virtual BinNode<T>* insert(const T& data) = 0;//插入节点,为了方便起见,设为纯虚函数,即这个基类为抽象类,没有实例

	private:
		void remove(BinNodePtr x);//只用于析构函数,因此不管高度等其他因素,直接暴力全部删除

	};//class BinTree

	//================更新高度==================//
	//更新节点x的高度
	template<typename T>
	int BinTree<T>::updateHeight(BinNodePtr x)const {
		return x->_height = 1 + std::max(stature(x->_lchild), stature(x->_rchild));//高度为左右子树的高度的最大值
	}

	//更新节点x及其祖先的高度
	template<typename T>
	void BinTree<T>::updateHeightAbove(BinNodePtr x)const{
		if (x == nullptr)
			return;
		updateHeight(x);
		do {
			x = x->_parent;
			if (x == nullptr)//如果父节点为空节点,则返回
				return;
			int currentHeight = x->_height;//记录节点当前的高度
			int afterHeight = updateHeight(x);
			if (currentHeight == afterHeight)//只要其高度没有更新,那么就可以跳出循环
				break;
		} while (x);//当此节点不为空
	}

	//=========删除============//
	template<typename T>
	void BinTree<T>::remove(BinNodePtr x) {

		if (nullptr==x)
			return;
		remove(x->_lchild);
		remove(x->_rchild);/*处于方便,用递归删除*/
		release(x->_data);
		release(x);
	}
}//namespace mytree

三、后序文章链接~

  1. 基本二叉树节点,通用函数 二叉树节点
  2. 基本二叉树类的定义和实现 二叉树基类
  3. BST(二叉搜索树的实现) BST
  4. AVL(二叉平衡搜索树的实现)AVL
  5. B树的实现(如果你只想了解B树,可以跳过所有章节,直接看B树)B树
  6. 红黑树的实现 RedBlack

学一个东西,不知道其道理,不高明!

你可能感兴趣的:(C++数据结构与算法)