【问题标题】:Good datastructure for look up of an id mapping to set of elements (c++)用于查找到元素集的 id 映射的良好数据结构 (c++)
【发布时间】:2009-06-23 19:12:08
【问题描述】:

没有提升,请简单的 STL。

我有一个类 Foo* 映射到一组类 ID 的指针。

我需要将指向 ID 实例的指针映射到 FOO 类。

说我有这个功能:

void FindXXX(const ID* pID)
{

 /*find the containing FOO class quickly, but not at expense of an ugly code*/

}

现在我将每个 ID* 映射到 FOO* 从而得到类似的东西

映射我的地图;我认为这有点丑陋和多余。

请推荐

【问题讨论】:

  • 什么值得反对?请建议我如何提高此问题的质量以赢得您的支持?
  • 是否保证每个ID对应一个Foo?如果是这样,类 ID 是否可以包含指向它所属集合的指针?那么保留一张 set* => Foo* 的地图就足够了。
  • 是的,这是有保证的。但是,保持 set* => foo,将不允许您查询,例如查找特定 ID* 的 FOO* 实例
  • 但是如果每个ID在逻辑上都属于一个FOO,为什么不在ID中包含一个指向FOO的指针作为成员变量呢?
  • 因为我无法修改这些类。

标签: c++ algorithm stl


【解决方案1】:

现在我将每个 ID* 映射到 FOO* 有类似的东西

映射我的地图;我认为这是一种 丑陋而多余。

我假设你有这样的东西:

map<ID*, Foo*> myMap;

为什么会很丑?

【讨论】:

  • 请将 cmets 发布到我的问题的评论部分。谢谢...因为我为许多许多 ID 存储了同一个 Foo* 实例,因为每个 ID 在逻辑上属于 Foo*
【解决方案2】:

听起来像是 std::map 的工作,但您的言论似乎表明您不想使用它,是这样吗?

std::map <key_type, data_type, [comparison_function]>

【讨论】:

  • 不正确 我确实想使用一个,只是不知道如何正确设置它。我已经拥有的那个似乎浪费了很多空间,因为我为多个 ID 存储重复的 Foo*
  • 嗯,它是一个哈希,所以默认情况下它会比简单的数组消耗更多的空间。
【解决方案3】:

嗯,这取决于两个集合(ID* 和 foo*)的大小。我假设您有 #ID >> #FOO,并且 #FOO 大到足以保证通过它们进行线性搜索。

我假设 ID Foo 是一对多映射。

您可以将映射存储为一组 >> 并以这种方式对它们进行排序: 该集合按 ID* 的升序排序(指针值顺序可以) set> 按对中第一个 ID* 的值的升序排序。第二个。

搜索时,您需要找到 Foo* 的范围,其中第一个 ID* 的(指针)值低于被搜索项,最后一个值更高。这将导致希望迭代它们的集合的项目集要小得多。 然后,遍历这些并找到包含您要查找的 ID* 的那个。

你需要一个比较器来匹配这对 > 像这样:

typedef Item pair<Foo*, set<ID*> >;

// Sorter in ascending order of first ID*, then ascending order of last ID*
struct IDOrdering: public binary_function<Item, Item, bool> {
  bool operator ()(const Item& lhs, const Item& rhs) {
    return *(lhs.second.begin()) < *(rhs.second.begin())
        || *(lhs.second.rbegin()) < *(rhs.second.rbegin());
  }
};


// your global map
set<Item, FirstIDOrdering> myMap;
typedef set<Item, FirstIDOrdering>::iterator ItemIterator;

// search for the item
Foo* FindXXX(const ID* pId) {
   Item criterion;
   criterion.second.insert(pId);
   ItemIterator start = myMap.lower_bound(criterion);
   while (start != myMap.end() && *(start->second.rbegin()) > pId) {
     if (start->second.count(pId))
       return start->first;
   }
   return NULL;
}

您可以在这里节省一些内存,因为 Foo* 和 ID* 只存储一次,但它会以一些复杂性和可能的​​一些性能为代价。

请注意,此示例未考虑各种边界情况(空列表),并且在将新项目插入全局 myMap 时必须小心,因为您可能可以将新 ID* 添加到一对的列表,但您需要确保整个集合再次排序,以便查找真正起作用。

但是,很难知道什么最适合您,因为关于您尝试实现的目标的信息很少:数百万的 Foo*,数百万的 ID*,这个函数是将 ID* 解析为 Foo* 经常调用?在系统的性能关键部分?所有这些都有助于权衡代码的可读性、复杂性和性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 2015-03-16
    • 1970-01-01
    • 2013-04-25
    • 1970-01-01
    • 1970-01-01
    • 2010-12-29
    相关资源
    最近更新 更多