主题:[原创]给大家提供一个简单的使用模板的数据结构库
附件就是该库的压缩包。
在rdt目录下,有一个interface.h,使用时#include此文件即可。
此库全部都是.h头文件形式,所有的类在一个名为rdt的命名空间里。(请使用对模板支持较好的编译器来编译,gcc或者其他,如果是微软的C++编译器,至少VC2005,VC6对标准支持非常差)
一.普通操作
示例(节点):
[code=c]
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
[/code]
示例(链表):
[code=c]
rdt::SuperList<int> list;
list.Create(); // 创建一个变长链表,默认
list.Plus(2); // 加入一个元素
list.Plus(3);
list.Minus(0); // 减去第一个元素
list.Release();
[/code]
二.值操作
[code=c]
// 值的操作通过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函数是返回元素的个数
[/code]
三.加载和存储
[code=c]
// 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();
[/code]
四.SuperBinary介绍
[code=c]
// 在以前,我都是直接对文件进行读写,对于简单文件,很直接。但是对于格式复杂的文件,不如将内容
// 加载到内存,然后在内存中解析。
// 我用使用内存解析的话,会出现这样的代码:
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();
[/code]
其他接口
[code]
// rdt的每个数据结构类都提供了Use()和Wait()函数,Use()返回是否正在使用,Wait()返回是否等待使用
// 所有的数据结构类都基于SuperDT基类,扩充非常容易
[/code]
在rdt目录下,有一个interface.h,使用时#include此文件即可。
此库全部都是.h头文件形式,所有的类在一个名为rdt的命名空间里。(请使用对模板支持较好的编译器来编译,gcc或者其他,如果是微软的C++编译器,至少VC2005,VC6对标准支持非常差)
一.普通操作
示例(节点):
[code=c]
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
[/code]
示例(链表):
[code=c]
rdt::SuperList<int> list;
list.Create(); // 创建一个变长链表,默认
list.Plus(2); // 加入一个元素
list.Plus(3);
list.Minus(0); // 减去第一个元素
list.Release();
[/code]
二.值操作
[code=c]
// 值的操作通过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函数是返回元素的个数
[/code]
三.加载和存储
[code=c]
// 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();
[/code]
四.SuperBinary介绍
[code=c]
// 在以前,我都是直接对文件进行读写,对于简单文件,很直接。但是对于格式复杂的文件,不如将内容
// 加载到内存,然后在内存中解析。
// 我用使用内存解析的话,会出现这样的代码:
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();
[/code]
其他接口
[code]
// rdt的每个数据结构类都提供了Use()和Wait()函数,Use()返回是否正在使用,Wait()返回是否等待使用
// 所有的数据结构类都基于SuperDT基类,扩充非常容易
[/code]