stdext Relation: 数据表(DataTable)

stdext Relation: 数据表(DataTable)

许式伟
2008-7-22

Relation容器简介

Relation是一个复杂容器。简单来说,它是一个数据表(DataTable)。它类似于数据库(Database)中的表,当然,是一个简化的表:简化在于没有复杂的SQL语句,只是支持基于关键字(索引)的select。

应用场景:如果你的数据有多列,并且需要相互查找(多对多关系),那么Relation容器非常适合。

著名的GLib(GNOME Library)有一个GRelation,和stdext Relation的功能类似。但stdext Relation的功能更加强大。这表现在:

  • stdext的Relation是真正的数据表(DataTable),可以创建任意多列的数据,而不只是2列。创建2列的表,可以使用stl的std::pair(当然也可以用boost::tuple)。创建超过2列的表,使用boost::tuple。
  • 可以为任意列创建索引,并且各列独立指定使用map(红黑树)还是hash map(哈希表)作为索引表是可能的。
  • 可以为若干列创建联合主键,使得这些列联合的数据不会重复。

Relation简单样例

下面是一个Relation的样例。为了简单,该例是2列的表,并且所有列都用hash map作为索引。这个样例可以在 stdext/examples/relation/Simplest.cpp 中找到。

typedef std::AutoFreeAlloc AllocT;
typedef std::pair<std::string, int> TupleT;
typedef std::Relation<TupleT, 3, 0, std::HashMapIndexing, AllocT> RelationT;
typedef RelationT::Indexing<0> Indexing0;
typedef RelationT::Indexing<1> Indexing1;

AllocT alloc;
RelationT rel(alloc);

rel.insert(TupleT("Mon", 1));
rel.insert(TupleT("Monday", 1));
rel.insert(TupleT("Tue", 2));
rel.insert(TupleT("Wed", 3));
rel.insert(TupleT("Wednesday", 3));
AssertExp(rel.size() == 5);

Indexing1::range rg = rel.select<1>(3);
AssertExp(std::distance(rg.first, rg.second) == 2);
for (Indexing1::iterator it = rg.first; it != rg.second; ++it) {
const TupleT& i = Indexing1::item(it);
AssertExp(i.first == "Wed" || i.first == "Wednesday");
AssertExp(i.second == 3);
}

Indexing0::range rg2 = rel.select<0>("Mon");
AssertExp(std::distance(rg2.first, rg2.second) == 1);
Indexing0::iterator it2 = rg2.first;
const TupleT& i2 = Indexing0::item(it2);
AssertExp(i2.first == "Mon" && i2.second == 1);

AssertExp(rel.count<1>(1) == 2);
AssertExp(rel.erase<1>(1) == 2);
AssertExp(rel.count<1>(1) == 0);
AssertExp(rel.size() == 3);

Indexing0::range rg3 = rel.select<0>("Mon");
AssertExp(std::distance(rg3.first, rg3.second) == 0);
AssertExp(rel.count<0>("Monday") == 0);

Relation 更多样例…

如果这不满足你的需求,我们还有一些更为复杂的样例(同样,这些样例在 stdext/examples/relation/Simplest.cpp 中可以找到):

testCustomIndexing

这个样例展示了如何定制索引。

// Field 0: rb-tree indexing
// Field 1..(N-1): hash-table indexing

即第0列使用rb-tree(红黑树),其他列用hash表做索引。

testTupleRelation

支持多列的样例(使用了boost::tuple)。

stdext Relation vs. GRelation(GLib)性能对比

测试程序: stdext/performance/relation/Performance.cpp

主要比较两个操作:插入(insert)与查找(select)。注:如果你取最新的代码,stdext Relation的表现应该会更好,这是因为我再次做了优化,但是没有更新这里的测试数据。

插入(insert)的对比结果

===== GRelation (insert) =====
---> Elapse 37163475 ticks (37.16 ms) (0.00 min) ...
---> Elapse 38908908 ticks (38.91 ms) (0.00 min) ...
---> Elapse 37951608 ticks (37.95 ms) (0.00 min) ...
---> Elapse 38112183 ticks (38.11 ms) (0.00 min) ...
---> Elapse 38991814 ticks (38.99 ms) (0.00 min) ...
---> Elapse 37209503 ticks (37.21 ms) (0.00 min) ...
---> Elapse 37091604 ticks (37.09 ms) (0.00 min) ...
---> Elapse 38056097 ticks (38.06 ms) (0.00 min) ...
---> Elapse 37491538 ticks (37.49 ms) (0.00 min) ...
---> Elapse 37197071 ticks (37.20 ms) (0.00 min) ...
---> Elapse 36716046 ticks (36.72 ms) (0.00 min) ...
---> Elapse 35923233 ticks (35.92 ms) (0.00 min) ...
---> Elapse 36989910 ticks (36.99 ms) (0.00 min) ...
---> Elapse 36041970 ticks (36.04 ms) (0.00 min) ...
---> Elapse 37710083 ticks (37.71 ms) (0.00 min) ...
---> Elapse 38065317 ticks (38.07 ms) (0.00 min) ...
Average: ---> Elapse 37476272 ticks (37.48 ms) (0.00 min) ...

