给大家提供一个简单的使用模板的数据结构库[原创]
附件就是该库的压缩包。
在rdt目录下,有一个interface.h,使用时#include此文件即可。
此库全部都是.h头文件形式,所有的类在一个名为rdt的命名空间里。(请使用对模板支持较好的编译器来编译,gcc或者其他,如果是微软的C++编译器,至少VC2005,VC6对标准支持非常差)
一.普通操作
示例(节点):
- C/C++ code
rdt::SuperNode<int> node, left, right; node.Create(2); // 此句表示创建拥有两个边的节点 left.Create(0); right.Create(0); // 没有边的节点(叶节点) // 关联节点 node.Link(-1, &left); node.Link(1, &right); // -1表示左边,1表示右边, 这是2个节点的情况下 // 边 node.Edge(-1); // 返回left的指针 node.Edge(1); 返回right的指针 // SuperNode的边有左和右两类,左边的是负右边的是正 // 如果是10个元素,那么边的表示就是:左:-1~-5 右:1~5,如果元素数量是奇数,可能有问题(未验证) left.Release(); right.Release(); node.Release(); // 会自动Release,不过如果node是SuperNode的指针的话,需要自行Release
示例(链表):
- C/C++ code
rdt::SuperList<int> list; list.Create(); // 创建一个变长链表,默认 list.Plus(2); // 加入一个元素 list.Plus(3); list.Minus(0); // 减去第一个元素 list.Release();
二.值操作
- C/C++ code
// 值的操作通过Value函数进行 // 单个节点的数据结构,是TYPE Value()和Value(TYPE value) // 多个节点的数据结构,是TYPE Value(long index)和bool Value(long index, TYPE new_value) // 一个是返回值,一个是修改值 // 每个rdt的数据结构类都有这两个函数。 rdt::SuperNode<int> node; node.Create(); // 当不指定边数时,默认创建2个边的节点 node.Value(32); printf("%d\n", node.Value()); // 32 node.Release(); rdt::SuperList<int> list; list.Create(); list.Plus(2); list.Plus(3); ;list.Plus(4); list.Value(2); // 返回4 list.Value(2, 5); // 第3个元素修改为5 list.Release(); // 除了传值之外,还提供传指针 // rdt的数据结构类都提供Ptr函数,和Value函数系列完全一致,Ptr是指针版的Value,主要是避免节点为大型结构的额外复制 // 还有Count函数是返回元素的个数三.加载和存储
- C/C++ code
// rdt提供了数据结构的加载和存储功能,每个数据结构类都能从内存加载/存储到内存 // 每个数据结构类都提供Load、Save、StoreBytes三个函数 // StoreBytes返回存储n个元素需要的字节数 // Load(void *ptr, long count)提供加载功能,将ptr中的数据恢复成数据结构 // Save(void *ptr, long count)提供存储功能,将数据结构存储到ptr中,count是读取/写入的元素个数 // rdt::SuperList<int> list; ... long size = list.StoreBytes(list.Count()); // 存储全部元素需要的字节数 char *data = new char[size]; list.Save(data, list.Count()); // 存储所有元素 ... // 如果要加载已存储的数据结构,如果已经Create,需要先Release long count = list.Count(); // 在实际运用中,最多的就是文件的读写,元素个数的信息需要自行保存 list.Release(); // 或者声明另一个对象 list.Load(data, count); // 加载,恢复整个数据结构 ... list.Release();
四.SuperBinary介绍
- C/C++ code
// 在以前,我都是直接对文件进行读写,对于简单文件,很直接。但是对于格式复杂的文件,不如将内容 // 加载到内存,然后在内存中解析。 // 我用使用内存解析的话,会出现这样的代码: bool _parse_fmt(char **pp) { if (!this->_is_chunk_id(pp, "fmt ")) return false; int fmtSize = *(int *)*pp; if ((16 != fmtSize) && (18 != fmtSize)) return false; *pp+=4; // format tag, normal 0x0001 *pp+=2; // channel m_channels = (long)*(short *)*pp; *pp+=2; // sample rate m_sample_rate = (long)*(int *)*pp; *pp+=4; // avg second byte m_avg_sec_byte = (long)*(int *)*pp; *pp+=4; // block align *pp+=2; // bit per sample m_bit_sample_rate = (long)*(short *)*pp; *pp+=2; // tag if (18 == fmtSize) *pp+=2; return true; } // 这是一段解析WAV文件的代码,这段代码的问题是一旦指针越界、非法操作等,都很难察觉,一旦出错 // 程序就会崩溃,如果在所有的函数中指定长度等信息,又会十分臃肿。最后可能还不如直接文件读写。 // 所以我写了一个可以说是专用于内存解析的SuperBinary类 rdt::SuperBinary<char> stream; // stream.Create(ptr, 1000, _STREAM_READ); // 这是指定一个指针的创建方式,ptr是数据区的指针,1000是大小,_STREAM_READ表示只允许读操作 // stream.Create(1000); // 这是创建一个由SuperBinary管理的数据区,SuperBinary会自动创建一个大小为1000的内存 steam.Create(1000); // 这种创建方式的权限是_STREAM_RW,即读写都可以。 char *hello = "hello SuperBinary!"; stream.Write(hello, strlen(hello)+1); 向流中写入数据,和C标准库的文件操作一样 stream.PutA('N'); // 写入一个字符 int *nums = 2; stream.Write<int>(nums); // 写入一个数值:2 stream.Write<int>(2) // 与上一句的处理方式不同 // Read系列和Write系列一样 // SuperBinary还提供Seek、Eof、Cursor等函数 // 其中,Seek=fseek,Cursor=ftell,Seek的使用完全和fseek一样 // 还有Begin、End函数,表示开始的位置和结束的位置 // Size函数返回创建时指定的大小,Ptr函数返回流操作的数据区指针 // stream.Seek(-3, _SEEK_CUR); // 现在位置在'N'这里 stream.Release();
其他接口
- C/C++ code
// rdt的每个数据结构类都提供了Use()和Wait()函数,Use()返回是否正在使用,Wait()返回是否等待使用 // 所有的数据结构类都基于SuperDT基类,扩充非常容易
此库不包含任何与平台有关的代码,windows、linux、unix都可以用
我在bbs.pfan.cn也发表了一篇同样的帖子
下载地址:http://www.vdisk.cn/down/index/10173026
[解决办法]
不错,支持下。