使用地图代替矢量

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&lt; unsigned int, link* &gt; 这种类型的映射,因为它与vector&lt; link* &gt; 最相似。然后就可以轻松切换到std::map&lt; LinkId, link* &gt;

【讨论】:

【参考方案2】:

我认为您可以做的是创建一个增强的数据结构:vectormap,它允许您通过linkID 对项目进行密钥访问,并且还支持std::vector 的操作。这个对象的[] 操作符可以被重载,这样links[3] 给你提供了对向量的位置访问,links[linkID] 在地图中查找一个链接ID。可以支持push_back 之类的东西,如果代码需要它们:push_back 必须将元素推入向量中,然后还要执行map[item-&gt;linkID] = item 将其输入到地图中。您可能会得到图片。

【讨论】:

哇!我不知道怎么做,但我会开始尝试一下,稍后再回复您。【参考方案3】:

将地图伪装成矢量是不可能的。

理论上,您可以尝试实现一个从向量派生的新类(即使用std::vector 作为基类)。在内部,它可以使用映射,而在外部,它将具有向量的接口(并且它会被接受为向量的替代品,因为它是由它派生的)。

不过,在实践中,您可能会遇到许多问题。您显然也会继承向量的内部数据结构,因此您必须在实现中忽略它们,即将它们留空。正如@Als 在下面的评论中指出的那样,从 STL 类(basic_ 除外)派生也违反了推荐的做法并且可能存在风险。

如果有机会通过重写大部分现有代码来避免这种情况,您应该这样做。但如果不可避免,使用继承可能会奏效。

【讨论】:

标准库容器不打算充当基类,它们没有虚拟析构函数,所以这是一个不好的建议。如果在处理标准时最好使用组合而不是继承库容器类。 @Als 是的,但如果你只是简单地用地图替换矢量,你就必须更改大部分源代码,例如因为迭代器的映射返回与向量返回的完全不同。这就是 OP 想要避免(或必须避免)的。 @Als 如果他有 std::vector* vp = new MyDerivedClass,这不是一个问题吗?私有继承是安全的(我并不是说它是正确的解决方案) @juanchopanza:是的,你可能想看看here。【参考方案4】:

我在很多个月前为铁路网络做过这个。基类是链接和节点。实际的铁路和最终的路线都是基于这些。 IIRC 我使用std::list 来包含链接和节点,并使用向量的向量来包含实际轨道。

【讨论】:

【参考方案5】:

如果linkIDLink 的成员,则正确的解决方案是std::set&lt;Link*, OrderByLinkID&gt;OrderByLinkID 谓词将采用两个 Link* 并返回 true,前提是第一个具有较小的 linkID 成员。

结果是 std::set 仍然包含Link*,你可以像 std::vector 一样迭代它们。相比之下,使用 std::map 您最终会迭代 std::pair&lt;Link*, LinkID&gt;,这是一个更大的变化。

【讨论】:

嗨,我希望你还在关注这个。我需要知道在您的“设置”解决方案中查找的速度有多快?我这样做的主要原因是能够快速查找链接(或任何其他对象),这个解决方案会比地图更快吗? 两者都是O(log N)。相比之下,向量是O(N)

以上是关于使用地图代替矢量的主要内容,如果未能解决你的问题,请参考以下文章

如何使用地图矢量

ECharts常用图表 地图

使用DEM和矢量数据绘制地图

免费百度地图矢量下载工具V5.7使用文档

OpenLayers 3:尝试将图像参考添加到矢量图层

地图(用ECharts绘制)