使用地图代替矢量
Posted
技术标签:
【中文标题】使用地图代替矢量【英文标题】:use map in place of vector 【发布时间】:2012-03-09 07:26:06 【问题描述】:我正在扩展一个已经存在的 C++ 代码。 其中一个类成员是另一个类对象的向量类型:
class Road
....
vector<Link*> links; //Link is just another class
其他模块通过大量的序列迭代器使用这个类及其成员。 现在,在扩展代码时,我需要向 Link 类添加一个名为 linkID 的成员,并使用此 linkID 来查找/访问我的“Link”对象。
问题: 我不会通过迭代数百万个项目来搜索向量中的 Link 对象(使用 LinkID),而只是为了找到一个特定的 Link 对象。最好的解决方案是“地图”!对吧?
....
map<linkID,*link> links
....
lnk=links[linkID]
.........
但问题是我不能修改当前的源代码,除了非常小的修改,比如添加链接ID等。
所以我的明显问题是: 是否可以(无论如何)。 换句话说,我想创建一个地图,将其填充,然后将其视为矢量。可能的? 谢谢你们的cmets
【问题讨论】:
只要您拥有的代码被巧妙地实现,即:不依赖std::vector
的随机迭代器行为,只需更改类型就可以了。当然,您最终将不得不重新访问所有实例如果您依赖容器的顺序性,但您无能为力,如果现有代码依赖于这种行为,那么它一开始就写得不好。
我同意上面的 Als。不过,这不仅仅是随机迭代器行为。例如,代码是否在执行类似links.push_back(ptr)
的操作?另外,代码是否依赖于位置访问链接?
@KAZ FYI,linkID 是一个类似于“lnk001”的字符串,来自 XML,稍后将用作数据库表的 PK。
@Als:你的意思是我将地图类型转换为矢量吗? (最初填写地图,然后将其视为矢量?)可能吗?能给我举个例子吗?
你能有矢量图和地图吗?
【参考方案1】:
最好的解决方案是“地图”!对吧?
是的,听起来地图是解决您问题的最简单方法。但我不会使用 operator[],而是使用 find 和 insert 方法。
最初,您可以更改代码以使用std::map< unsigned int, link* >
这种类型的映射,因为它与vector< link* >
最相似。然后就可以轻松切换到std::map< LinkId, link* >
。
【讨论】:
【参考方案2】:我认为您可以做的是创建一个增强的数据结构:vectormap
,它允许您通过linkID
对项目进行密钥访问,并且还支持std::vector
的操作。这个对象的[]
操作符可以被重载,这样links[3]
给你提供了对向量的位置访问,links[linkID]
在地图中查找一个链接ID。可以支持push_back
之类的东西,如果代码需要它们:push_back
必须将元素推入向量中,然后还要执行map[item->linkID] = item
将其输入到地图中。您可能会得到图片。
【讨论】:
哇!我不知道怎么做,但我会开始尝试一下,稍后再回复您。【参考方案3】:将地图伪装成矢量是不可能的。
理论上,您可以尝试实现一个从向量派生的新类(即使用std::vector
作为基类)。在内部,它可以使用映射,而在外部,它将具有向量的接口(并且它会被接受为向量的替代品,因为它是由它派生的)。
不过,在实践中,您可能会遇到许多问题。您显然也会继承向量的内部数据结构,因此您必须在实现中忽略它们,即将它们留空。正如@Als 在下面的评论中指出的那样,从 STL 类(basic_
除外)派生也违反了推荐的做法并且可能存在风险。
如果有机会通过重写大部分现有代码来避免这种情况,您应该这样做。但如果不可避免,使用继承可能会奏效。
【讨论】:
标准库容器不打算充当基类,它们没有虚拟析构函数,所以这是一个不好的建议。如果在处理标准时最好使用组合而不是继承库容器类。 @Als 是的,但如果你只是简单地用地图替换矢量,你就必须更改大部分源代码,例如因为迭代器的映射返回与向量返回的完全不同。这就是 OP 想要避免(或必须避免)的。 @Als 如果他有 std::vector我在很多个月前为铁路网络做过这个。基类是链接和节点。实际的铁路和最终的路线都是基于这些。 IIRC 我使用std::list
来包含链接和节点,并使用向量的向量来包含实际轨道。
【讨论】:
【参考方案5】:如果linkID
是Link
的成员,则正确的解决方案是std::set<Link*, OrderByLinkID>
。 OrderByLinkID
谓词将采用两个 Link*
并返回 true,前提是第一个具有较小的 linkID 成员。
结果是 std::set 仍然包含Link*
,你可以像 std::vector 一样迭代它们。相比之下,使用 std::map 您最终会迭代 std::pair<Link*, LinkID>
,这是一个更大的变化。
【讨论】:
嗨,我希望你还在关注这个。我需要知道在您的“设置”解决方案中查找的速度有多快?我这样做的主要原因是能够快速查找链接(或任何其他对象),这个解决方案会比地图更快吗? 两者都是O(log N)
。相比之下,向量是O(N)
。以上是关于使用地图代替矢量的主要内容,如果未能解决你的问题,请参考以下文章