===== Relation (insert) =====
---> Elapse 7990647 ticks (7.99 ms) (0.00 min) ...
---> Elapse 8297058 ticks (8.30 ms) (0.00 min) ...
---> Elapse 9548964 ticks (9.55 ms) (0.00 min) ...
---> Elapse 8238109 ticks (8.24 ms) (0.00 min) ...
---> Elapse 8142560 ticks (8.14 ms) (0.00 min) ...
---> Elapse 8000914 ticks (8.00 ms) (0.00 min) ...
---> Elapse 7674457 ticks (7.67 ms) (0.00 min) ...
---> Elapse 7784394 ticks (7.78 ms) (0.00 min) ...
---> Elapse 8068944 ticks (8.07 ms) (0.00 min) ...
---> Elapse 7860595 ticks (7.86 ms) (0.00 min) ...
---> Elapse 7785512 ticks (7.79 ms) (0.00 min) ...
---> Elapse 8525382 ticks (8.53 ms) (0.00 min) ...
---> Elapse 7681512 ticks (7.68 ms) (0.00 min) ...
---> Elapse 7877846 ticks (7.88 ms) (0.00 min) ...
---> Elapse 7896565 ticks (7.90 ms) (0.00 min) ...
---> Elapse 7597069 ticks (7.60 ms) (0.00 min) ...
Average: ---> Elapse 8060658 ticks (8.06 ms) (0.00 min) ...

查找(select)的对比结果

===== GRelation (select) =====
---> Elapse 18511577 ticks (18.51 ms) (0.00 min) ...
---> Elapse 15667689 ticks (15.67 ms) (0.00 min) ...
---> Elapse 16131391 ticks (16.13 ms) (0.00 min) ...
---> Elapse 15866818 ticks (15.87 ms) (0.00 min) ...
---> Elapse 15679213 ticks (15.68 ms) (0.00 min) ...
---> Elapse 16461061 ticks (16.46 ms) (0.00 min) ...
---> Elapse 15717209 ticks (15.72 ms) (0.00 min) ...
---> Elapse 16135303 ticks (16.14 ms) (0.00 min) ...
---> Elapse 15502853 ticks (15.50 ms) (0.00 min) ...
---> Elapse 16177000 ticks (16.18 ms) (0.00 min) ...
---> Elapse 15647992 ticks (15.65 ms) (0.00 min) ...
---> Elapse 15948956 ticks (15.95 ms) (0.00 min) ...
---> Elapse 15846702 ticks (15.85 ms) (0.00 min) ...
---> Elapse 15622359 ticks (15.62 ms) (0.00 min) ...
---> Elapse 16597469 ticks (16.60 ms) (0.00 min) ...
---> Elapse 15605666 ticks (15.61 ms) (0.00 min) ...
Average: ---> Elapse 16069953 ticks (16.07 ms) (0.00 min) ...

===== Relation (select) =====
---> Elapse 3047628 ticks (3.05 ms) (0.00 min) ...
---> Elapse 3125855 ticks (3.13 ms) (0.00 min) ...
---> Elapse 2869383 ticks (2.87 ms) (0.00 min) ...
---> Elapse 2919881 ticks (2.92 ms) (0.00 min) ...
---> Elapse 3014382 ticks (3.01 ms) (0.00 min) ...
---> Elapse 2921627 ticks (2.92 ms) (0.00 min) ...
---> Elapse 2875459 ticks (2.88 ms) (0.00 min) ...
---> Elapse 2843331 ticks (2.84 ms) (0.00 min) ...
---> Elapse 3197377 ticks (3.20 ms) (0.00 min) ...
---> Elapse 2871687 ticks (2.87 ms) (0.00 min) ...
---> Elapse 2821260 ticks (2.82 ms) (0.00 min) ...
---> Elapse 3263100 ticks (3.26 ms) (0.00 min) ...
---> Elapse 2905074 ticks (2.91 ms) (0.00 min) ...
---> Elapse 2855135 ticks (2.86 ms) (0.00 min) ...
---> Elapse 3093517 ticks (3.09 ms) (0.00 min) ...
---> Elapse 2958995 ticks (2.96 ms) (0.00 min) ...
Average: ---> Elapse 2973980 ticks (2.97 ms) (0.00 min) ...

为什么stdext Relation 比 GRelation 好这么多?

其实两者的实现方案完全类似。唯一不同是而GLib多了一个我认为不必要的HashTable,这导致GLib在插入时多了一次多余的查找(但 select性能不会因为这个多余的HashTable影响)。但是就这一点而言,怎么也不致于差这么多:你可以看到两者性能差5倍左右。

这个例子很典型。那些认为C比C++更容易写出高效的代码的人应该想想性能差异主要在哪些地方。

其实我认为关键的性能差异(之一)在于C用了回调(callback),C++用了仿函数(functor)

这个问题在sort函数上更为明显,因为sort中比较函数调用非常频繁,比HashTable要频繁很多。

所以,C++的std::sort的性能是任何语言都无法与之相提并论的。关于仿函数(functor)更详细的信息,参阅:http://cpp.winxgui.com/cn:functor

 
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值