std :: vector中的值传播

时间:2013-07-10 10:20:21

标签: c++

如果我的std::vector初始化如下:

0 1 2 3 4 5

我怎样才能最好地将4传播到第一位?即我想要std::vector处于这种状态:

4 0 1 2 3 5

移除4并重新插入它可能很昂贵,因为前面的插入是O(N),我相信。我在考虑在连续的地方交换值(比如在冒泡排序中),但那也是O(N)。是否正在使用另一个容器,例如std::list

编辑: 在看到一些混淆之后,让我澄清一下,我的目标是在std::vector中另一个已知位置的值前面的std::vector中的已知任意位置添加值。

4 个答案:

答案 0 :(得分:15)

即使有可接受的答案,正常的C ++方式是使用提供的算法。在这种情况下,它应该是std::rotate

#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator> // for std::advance


int main(int argc, char** argv) {

    std::vector<int> v = { 0, 1, 2, 3, 4, 5 };

    std::cout << "Before: ";
    for (auto element : v)
        std::cout << element << " ";
    std::cout << std::endl;

    // edit starts here
    auto first=v.begin();
    auto nfirst=first;
    std::advance(nfirst, 4); // Iterator of first element to move to front
    auto last=nfirst;
    std::advance(last, 1); // 1 is element count for moving to front

    std::rotate(first, nfirst, last);
    // edit ends here

    std::cout << "After: ";
    for (auto element : v)
        std::cout << element << " ";
    std::cout << std::endl;

    return 0;
}

编辑: 在与Luc Touraille讨论后,我看到了改进的空间。现在解决方案使用std::advance进行迭代器操作。所以它应该使用前向迭代器,这是std::rotate的要求。

答案 1 :(得分:7)

如果O(N)出现问题,更改容器(例如std :: deque)是唯一的选择。

但是,请确保O(N)确实是个问题!

答案 2 :(得分:3)

说真的,我强烈怀疑O(n)确实是你实际代码中的一个问题。有一个更好的理由使用std::vector而不是std::list,比更好的内存局部性和更少的内存开销,而不仅仅是大O.但您仍然可以优化标准方法(要求dstsrc之前),

std::vector<int>::iterator src = ..., dst = ...;
...
auto tmp = std::move(*src);
vec.erase(src);
vec.insert(dst, std::move(tmp));

将O(n)个遍历(erase中的一个左移和insert中的一个左移)转换为一个(可能更小)的一个:

auto tmp = std::move(*src);
for(auto iter=src; iter!=dst; --iter)
    *iter = std::move(*std::prev(iter));
*dst = std::move(tmp);

编辑:请注意我上面的代码段除了在他的回答中按照 Jan 的建议不必要地复制std::rotate之外别无其他。

答案 3 :(得分:2)

作为@JanHerrmann提供的优秀答案的补充,这是一个用于移动范围内元素的通用函数:

#include <algorithm>
#include <iostream>
#include <iterator>

// Moves the element src before dst, maintaining the order of other values
template <typename RandomAccessIt>
void moveElement(RandomAccessIt src, RandomAccessIt dst)
{ 
    if (dst == src)
    {
        return;
    }
    if (dst < src)
    { 
        std::rotate(dst, src, src + 1);
    }
    else
    { 
        std::rotate(src, src + 1, dst);
    }
}

void printVector(const std::vector<int> &v)
{
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
}

int main() {

    std::vector<int> v = { 0, 1, 2, 3, 4, 5 };
    printVector(v); // 0 1 2 3 4 5

    moveElement(v.begin() + 4, v.begin());
    printVector(v); // 4 0 1 2 3 5

    moveElement(v.begin() + 2, v.begin() + 2);
    printVector(v); // 4 0 1 2 3 5

    moveElement(v.begin() + 2, v.begin() + 3);
    printVector(v); // 4 0 1 2 3 5

    moveElement(v.begin() + 2, v.end());
    printVector(v); // 4 0 2 3 5 1
}