初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
实现数组肯定不是我们的目标,大部分情况下,我们用的是set和map(从set到map很简单,“set+数组”就可以实现map),核心问题是实现set。
目录
一、几个不核心的类
二、树节点结构
三、树节点的HANDLE
大部分算法充斥了动态申请和释放,而STL的分配器比较难懂,也没研究出使用方法,因此无法直接使用STL的容器,所以要重新手写。(STL博大精深,我感觉是我还没学好)
还有一个原因是一些早期编译器对STL的标准化支持不完善。
一、几个不核心的类
单字节标志,用于记录删除、修改状态:
//单字节标志组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;}};
遍历标志位的接口:
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~7bool GetUserFlag(int flag)const{return uflag->getflag(flag);}//设置一个节点的标志(即使节点已经删除,标志位仍然可能有用)flag 0~7bool SetUserFlag(int flag, bool value)const{return uflag->setflag(flag, value);}public:virtual bool doOneData(long handle, T_DATA const * pData) = 0;};
分多个子树的接口:
//set接口,用于分为N个子树的settemplate<typename T_DATA>class ISet{public://IListSet遍历接口struct ISetForEach{long iSet;//非group对象为-1ISetForEach() :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;}};
二、树节点结构
树基于之前介绍的数组,树节点结构对应数组的模板参数。
这是纯的结构,可供外部使用:
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);}};
这是带有一些操作方法的结构,只能用在树模板内部:
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
这个句柄当作指针时返回的是用户的数据(也就是不包含树结构本身):
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();}};
这个树的设计不是很理想,但是因为其他数据结构都是基于这个的,所以也不容易改。(屎山开始了?)
什么是理想的设计?自然而然就是最好的设计,不用刻意去理解。
(待续)