我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
实现数组肯定不是我们的目标,大部分情况下,我们用的是set和map(从set到map很简单,"set+数组"就可以实现map),核心问题是实现set。
目录
大部分算法充斥了动态申请和释放,而STL的分配器比较难懂,也没研究出使用方法,因此无法直接使用STL的容器,所以要重新手写。(STL博大精深,我感觉是我还没学好)
还有一个原因是一些早期编译器对STL的标准化支持不完善。
一、几个不核心的类
单字节标志,用于记录删除、修改状态:
cpp
//单字节标志组
struct T_FLAG
{
unsigned char _flag;
T_FLAG() :_flag(0) {}
bool getflag(int flag)const
{
if (flag < 0 || flag >= 8)
{
thelog << "无效的位 " << flag << ende;
return false;
}
return _flag & (1 << flag);
}
bool setflag(int flag, bool value)
{
if (flag < 0 || flag >= 8)
{
thelog << "无效的位 " << flag << ende;
return false;
}
_flag &= (0 << flag);//清位
_flag |= ((value ? 1 : 0) << flag);
return true;
}
};
遍历标志位的接口:
cpp
template<typename T_DATA>
class IForEachFlag
{
protected:
bool isDeleted;//是否是删除的,这个不是标志,表明数据是否已经删除
T_FLAG * flag;//内置标志 位0 添加 位1修改(包括因为不存在而添加) 位2 删除
T_FLAG * uflag;//用户标志
public:
void set(bool d, T_FLAG * f, T_FLAG * uf)
{
isDeleted = d;
flag = f;
uflag = uf;
}
protected:
//检查一个节点的标志(即使节点已经删除,标志位仍然可能有用)
bool GetFlagInsert()const
{
return flag->getflag(0);
}
bool GetFlagUpdate()const
{
return flag->getflag(1);
}
bool GetFlagDelete()const
{
return flag->getflag(2);
}
//设置一个节点的标志(即使节点已经删除,标志位仍然可能有用)
bool ClearFlagInsert()const
{
return flag->setflag(0, false);
}
bool ClearFlagUpdate()const
{
return flag->setflag(1, false);
}
bool ClearFlagDelete()const
{
return flag->setflag(2, false);
}
bool SetFlagInsert()const
{
return flag->setflag(0, true);
}
bool SetFlagUpdate()const
{
return flag->setflag(1, true);
}
bool SetFlagDelete()const
{
return flag->setflag(2, true);
}
//检查一个节点的标志(即使节点已经删除,标志位仍然可能有用)flag 0~7
bool GetUserFlag(int flag)const
{
return uflag->getflag(flag);
}
//设置一个节点的标志(即使节点已经删除,标志位仍然可能有用)flag 0~7
bool SetUserFlag(int flag, bool value)const
{
return uflag->setflag(flag, value);
}
public:
virtual bool doOneData(long handle, T_DATA const * pData) = 0;
};
分多个子树的接口:
cpp
//set接口,用于分为N个子树的set
template<typename T_DATA>
class ISet
{
public:
//IListSet遍历接口
struct ISetForEach
{
long iSet;//非group对象为-1
ISetForEach() :iSet(-1) {}
virtual bool doOneData(long handle, T_DATA const * pData) = 0;
};
public:
virtual T_DATA * isetGet(long h)const
{
thelog << " ISet::isetGet 未实现" << ende;
return NULL;
}
virtual long isetMoveNext(long & h)const
{
thelog << " ISet::isetMoveNext 未实现" << ende;
return -1;
}
virtual long isetBegin()const
{
thelog << " ISet::isetBegin 未实现" << ende;
return -1;
}
virtual pair<long, bool> isetInsert(T_DATA const & value)
{
pair<long, bool> tmp;
tmp.first = -1;
tmp.second = false;
thelog << " ISet::isetInsert 未实现" << ende;
return tmp;
}
virtual long isetFind(T_DATA const & value)const
{
thelog << " ISet::isetFind 未实现" << ende;
return -1;
}
virtual long isetFindLowerBound(T_DATA const & value, bool(*less)(T_DATA const &, T_DATA const &))const
{
thelog << " ISet::isetFindLowerBound 未实现" << ende;
return -1;
}
virtual bool isetErase(long h)
{
thelog << " ISet::isetErase 未实现" << ende;
return -1;
}
virtual bool isetForEachShuffle(long handle, ISetForEach * pForEach)const
{
thelog << " IListSet::isetForEachShuffle 未实现" << ende;
return true;
}
};
二、树节点结构
树基于之前介绍的数组,树节点结构对应数组的模板参数。
这是纯的结构,可供外部使用:
cpp
template<typename T_DATA >
struct T_TREE_NODE_STRUCT
{
T_SHM_SIZE hParent;//-1:无,根节点;0-N,子节点,或指向下个空闲地址
T_SHM_SIZE hLeft;//-1表示无子节点
T_SHM_SIZE hRight;//-1表示无子节点
//平衡因子
signed char bf;//balance_factor 0;平衡 1: 左子节点高 -1:右子节点高
//删除标志
signed char deleted;//0:有效,1:删除
//额外标志
T_FLAG flag;//内置标志 位0 添加 位1修改(包括因为不存在而添加) 位2 删除
T_FLAG uflag;//用户标志
//用户数据结构
T_DATA data;
T_TREE_NODE_STRUCT() :hParent(-1), hLeft(-1), hRight(-1), bf(EH), deleted(0) {}
T_TREE_NODE_STRUCT(T_SHM_SIZE parent, T_DATA const & tmp) :hParent(parent), hLeft(-1), hRight(-1), bf(EH), deleted(0), data(tmp) {}
string & toString(string & str, void * = NULL)const
{
char buf[2048];
string tmp;
sprintf(buf, "%8ld %8ld %8ld %1d %1d %3d %3d: %s", hParent, hLeft, hRight, bf, deleted
, (unsigned int)flag._flag, (unsigned int)uflag._flag, data.toString(tmp).c_str());
return str = buf;
}
static bool AddTableColumns(CHtmlDoc::CHtmlTable2 & table)
{
table.AddCol("P", CHtmlDoc::CHtmlDoc_DATACLASS_RIGHT);
table.AddCol("L", CHtmlDoc::CHtmlDoc_DATACLASS_RIGHT);
table.AddCol("R", CHtmlDoc::CHtmlDoc_DATACLASS_RIGHT);
table.AddCol("b", CHtmlDoc::CHtmlDoc_DATACLASS_RIGHT);
table.AddCol("d", CHtmlDoc::CHtmlDoc_DATACLASS_RIGHT);
table.AddCol("F", CHtmlDoc::CHtmlDoc_DATACLASS_RIGHT);
table.AddCol("uF", CHtmlDoc::CHtmlDoc_DATACLASS_RIGHT);
table.AddCol("|");
return T_DATA::AddTableColumns(table);
}
bool AddTableData(CHtmlDoc::CHtmlTable2 & table)const
{
table.AddData(hParent);
table.AddData(hLeft);
table.AddData(hRight);
table.AddData(bf);
table.AddData(deleted);
table.AddData((unsigned int)flag._flag);
table.AddData((unsigned int)uflag._flag);
table.AddData("|");
return data.AddTableData(table);
}
};
这是带有一些操作方法的结构,只能用在树模板内部:
cpp
template<typename T_DATA, int PI_N, typename T_HANDLE, typename T_COMP >
struct T_TREE_NODE : public T_TREE_NODE_STRUCT<T_DATA >
{
using T_TREE_NODE_STRUCT<T_DATA >::data;
using T_TREE_NODE_STRUCT<T_DATA >::hLeft;
using T_TREE_NODE_STRUCT<T_DATA >::hRight;
using T_TREE_NODE_STRUCT<T_DATA >::hParent;
T_TREE_NODE() {}
T_TREE_NODE(T_SHM_SIZE parent, T_DATA const& tmp) :T_TREE_NODE_STRUCT<T_DATA >(parent, tmp) {}
bool operator < (T_TREE_NODE const & tmp)const
{
T_COMP comp;
return comp(data, tmp.data);
}
static T_TREE_NODE & at(T_SHM_SIZE n)
{
if (n < 0)
{
G_SET_ERROR(My_ERR_INVALID_HANDLE);
thelog << "at error " << n << ende;
}
T_HANDLE array_handle(n);
//char buf[256];
//sprintf(buf,"%ld %p",n,&*array_handle);
//theLog<<buf<<endi;
return *(T_TREE_NODE *)(void *)&*array_handle;
}
T_SHM_SIZE _me()const
{
return T_HANDLE::_me(this);
}
T_SHM_SIZE _begin()const
{
if (-1 == hLeft)return _me();
return at(hLeft)._begin();
}
T_SHM_SIZE _end()const
{
if (-1 == hRight)return _me();
return at(hRight)._end();
}
bool isRight()const
{
return -1 != hParent && _me() == at(hParent).hRight;
}
bool isLeft()const
{
return !isRight();
}
};
三、树节点的HANDLE
这个句柄当作指针时返回的是用户的数据(也就是不包含树结构本身):
cpp
template<typename T_DATA, int PI_N >
struct T_HANDLE_SET :public T_HANDLE_ARRAY<T_TREE_NODE_STRUCT<T_DATA >, PI_N >
{
typedef T_TREE_NODE_STRUCT<T_DATA > T;
typedef T_HANDLE_ARRAY<T, PI_N > T_PARENT;
using T_PARENT::handle;
T_HANDLE_SET(T_SHM_SIZE h = -1) :T_PARENT(h) {}
T_HANDLE_SET(T_HANDLE_SET const& tmp) :T_PARENT(tmp.handle) {}
using T_PARENT::iterator_category;
using T_PARENT::pointer;
using T_PARENT::element_type;
using T_PARENT::value_type;
using T_PARENT::difference_type;
using T_PARENT::offset_type;
using T_PARENT::reference;
bool operator<(T_HANDLE_SET const& tmp)const { return handle < tmp.handle; }
T_HANDLE_SET operator + (long n)const
{
T_HANDLE_SET tmp;
tmp.handle = handle + n;
return tmp;
}
T_HANDLE_SET operator - (long n)const
{
T_HANDLE_SET tmp;
tmp.handle = handle - n;
return tmp;
}
T_SHM_SIZE operator - (T_HANDLE_SET const& tmp)const { return handle - tmp.handle; }
T_HANDLE_SET& operator += (T_SHM_SIZE n) { handle += n; return *this; }
T_HANDLE_SET& operator ++ () { ++handle; return *this; }
T_HANDLE_SET& operator -- () { --handle; return *this; }
T_HANDLE_SET& operator = (T_HANDLE_SET const& tmp) { handle = tmp.handle; return *this; }
bool operator == (T_HANDLE_SET const& tmp)const { return handle == tmp.handle; }
bool operator != (T_HANDLE_SET const& tmp)const { return !((*this) == tmp); }
T& operator * ()const
{
return *operator ->();
}
T* operator -> ()const
{
return T_PARENT::operator->();
}
static T_SHM_SIZE _me(T const* p, bool not_throw = false)
{
return T_PARENT::_me(p, not_throw);
}
static void ShowVMapPrivateData()
{
return T_PARENT::ShowVMapPrivateData();
}
};
这个树的设计不是很理想,但是因为其他数据结构都是基于这个的,所以也不容易改。(屎山开始了?)
什么是理想的设计?自然而然就是最好的设计,不用刻意去理解。
(待续)