【问题标题】:Does inserting an element in vector by re-sizing the vector every time takes more time?每次通过重新调整向量的大小来在向量中插入元素是否需要更多时间?
【发布时间】:2016-04-28 03:29:16
【问题描述】:

我在这里遇到了一个决策问题。在我的应用程序中,我需要合并两个向量。我不能使用 stl 算法,因为数据顺序很重要(不应该排序。)。

  • 两个向量都包含有时相同或在最坏情况下相差 75% 的数据。

  • 目前我对两种方法感到困惑,

    Approach 1:
    
       a. take an element in the smaller vector.
       b. compare it with the elements in bigger one.
       c. If element matches then skip it (I don't want duplicates).
       d. If element is not found in bigger one, calculate proper position to insert.
       e. re-size the bigger one to insert the element (multiple time re-size may happen).
    
    
     Approach 2:
    
       a. Iterate through vectors to find matched element positions.
       b. Resize the bigger one at a go by calculating total size required.
       c. Take smaller vector and go to elements which are not-matched.
       d. Insert the element in appropriate position.
    

请帮我选择合适的。如果有任何更好的方法或更简单的技术(如 stl 算法),或者比向量更简单的容器,请在此处发布。谢谢。

【问题讨论】:

  • 使用set 怎么样?您可以非常轻松地完成方法 1 中的所有步骤。
  • 任何改进建议都需要关于您的数据的真实信息。例如,什么决定了订单 - 即您如何计算要插入的位置?数组中值的类型和范围是什么?
  • 嗨@paddy。数据是格式化的字符串。数据来自两个不同的 xml 文件。由于存在分组,因此顺序很重要,并且位置计算基于最后插入的位置和当前元素位置。但是,元素范围并不太大。最大可以达到 5000 个元素。

标签: c++ algorithm vector stl


【解决方案1】:

您不应该专注于调整大小。在方法 1 中,您应该使用 use vector.insert() 因此您实际上不需要自己调整向量的大小。这可能会导致底层缓冲区的重新分配自动发生,但 std::vector 是经过仔细实现的,因此这些操作的总成本会很小。

您的算法的真正问题是插入,也许是搜索(您没有详细说明)。当您在除末尾之外的任何位置进入向量时,插入点之后的所有元素都必须在内存中向上移动,这可能会非常昂贵。

如果你想让这个速度更快,你应该从你的两个输入向量中构建一个新向量,一次追加一个元素,中间不要插入。

【讨论】:

  • 嗨@Matt。你的回答很有道理。但是有一些问题。请考虑这个例子。假设我有两个向量。 v1 {1,2,3,4,5,6} 和 v2 {7,9,1,4,8}。现在,无论我采用什么向量,在某些情况下我需要在最终向量中插入元素。我需要的输出是 F {7,9,1,2,3,4,5,6,8}。你有什么更好的方法来避免在这种情况下插入。我的意思是如何选择我需要首先插入的元素。我不希望它们按排序顺序。
  • @BharadwajGali:插入在末尾​​i>很好。
  • @BharadwajGali 当您说“计算要插入的正确位置”和“在适当位置插入”时,您没有说明如何确定适当位置,所以我们不知道什么顺序如果您要通过附加来构建目标向量,则您想要元素并且无法告诉您如何选择“下一个”。
【解决方案2】:

看起来你不能以比 O(n.log(n)) 更好的时间复杂度来执行此操作,因为从法线向量中删除重复项需要 n.log(n) 时间。因此,使用 set 删除重复项可能是您能做的最好的事情。 n 这里是两个向量中的元素数。

【讨论】:

  • 我不需要删除任何重复项。如您所见,我将检查元素是否匹配,如果匹配则跳过它。 (如果我是正确的,这将减少大小重新排列的时间。)我确实考虑设置和检查。但是当我不断调整矢量大小时,你能说出性能吗?感谢您的快速回复。
【解决方案3】:

根据您的实际设置(例如,如果您将对象指针添加到向量而不是将值复制到一个向量中),使用 std::list 可能会获得明显更快的结果。 std::list 允许恒定时间插入,这将是一个巨大的性能开销。

进行插入可能有点尴尬,但完全可以通过仅更改几个指针(便宜)而不是通过向量插入来完成,该向量将每个元素移开以放下新元素。

如果它们最终需要作为向量,您可以将列表转换为具有类似(未经测试)的向量

std::list<thing> things;

//efficiently combine the vectors into a list
//since list is MUCH better for inserts
//but we still need it as a vector anyway

std::vector<thing> things_vec;
things_vec.reserve(things.size()); //allocate memory

//now move them into the vector
things_vec.insert(
    things_vec.begin(), 
    std::make_move_iterator(things.begin()), 
    std::make_move_iterator(things.end())
);

//things_vec now has the same content and order as the list with very little overhead

【讨论】:

  • 嗨@Bryan。我正在向向量中添加一个结构(将来它可能会成为对象而不是指针)。