PS:
2013.2.5修改了树的实现:
1、将关键字K与值域T分离开来,重新更新相关代码,Remove函数以及Find函数。
2、对于旋转操作中的需要先左旋再右旋 以及 先右旋再左旋这两种操作,合并为一个函数来实现了
3、T类需要提供的3种比较操作 operator<=(const T &t),用于Insert函数; operator==(const K &k),operator>(const K &k),用于Find函数
2013.2.21修改了:
1、find,remove的Key参数改为引用传值
2、增加了一个GetRoot();
2013.3.1修改了:
本次修改是为了实现允许使用不同种类的关键字对TTree进行查找操作
结点TLeaf中保存关键字K的值
Insert函数中之前需要的operator<=(const T &t)去掉,不再需要。
Insert函数中改为使用operator>(const K &k)进行比较插入
2013.3.6修改了:
增加了两个功能函数到tool.h
用来处理模版参数T是对象,还是对象的指针的处理
当T是对象时,模板中的operator> 应该是 T > K
当T是对象的指针时,模板中的operator> 应该是 (*T) > K
template <class T>
T& GetRef(T& o)
{
return o;
}
template <class T>
T& GetRef(T* o)
{
return *o;
}
2013.6.5修改了容器的实现:继承了后面提到的TContainer,实现相关接口。
说明:
1、叶子节点结构的设计上,除了基本的左右叶子节点和值域外,另外消耗了20个字节(6项属性)用于树操作过程中需要的一些附加值的记录,因此这个类在性价比上更适合来管理一些占内存比较多的大对象数组,比如我们游戏设计当中character对象,如果只是用来管理个DWORD数组,则显得有些得不偿失。
2、效率上的问题。AVLTree这个操作,由于需要从被改变的节点开始一直平衡到根节点,测了一下还是比较消耗时间的(100W个数据的打乱顺序的插入操作,插入时进行AVLTree操作耗时1200毫秒左右,而插入时不进行AVLTree操作耗时900毫秒的样子)。
至于查找操作,实际测下来反而比stl的map和set都要快些,不知道如果将stl的map和set的内存分配方式改为内存池的方式下,效果怎样,没有具体做过,那位大大测试过欢迎给出测试数据。至于这个AVL树的测试结果,以及与stl的map和set的比较的测试结果,见自己的底层代码库(四)——计时模块。
3、在进行删除操作时:1、是直接交换两个结点,而不是交换两结点的值域。2、删除接口bool TTree<T>::Remove(T *pEg)没有再加锁,而是在其内部调用的Find跟Remove这两个函数分别加的锁,当多线程同时删除一个相同的结点的时候,后进bool TTree<T>::Remove(TLeaf<T> *pLeaf)函数的线程将通过判断if (this == pLeaf->m_pTree)过滤掉,因此没有多线程的问题。
4、本树给出了按树状结构打印一棵树的功能,打印如下所示,并生成log文件。(之前发的结果在网页上无法对齐,现改为发个文本文档中的截图)
最后贴上代码
TTree.h:
#ifndef _TTree_h_
#define _TTree_h_
#include <stdio.h>
#include <windows.h>
#include "TContainer.h"
template <class K, class T>
class TTree;
//叶子结点
template <class K, class T>
struct TLeaf
{
TLeaf<K, T> *m_pLeft; //左叶子结点
TLeaf<K, T> *m_pRight; //右叶子结点
K m_Key; //比较值域
T m_Value; //值域
//以上为树的基本属性
short m_sBF; //平衡因子
//记录平衡因子是为了在多次左旋右旋操作时
//除非有必要,否则不再每次都重复计算子结点的平衡因子
WORD m_wHeight; //高度
//2^30 = 1G,因此高度用BYTE表示就已经足够
//此处用WORD只是为了和平衡因子凑足4字节对齐,不用也是浪费
TLeaf<K, T> *m_pFather; //父结点
//记录父结点用于在平衡操作时直接循环向根操作,不用递归
TLeaf<K, T> *m_pLast; //上一个结点
TLeaf<K, T> *m_pNext; //下一个结点
//记录前序的上一个结点和下一个结点
//是为了在删除操作时直接取用于替换的结点,不再做查找操作
TTree<K, T> *m_pTree; //该结点当前从属的树对象
//属于树操作的合法性验证字段
void Init()
{
m_pLeft = NULL;
m_pRight = NULL;
m_wHeight = 0;
m_sBF = 0;
m_pFather = NULL;
m_pLast = NULL;
m_pNext = NULL;
m_pTree = NULL;
}
};
//AVL树
//该类自己不申请TLeaf,只是负责管理外部申请的TLeaf结点
//将其组织成树,提供插入、删除、查找功能
//该树允许存在相同的key
//使用该类时,需要K提供:
//operator==(const K &k),operator>(const K &k)
template <class K, class T>
class TTree : public TContainer<T>
{
public:
TTree();
~TTree();
//将pLeaf加入到树中合适的位置上
//成功返回true
//参数不合法(为空/已经属于这棵树),返回false
bool Insert(TLeaf<K, T> *pLeaf);
//在树中查找与关键字匹配的第一个结点
//并移除该结点
//成功返回被移除的结点
//参数不合法(为空),返回NULL
//未找到匹配的结点,返回NULL
TLeaf<K, T> *Remove(K& key);
//移除树根结点
TLeaf<K, T> *RemoveHead();
//在树中移除pLeaf结点
//成功返回true
//参数不合法(不属于这棵树),返回false
bool Remove(TLeaf<K, T> *pLeaf);
//在树中查找与关键字匹配的第一个结点
//找到返回该匹配的结点
//参数不合法(为空),返回NULL
//未找到匹配的结点,返回NULL
TLeaf<K, T> *Find(K& key);
//初始化\清空AVL树
void Init(ContainerFlag dwLock = enum_EnableLock);
//获取AVL树头对象
//若m_pHead为空则返回空
T *GetHead();
//获取AVL树中curr的下一个对象
//若curr为空则返回空
//若curr没有下一个对象则返回空
T *GetNext(T *curr);
//获取AVL树中curr对应的结点对象
//若curr为空则返回空
void *GetNode(T *curr);
private:
void AVLTree(TLeaf<K, T> *pLeaf);//从pLeaf开始,向根方向平衡整棵树
void AVL(TLeaf<K, T> *pLeaf);//平衡pLeaf做为根的子树
void L(TLeaf<K, T> *pLeaf);//左旋
void LR(TLeaf<K, T> *pLeaf);//左旋后再右旋
void R(TLeaf<K, T> *pLeaf);//右旋
void RL(TLeaf<K, T> *pLeaf);//右旋后再左旋
void H(TLeaf<K, T> *pLeaf);//计算pLeaf结点的高度,更新m_wHeight
void BF(TLeaf<K, T> *pLeaf);//计算pLeaf结点的平衡因子,更新m_sBF
TLeaf<K, T> *m_pRoot;//根指针
//附加以树形结构打印2叉树到文件的功能
public:
void PrintTree();
private:
void print(TLeaf<K, T> *pLeaf, int count, char *pLastLine, char *pCurrLine, FILE *pLog);
};
#include "TTree.hpp"
#endif
TTree.hpp:
#ifndef _TTree_hpp_
#define _TTree_hpp_
template <class K, class T>
TTree<K, T>::TTree()
{
Init();
}
template <class K, class T>
TTree<K, T>::~TTree()
{
Init();
}
template <class K, class T>
void TTree<K, T>::Init(ContainerFlag dwLock)
{
m_pRoot = NULL;
m_dwLock = dwLock;
}
template <class K, class T>
bool TTree<K, T>::Insert(TLeaf<K, T> *pLeaf)
{
bool res = false;
if (NULL != pLeaf)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
if (this != pLeaf->m_pTree)
{
//搜索插入的位置,插入结点
if (NULL == m_pRoot)
{
m_pRoot = pLeaf;
pLeaf->m_pFather = NULL;
pLeaf->m_pLast = NULL;
pLeaf->m_pNext = NULL;
}
else
{
TLeaf<K, T> *pFind = m_pRoot;
while (true)
{
//2分查找,比pFind小查左子树,否则查右子树
if (GetRef(pLeaf->m_Value) > pFind->m_Key)
{
if (NULL != pFind->m_pRight)
{
pFind = pFind->m_pRight;
}
else
{
pFind->m_pRight = pLeaf;
pLeaf->m_pFather = pFind;
pLeaf->m_pNext = pFind->m_pNext;
if (NULL != pLeaf->m_pNext)
{
pLeaf->m_pNext->m_pLast = pLeaf;
}
pLeaf->m_pLast = pFind;
pFind->m_pNext = pLeaf;
break;
}
}
else
{
if (NULL != pFind->m_pLeft)
{
pFind = pFind->m_pLeft;
}
else
{
//找到合适的位置,接入pLeaf
pFind->m_pLeft = pLeaf;
pLeaf->m_pFather = pFind;
pLeaf->m_pLast = pFind->m_pLast;
if (NULL != pLeaf->m_pLast)
{
pLeaf->m_pLast->m_pNext = pLeaf;
}
pLeaf->m_pNext = pFind;
pFind->m_pLast = pLeaf;
break;
}
}
}
}
pLeaf->m_pLeft = NULL;
pLeaf->m_pRight = NULL;
pLeaf->m_wHeight = 0;
pLeaf->m_sBF = 0;
pLeaf->m_pTree = this;
//从该插入结点的父结点开始向根遍历,逐个平衡子树
AVLTree(pLeaf->m_pFather);
m_dwLen++;
res = true;
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
}
return res;
}
template <class K, class T>
TLeaf<K, T> *TTree<K, T>::Remove(K &key)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
TLeaf<K, T> *pLeaf = Find(key);
if (Remove(pLeaf))
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pLeaf;
}
else
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return NULL;
}
}
template <class K, class T>
TLeaf<K, T> *TTree<K, T>::RemoveHead()
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
TLeaf<K, T> *pLeaf = m_pRoot;
if (Remove(pLeaf))
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pLeaf;
}
else
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return NULL;
}
}
template <class K, class T>
bool TTree<K, T>::Remove(TLeaf<K, T> *pLeaf)
{
bool res = false;
if (NULL != pLeaf)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
if (this == pLeaf->m_pTree)
{
ResetNext(&(pLeaf->m_Value));
if (NULL == pLeaf->m_pLeft && NULL == pLeaf->m_pRight)
{
//该结点是叶子结点,直接移除
TLeaf<K, T> *pFather = pLeaf->m_pFather;
if (NULL != pFather)
{
if (pFather->m_pLeft == pLeaf)
{
pFather->m_pLeft = NULL;
}
else//pFather->m_pRight == pLeaf
{
pFather->m_pRight = NULL;
}
//从pLeaf的父结点开始,向根结点方向重新平衡各级子树
AVLTree(pFather);
}
else
{
//没有父结点的叶子结点,即单独的根结点
m_pRoot = NULL;
}
}
else if (NULL != pLeaf->m_pLeft)
{
//存在左子结点的情况下,与m_pLast交换
//存在左子结点的情况下,必定存在m_pLast,否则表示树结构发生错误
TLeaf<K, T> *pLast = pLeaf->m_pLast;
if (pLast == pLeaf->m_pLeft)
{
//pLeaf与pLast是父子结点
//将pLast交换到pLeaf的位置上:
//重新赋值pLast的m_pFather
pLast->m_pFather = pLeaf->m_pFather;
if (NULL != pLast->m_pFather)
{
if (pLast->m_pFather->m_pLeft == pLeaf)
{
pLast->m_pFather->m_pLeft = pLast;
}
else//pLast->m_pFather->m_pRight == pLeaf
{
pLast->m_pFather->m_pRight = pLast;
}
}
else
{
m_pRoot = pLast;
}
//重新赋值pLast的m_pRight
//由于pLast是比pLeaf小的最大结点,则pLast必定不存在m_pRight,否则表示树结构发生错误
//因此可以对pLast的m_pRight直接赋值为pLeaf的m_pRight,即将pLast直接上移一层
pLast->m_pRight = pLeaf->m_pRight;
if (NULL != pLast->m_pRight)
{
pLast->m_pRight->m_pFather = pLast;
}
//由于pLast的右结点发生变化,因此从pLast开始,向根结点方向重新平衡各级子树
AVLTree(pLast);
}
else
{
//pLeaf与pLast非父子结点的情况下,进行结点交换
//需要平衡的起始根结点为结点交换前pLast的m_pFather,需要在此时记录
//之后pLast的m_pFather会发生变化
TLeaf<K, T> *pLastFather = pLast->m_pFather;
//修改交换前pLast处的树结点关系:
//由于pLast是比pLeaf小的最大结点,则pLast必定不存在m_pRight,否则表示树结构发生错误
//因此可以将pLast的m_pLeft直接接到pLastFather的m_pRight上,即将pLast的左结点上移一层
pLastFather->m_pRight = pLast->m_pLeft;
if (NULL != pLast->m_pLeft)
{
pLast->m_pLeft->m_pFather = pLast->m_pFather;
}
//将pLast交换到pLeaf的位置上:
//重新赋值pLast的m_pFather
pLast->m_pFather = pLeaf->m_pFather;
if (NULL != pLast->m_pFather)
{
if (pLast->m_pFather->m_pLeft == pLeaf)
{
pLast->m_pFather->m_pLeft = pLast;
}
else//pLast->m_pFather->m_pRight == pLeaf
{
pLast->m_pFather->m_pRight = pLast;
}
}
else
{
m_pRoot = pLast;
}
//重新赋值pLast的m_pLeft
//pLeaf->m_pLeft != NULL,所以直接复制
pLast->m_pLeft = pLeaf->m_pLeft;
pLast->m_pLeft->m_pFather = pLast;
//重新赋值pLast的m_pRight
pLast->m_pRight = pLeaf->m_pRight;
if (NULL != pLast->m_pRight)
{
pLast->m_pRight->m_pFather = pLast;
}
//从pLast被交换前的m_pFather位置开始,向根结点方向重新平衡各级子树
AVLTree(pLastFather);
}
}
else//NULL != pLeaf->m_pRight
{
TLeaf<K, T> *pNext = pLeaf->m_pNext;
if (pNext == pLeaf->m_pRight)
{
//pLeaf与pNext是父子结点
//将pNext交换到pLeaf的位置上:
//重新赋值pNext的m_pFather
pNext->m_pFather = pLeaf->m_pFather;
if (NULL != pNext->m_pFather)
{
if (pNext->m_pFather->m_pLeft == pLeaf)
{
pNext->m_pFather->m_pLeft = pNext;
}
else//pNext->m_pFather->m_pRight == pLeaf
{
pNext->m_pFather->m_pRight = pNext;
}
}
else
{
m_pRoot = pNext;
}
//由于此时pLeaf的m_pLeft为空(不为空的情况会在else if (NULL != pLeaf->m_pLeft)处理)
//且pNext的m_pLeft也为空,因为pNext是比pLeaf大的最小结点
//不需要再赋值
//pNext->m_pLeft = NULL;
//由于pNext的左右结点未发生变化,因此从pNext的m_pFather开始,向根结点方向重新平衡各级子树
AVLTree(pNext->m_pFather);
}
else
{
//若pLeaf与pNext非父子结点
//当pLeaf不存在左结点,且存在右结点的情况下
//若pLeaf的右结点还有子结点
//则pLeaf这棵子树不是一颗AVL树
//因此pLeaf与pNext非父子结点的情况不存在
}
}
//重新赋值前后结点
if (NULL != pLeaf->m_pLast)
{
pLeaf->m_pLast->m_pNext = pLeaf->m_pNext;
}
if (NULL != pLeaf->m_pNext)
{
pLeaf->m_pNext->m_pLast = pLeaf->m_pLast;
}
pLeaf->Init();
m_dwLen--;
res = true;
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
}
return res;
}
template <class K, class T>
TLeaf<K, T> *TTree<K, T>::Find(K &key)
{
TLeaf<K, T> *pFind = NULL;
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
pFind = m_pRoot;
while (NULL != pFind)
{
if (GetRef(pFind->m_Value) == key)
{
break;
}
else if (GetRef(pFind->m_Value) > key)
{
pFind = pFind->m_pLeft;
}
else
{
pFind = pFind->m_pRight;
}
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pFind;
}
template <class K, class T>
T *TTree<K, T>::GetHead()
{
T *pRes = NULL;
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
TLeaf<K, T> *pHead = m_pRoot;
while (NULL != pHead)
{
if (NULL == pHead->m_pLeft)
{
pRes = &(pHead->m_Value);
break;
}
else
{
pHead = pHead->m_pLeft;
}
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
return pRes;
}
template <class K, class T>
T *TTree<K, T>::GetNext(T *curr)
{
T *pRes = NULL;
if (NULL != curr)
{
if (enum_EnableLock == m_dwLock)
{
m_csLock.Lock();
}
TLeaf<K, T> *pCurrLinker = (TLeaf<K, T> *)GetNode(curr);
if (this == pCurrLinker->m_pTree)
{
if (NULL != pCurrLinker->m_pNext)
{
pRes = &(pCurrLinker->m_pNext->m_Value);
}
}
if (enum_EnableLock == m_dwLock)
{
m_csLock.UnLock();
}
}
return pRes;
}
template <class K, class T>
void *TTree<K, T>::GetNode(T *curr)
{
TLeaf<K, T> *pRes = NULL;
if (NULL != curr)
{
pRes = ContainerOf(curr, TLeaf<K TEMPLATE_COMMA T>, m_Value);
}
return pRes;
}
template <class K, class T>
void TTree<K, T>::AVLTree(TLeaf<K, T> *pLeaf)
{
TLeaf<K, T> *pTemp = pLeaf;
while (NULL != pTemp)
{
BF(pTemp);
if (2 == pTemp->m_sBF || -2 == pTemp->m_sBF)
{
AVL(pTemp);
}
else
{
H(pTemp);
}
pTemp = pTemp->m_pFather;
}
}
template <class K, class T>
void TTree<K, T>::AVL(TLeaf<K, T> *pLeaf)
{
if (-2 == pLeaf->m_sBF)
{
if(1 == pLeaf->m_pRight->m_sBF)
{
RL(pLeaf);
}
else//-1 == pLeaf->m_pRight->m_sBF || 0 == pLeaf->m_pRight->m_sBF
{
L(pLeaf);
}
}
else//2 == pLeaf->m_sBF
{
if (-1 == pLeaf->m_pLeft->m_sBF)
{
LR(pLeaf);
}
else//1 == pLeaf->m_pLeft->m_sBF || 0 == pLeaf->m_pLeft->m_sBF
{
R(pLeaf);
}
}
}
template <class K, class T>
void TTree<K, T>::L(TLeaf<K, T> *pLeaf)
{
TLeaf<K, T> *pFather = pLeaf->m_pFather;
TLeaf<K, T> *pRightChild = pLeaf->m_pRight;
pLeaf->m_pRight = pRightChild->m_pLeft;
if (NULL != pRightChild->m_pLeft)
{
pLeaf->m_pRight->m_pFather = pLeaf;
}
pRightChild->m_pLeft = pLeaf;
pLeaf->m_pFather = pRightChild;
pRightChild->m_pFather = pFather;
if (NULL != pFather)
{
if (pFather->m_pLeft == pLeaf)
{
pFather->m_pLeft = pRightChild;
}
else
{
pFather->m_pRight = pRightChild;
}
}
else
{
m_pRoot = pRightChild;
}
H(pLeaf);
BF(pLeaf);
H(pRightChild);
BF(pRightChild);
}
template <class K, class T>
void TTree<K, T>::LR(TLeaf<K, T> *pLeaf)
{
TLeaf<K, T> *pFather = pLeaf->m_pFather;
TLeaf<K, T> *pLChild = pLeaf->m_pLeft;
TLeaf<K, T> *pLRChild = pLChild->m_pRight;
pLeaf->m_pLeft = pLRChild->m_pRight;
if (NULL != pLeaf->m_pLeft)
{
pLeaf->m_pLeft->m_pFather = pLeaf;
}
pLeaf->m_pFather = pLRChild;
pLChild->m_pRight = pLRChild->m_pLeft;
if (NULL != pLChild->m_pRight)
{
pLChild->m_pRight->m_pFather = pLChild;
}
pLChild->m_pFather = pLRChild;
pLRChild->m_pLeft = pLChild;
pLRChild->m_pRight = pLeaf;
pLRChild->m_pFather = pFather;
if (NULL != pFather)
{
if (pFather->m_pLeft == pLeaf)
{
pFather->m_pLeft = pLRChild;
}
else
{
pFather->m_pRight = pLRChild;
}
}
else
{
m_pRoot = pLRChild;
}
H(pLeaf);
BF(pLeaf);
H(pLChild);
BF(pLChild);
H(pLRChild);
BF(pLRChild);
}
template <class K, class T>
void TTree<K, T>::R(TLeaf<K, T> *pLeaf)
{
TLeaf<K, T> *pFather = pLeaf->m_pFather;
TLeaf<K, T> *pLeftChild = pLeaf->m_pLeft;
pLeaf->m_pLeft = pLeftChild->m_pRight;
if (NULL != pLeftChild->m_pRight)
{
pLeaf->m_pLeft->m_pFather = pLeaf;
}
pLeftChild->m_pRight = pLeaf;
pLeaf->m_pFather = pLeftChild;
pLeftChild->m_pFather = pFather;
if (NULL != pFather)
{
if (pFather->m_pLeft == pLeaf)
{
pFather->m_pLeft = pLeftChild;
}
else
{
pFather->m_pRight = pLeftChild;
}
}
else
{
m_pRoot = pLeftChild;
}
H(pLeaf);
BF(pLeaf);
H(pLeftChild);
BF(pLeftChild);
}
template <class K, class T>
void TTree<K, T>::RL(TLeaf<K, T> *pLeaf)
{
TLeaf<K, T> *pFather = pLeaf->m_pFather;
TLeaf<K, T> *pRChild = pLeaf->m_pRight;
TLeaf<K, T> *pRLChild = pRChild->m_pLeft;
pLeaf->m_pRight = pRLChild->m_pLeft;
if (NULL != pLeaf->m_pRight)
{
pLeaf->m_pRight->m_pFather = pLeaf;
}
pLeaf->m_pFather = pRLChild;
pRChild->m_pLeft = pRLChild->m_pRight;
if (NULL != pRChild->m_pLeft)
{
pRChild->m_pLeft->m_pFather = pRChild;
}
pRChild->m_pFather = pRLChild;
pRLChild->m_pLeft = pLeaf;
pRLChild->m_pRight = pRChild;
pRLChild->m_pFather = pFather;
if (NULL != pFather)
{
if (pFather->m_pLeft == pLeaf)
{
pFather->m_pLeft = pRLChild;
}
else
{
pFather->m_pRight = pRLChild;
}
}
else
{
m_pRoot = pRLChild;
}
H(pLeaf);
BF(pLeaf);
H(pRChild);
BF(pRChild);
H(pRLChild);
BF(pRLChild);
}
template <class K, class T>
void TTree<K, T>::H(TLeaf<K, T> *pLeaf)
{
int lh = (NULL == pLeaf->m_pLeft) ? -1 : pLeaf->m_pLeft->m_wHeight;
int rh = (NULL == pLeaf->m_pRight) ? -1 : pLeaf->m_pRight->m_wHeight;
if (lh > rh)
{
pLeaf->m_wHeight = lh + 1;
}
else
{
pLeaf->m_wHeight = rh + 1;
}
}
template <class K, class T>
void TTree<K, T>::BF(TLeaf<K, T> *pLeaf)
{
int lh = (NULL == pLeaf->m_pLeft) ? -1 : pLeaf->m_pLeft->m_wHeight;
int rh = (NULL == pLeaf->m_pRight) ? -1 : pLeaf->m_pRight->m_wHeight;
pLeaf->m_sBF = lh - rh;
}
#define TREE_PRINT_BUFF_LEN 2000
template <class K, class T>
void TTree<K, T>::PrintTree()
{
char *pLastLine = new char[TREE_PRINT_BUFF_LEN];
char *pCurrLine = new char[TREE_PRINT_BUFF_LEN];
if (NULL == pLastLine || NULL == pCurrLine)
{
if (NULL != pLastLine)
{
delete[] pLastLine;
pLastLine = NULL;
}
if (NULL != pCurrLine)
{
delete[] pCurrLine;
pCurrLine = NULL;
}
return;
}
FILE *pLog = NULL;
fopen_s(&pLog, "tree.log", "a+");
if (NULL != pLog)
{
memset(pLastLine, 0x00, TREE_PRINT_BUFF_LEN);
memset(pCurrLine, 0x00, TREE_PRINT_BUFF_LEN);
fprintf(pLog,"\n");
print(m_pRoot, 0, pLastLine, pCurrLine, pLog);
fclose(pLog);
pLog = NULL;
}
if (NULL != pLastLine)
{
delete[] pLastLine;
pLastLine = NULL;
}
if (NULL != pCurrLine)
{
delete[] pCurrLine;
pCurrLine = NULL;
}
}
template <class K, class T>
void TTree<K, T>::print(TLeaf<K, T> *pLeaf, int count, char *pLastLine, char *pCurrLine, FILE *pLog)
{
static int nNodeInfoLen = 16; //此值关系到下面格式控制输出pLeaf->m_Value时
//所需输出的字符串总长度
//格式长度有变时 需要修改该值
//另外格式长度应为固定值
//否则输出的内容无法对齐
if (NULL != pLeaf)
{
char temp[100];
sprintf_s(temp, 100, "%16x", pLeaf->m_Value);
strcat_s(pCurrLine, TREE_PRINT_BUFF_LEN, temp);
strcat_s(pCurrLine, TREE_PRINT_BUFF_LEN, "┬");
if (NULL != pLeaf->m_pLeft)
{
print(pLeaf->m_pLeft, count + nNodeInfoLen + 2, pLastLine, pCurrLine, pLog);
}
else
{
strcat_s(pCurrLine, TREE_PRINT_BUFF_LEN, "[N]");
fprintf(pLog,"%s\n", pCurrLine);
strcpy_s(pLastLine, TREE_PRINT_BUFF_LEN, pCurrLine);
pCurrLine[0] = '\0';
}
for (int i = 0; i < count; i = i + nNodeInfoLen + 2)
{
for (int j = 0; j < nNodeInfoLen; j++)
{
strcat_s(pCurrLine, TREE_PRINT_BUFF_LEN, " ");
}
if (pLastLine[i+nNodeInfoLen] == ' ' || (pLastLine[i+nNodeInfoLen] == -87 && pLastLine[i+nNodeInfoLen+1] == -72))
{
//上一行的该位置是 空格 或者是“└”
strcat_s(pCurrLine, TREE_PRINT_BUFF_LEN, " ");
}
else
{
strcat_s(pCurrLine, TREE_PRINT_BUFF_LEN, "│");
}
}
for (int j = 0; j < nNodeInfoLen; j++)
{
strcat_s(pCurrLine, TREE_PRINT_BUFF_LEN, " ");
}
strcat_s(pCurrLine, TREE_PRINT_BUFF_LEN, "└");
if (NULL != pLeaf->m_pRight)
{
print(pLeaf->m_pRight, count + nNodeInfoLen + 2, pLastLine, pCurrLine, pLog);
}
else
{
strcat_s(pCurrLine, TREE_PRINT_BUFF_LEN, "[N]");
fprintf(pLog,"%s\n", pCurrLine);
strcpy_s(pLastLine, TREE_PRINT_BUFF_LEN, pCurrLine);
pCurrLine[0] = '\0';
}
}
}
#endif