这里主要讲解红黑树的源码实现,并附上源码。具体参考书籍为《算法导论》
首先,我们知道红黑树也是树的一种,所以在程序的设计上,它的大部分方法完全能够继承自普通树(父类)的方法,父类的存在可以使得在对树这种数据结构了解的同时,同时也注意程序的高聚合与低耦合性。原先在对二叉树与红黑树数据结构实现的时候,都是分为一个二叉树实现类,一个红黑树实现类,两个类中,往往好多方法都是重用,以至于这里copy过去,那里从copy过来,完全没注意聚合与耦合的问题。大神就略过,希望能够对你编程规范有一定帮助。
环境为VS2015
1、父类的实现 CTree
#pragma once
#include <iostream>
#include <map>
#include <list>
#include <queue>
using namespace std;
/************************************************************************/
/* 普通树(父类) 包含一些树节点的定义和通用方法 */
/************************************************************************/
enum ColorType
{
RED,
BLACK,
};
struct NODE
{
int key;
NODE *pLeft;
NODE *pRight;
NODE *pParent;
ColorType color;
};
struct CHILDNUM
{
int nLeftNum;
int nRightNum;
int totalSpace;// 空格数
};
class CTree
{
public:
CTree();
~CTree();
virtual void MakeTree(int *pAry, int nLen); // 使用数组生成树结构
virtual void TreeInsert(int key) = 0; // 插入数据节点(普通二叉树插入方法)
virtual NODE* SearchNode(int nValue); // 根据值查找目标节点
virtual int GetTreeHeight(NODE *pNode); // 获取树的高度
NODE* GetRootNode() const; // 获取根节点
void PrintTree(); // 打印成树形(类似层序遍历)
NODE *m_pRoot; // 根节点
bool m_bInitRoot; // 根节点是否初始化
private:
void GetChildNum(NODE *pNode, int &nNum); // 获取子节点的个数(采用前序遍历的方式)
void GetChildNumToMap(NODE *pNode); // 计算每个子节点的个数,并存储到map结构中(使用前序遍历获取每个节点的子节点个数并存储到map中)
void PrintSingleNode(NODE *pNode, int &nOffset); // 打印一行树
void PrintSpace(int nSpace, int key, int &nOffset); // 打印空格
NODE* TreeSearch(NODE *pNode, int value); // 查询二叉搜索树(递归算法)
map<NODE*, CHILDNUM> m_Map; // 记录每个节点的子节点个数
};
提供给外部的接口均是一些插入、生成树结构、查找某个key对应的目标节点,以及打印树结构等普通树的公共方法,而主要的实现封装在私有成员函数中,比如打印树中设计到的打印空格与打印行数。
而为什么父类的成员函数要使用virtual关键字,当然是为了实现类的多态。也方便后期实现一个树的工厂方法,达到通过一个工厂方法进行对不同树对象的操作。如果不懂工厂方法,可以留言我再加上,也很简单。
2、二叉树的简单实现 CBinaryTree
#pragma once
#include "Tree.h"
/************************************************************************/
/* 二叉树 */
/************************************************************************/
class CBinaryTree : public CTree
{
public:
CBinaryTree();
~CBinaryTree();
virtual void TreeInsert(int key) override;// 数据插入生成树结构
private:
void BinaryTreeInsert(NODE* &pNode, NODE *pNewNode); // 插入数据节点(普通二叉树插入方法)
};
父类CTree中,对TreeInsert的实现是纯虚函数,所以这里需要子类继承实现。
3、红黑树的简单实现 CRBTree
#pragma once
#include "Tree.h"
/************************************************************************/
/* 红黑树 */
/************************************************************************/
class CRBTree : public CTree
{
public:
CRBTree();
~CRBTree();
virtual void TreeInsert(int key) override;
private:
void RB_INSERT_FIXUP(NODE* &pRoot, NODE *pNowNode);// 使得新的节点加入后依旧保持红黑树性质
void LeftRotate(NODE* &pRoot, NODE *pNode);// 左旋转
void RightRotate(NODE* &pRoot, NODE *pNode);// 右旋转
void RBTreeInsert(NODE *pNewNode);// 重写插入算法(红黑树树插入方法)
};
小结:通过对父类CTree的继承,不仅仅可以简单看出二叉树与红黑树的差别,也省去了很多冗余的方法。通过对树的学习,我们可以了解map的基本实现原理,如果这里使用模板来实现就更好了。
类的具体是实现源码地址:https://download.csdn.net/download/qq_30145355/10525848