将对象移动到矢量c ++的前面

时间:2015-04-21 23:55:29

标签: c++ vector

我的vector<Suggestions> finalSuggestions包含string word和一些int num

如果这个单词满足某些条件,我想将该对象移动到向量的前面,将其从任何地方移除。

我可以使用vector::insert

插入列表的开头
for (auto &x: finalSuggestions) {
    if ( double((x.num)/(topword.num)) < 50)
    {
        finalSuggestions.insert(finalSuggestions.begin(),x);
        break;
    }
}

我不知道如何将其从列表中的位置删除。

例如,对于某些任意向量{ 1,2,3,4,50,6,7,8,9 }, 如果50符合条件,请将其移至列表的前面并将其从原处删除,然后返回{ 50,1,2,3,4,6,7,8,9 }。上面的代码返回{ 50,1,2,3,4,50,6,7,8,9 }

我正在调查vector::erase,但我遇到了问题,并且花费的时间超过了应有的时间。

我设想了一个简单的解决方案(但这显然不起作用)

for (auto &x: finalSuggestions) {
    if ( double((x.num)/(topword.num)) < 50)
    {
        finalSuggestions.insert(finalSuggestions.begin(),x);
        finalSuggestions.erase(x);
        break;
    }
}

我读了擦除删除习语(这是我的实现):

 finalSuggestions.erase( remove( begin(finalSuggestions), end(finalSuggestions), x ), end(finalSuggestions) ); 

但是我收到了一个我不明白的错误:

In instantiation of '_FIter std::remove(_FIter, _FIter, const _Tp&) [with _FIter = __gnu_cxx::__normal_iterator<Suggestion*, std::vector<Suggestion> >; _Tp = Suggestion]':|

6 个答案:

答案 0 :(得分:19)

使用std::rotate。它比删除和重新插入要快很多。

例如:

for (auto it = finalSuggestions.begin(), lim = finalSuggestions.end();
     it != lim;
     ++it) {
  if (it->num < 50 * topword.num) {
    std::rotate(finalSuggestions.begin(), it, it + 1);
    break;
  }
}

更好的是,正如@JerryCoffin在评论中建议的那样,使用std::find_if来找到支点:

auto pivot = std::find_if(finalSuggestions.begin(),
                          finalSuggestions.end(),
                          [&topword](const Suggestions& s) -> bool {
                            return s.num < 50 * topword.num;
                          });
if (pivot != finalSuggestions.end()) {
  std::rotate(finalSuggestions.begin(), pivot, pivot + 1);
}

答案 1 :(得分:8)

对于vector::erase,您需要一个迭代器,因此不能使用基于范围的for。请改用简单的for循环。首先擦除一个元素,然后插入它,因为insert使迭代器无效:

for (auto it = finalSuggestions.begin(); it != finalSuggestions.end(); ++it) {
    if (some_condition(*it)) {
        auto x = *it; // or std::move(*it)
        finalSuggestions.erase(it);
        finalSuggestions.insert(finalSuggestions.begin(), x /* or std::move(x) */);
        break;
    }
}

使用std::move将允许您移动元素而不是复制它,这可以节省一些周期。

答案 2 :(得分:2)

您的迭代器使得很难知道相关元素的位置。您可能想尝试使用允许访问该位置的标准for迭代器(由std::vector::erase使用)

int len=finalSuggestions.size();
for (int i=0, ; i<len; ++i) {
    // Save a copy of the item
    auto item = finalSuggestions.at(i);
    if (double((item.num)/(topword.num)) < 50) {
        // Erase the item in the list
        finalSuggestions.erase(i);
        // Add the copy of the item back in at the front
        finalSuggestions.insert(finalSuggestions.begin(), item);
        break;
    }
}

...或使用std :: iterator ...

for (auto it = finalSuggestions.begin(); it != finalSuggestions.end(); ++it) {
    if (double((*it->num)/(topword.num)) < 50) {
        // Save a copy of the item
        auto item = *it;  
        // Erase the item in the list
        finalSuggestions.erase(it); 
        // Add the copy of the item back in at the front
        finalSuggestions.insert(finalSuggestions.begin(), item); 
        break;
    }
}

std::vector个对象对其元素使用连续内存,这意味着在更改容器期间实际移动内存。如果您要移动元素,可能需要查看std::liststd:deque。这些容器的定义几乎完全相同(读取:替换掉),使得替换它们非常简单。

<强>建议:

std::deque设计用于在容器的开头和结尾进行最佳插入。取自网站cplusplus.com:

  

...它们提供类似于向量的功能,但是在序列的开头也有效地插入和删除元素,而不仅仅是在它的结尾。但是,与矢量不同,deques不能保证将其所有元素存储在连续的存储位置:...

答案 3 :(得分:1)

安东的回答是正确的。但是,如果你做了很多这样的事情,你应该考虑不同的数据结构。 eraseinsert都是O(N)操作,其中N是vector的大小。如果这是一个常见的操作,列表会更好。

答案 4 :(得分:1)

它在功能上等同于Anton的答案,但是我会使用std::find_if来获取你正在寻找的元素的迭代器而不是循环。

//add #include <algorithm> to your source file

auto result = std::find_if(finalSuggestions.begin(), finalSuggestions.end(), condition_func);
if(result != finalSuggestions.end())
{
    auto resultValue = *result;
    finalSuggestions.erase(result);
    finalSuggestions.insert(finalSuggestions.begin(), resultValue);
}

condition_func应该是一个返回bool的函数,它接受一个与向量中元素类型匹配的参数(在本例中为Suggestion):

bool condition_func(Suggestion elementValue) { /*condition here*/ }

有关find_if的更多信息,请here

答案 5 :(得分:0)

也许使用std :: iter_swap可以解决您的问题。

#include <iostream> 
#include <algorithm>
#include <vector>
using namespace std;
int main () {
vector<int> myvector{};
for(int io{}; io<7; ++io) myvector.push_back(io+1);
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
cout << ' ' << *it;
cout << '\n';
iter_swap(myvector.begin(),myvector.begin()+2);//exchange the third element with the first.
cout << "myvector contains:";
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
std::cout << ' ' << *it;
 std::cout << '\n';
return 0;
}