C++:用于高效插入和检索自定义数据的数据结构

Posted

技术标签:

【中文标题】C++:用于高效插入和检索自定义数据的数据结构【英文标题】:C++: Data structure for efficient insertion and retrieval of custom data 【发布时间】:2012-04-18 03:16:45 【问题描述】:

我在 C++(在 Windows 上)中遇到了一种情况,我需要保留一组 int: pair,其中 start 值是唯一的(我们不需要关心这个)。 所需的操作是:

插入对 检索对X:这应该返回对Y,其中Y的开始

基本的解决方案是简单地保留一组对。对于检索,我们将依次遍历要检查的集合。这是 O(n)。

我正在寻找更好的解决方案。我目前看到 2 个候选数据结构:

    排序向量 STL 的集合(内部实现为二叉搜索树?)

排序向量: 优点:可以自定义二分查找,支持检索操作。这是 O(logn) 缺点:如何有效地插入新对以保持排序顺序。如何避免 O(nlogn) 的重新排序成本?

设置: 优点:使用标准插入方法轻松插入。这是 O(1)? 缺点:如何避免顺序搜索?如何比 O(n) 做得更好?

感谢您的建议。

我也对任何其他可以有效地支持上述两种操作的结构(第一个标准是速度;第二个是内存)持开放态度。

【问题讨论】:

我在您的描述中看到了一个缺失的情况,如果x = 3 并且您尝试从具有1,21,4 的结构中检索。应该使用哪一个? std::map 似乎是显而易见的选择,因为它实际上只是一个 std::set 对,其中比较操作只查看对的第一部分 @Jack:谢谢。在我的情况下,起始值不能有重复值。我已经更新了这个问题。谢谢。 如果你真的想要效率,你可能需要 B+ 树,我认为它在 STL 中没有实现。由于局部性差,对大数据进行二分搜索(无论是否为树)在现代 CPU 上都是灾难性的。 好像你在说这些对代表范围。范围可以重叠吗? 【参考方案1】:

尚不清楚范围是否可以重叠,但如果不能,那么这应该可以。我已经包含了一个完整的测试示例。

#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include <map>

struct RangeContainer 
  typedef std::map<int,int> RangeMap;
  typedef std::pair<int,int> Range;

  void insert(const Range &range)
  
    range_map.insert(range);
  

  Range find(const Range &x) const
  
    RangeMap::const_iterator iter = range_map.upper_bound(x.second);
    if (iter==range_map.begin()) 
      return invalidRange();
    
    --iter;
    Range y = *iter;
    if (y.first<x.first && x.second<y.second) 
      return y;
    

    return invalidRange();
  

  static Range invalidRange()
  
    return Range(INT_MAX,INT_MIN);
  

  RangeMap range_map;
;


static void test1()

  RangeContainer c;
  typedef RangeContainer::Range Range;
  c.insert(Range(1,10));
  c.insert(Range(20,30));
  assert(c.find(Range(-5,-4))==c.invalidRange());
  assert(c.find(Range(1,10))==c.invalidRange());
  assert(c.find(Range(2,9))==Range(1,10));
  assert(c.find(Range(2,10))==c.invalidRange());
  assert(c.find(Range(11,19))==c.invalidRange());
  assert(c.find(Range(21,29))==Range(20,30));
  assert(c.find(Range(20,29))==c.invalidRange());
  assert(c.find(Range(21,30))==c.invalidRange());
  assert(c.find(Range(35,40))==c.invalidRange());


int main(int argc,char **argv)

  test1();
  return EXIT_SUCCESS;

【讨论】:

感谢您的回答,尤其是示例程序。不过,我有一个问题:您是否大致知道 map 的 upper_bound 方法在内部是通过顺序迭代还是通过对(排序的)键进行二进制搜索来实现的?如果搜索是顺序的,是不是就相当于使用set和顺序迭代? 类似于二分查找,所以具有对数复杂度。

以上是关于C++:用于高效插入和检索自定义数据的数据结构的主要内容,如果未能解决你的问题,请参考以下文章

用于对大型数组进行高效插入和删除的数据结构

如何高效实现批量插入数据,并去重

C++ - 在自定义数据类型向量中按值匹配和替换元素

如何插入数据库 Drupal 自定义字段

如何从自定义 UITableview 中检索有关选择单元格的数据

将自定义数据属性插入 JQuery DataTables