[英]fastest way to remove items from multiple std::vectors
我有三個std::vectors
,每個都包含不同的數據類型。
我需要做的是從每個索引項中刪除相同的索引項,具體取決於第一個索引項的值。
在下面的代碼中,如果localMap_points[i].m_counter
值大於30,我將從所有三個向量中刪除index [i]
處的項目。 ( localMap_desc
包含8個項目,其他向量一個,因此x 8
添加到那個)
這很好用,但很慢。 有更快的方法嗎?
我有:
for (int i = 0; i < localMap_points.size(); i++)
{
if (localMap_points[i].m_counter > 30)
{
localMap_kp.erase(localMap_kp.begin() + i, localMap_kp.begin() + i + 1); // Deleting from n element to n element
localMap_desc.erase(localMap_desc.begin() + (i * 8), localMap_desc.begin() + (i * 8) + 8); // Deleting from n element to n element X 8
localMap_points.erase(localMap_points.begin() + i, localMap_points.begin() + i + 1); // Deleting from n element to n element
}
}
這里的性能瓶頸是std::vector
的內存布局,可能還有特殊的成員函數屬性/ vector元素的存在。 如果擦除中間的一個元素,則必須移動從該位置到結尾的所有元素,以便在移除元素之前調整元素。 這是通過
noexcept
因此,要確保的第一件事是存儲在向量中的元素類型具有noexcept
移動構造函數。
其次,請務必在此處使用erase-remove慣用法 。 通過遵循此模式,在任何調用擦除之前,首先完成交換調用方面的重新排序。 對於要刪除的n
項目,這些是n
交換調用。 然后,您將對std::vector::erase
進行一個簡單的調用,因為所有元素都已按原樣放置。 為了使此過程盡可能快,您可能需要考慮為自定義類型提供swap
功能。
使用更合適的數據結構。 向量不適用於快速內部刪除和插入(是O(n)
),如果您不需要索引訪問(插入/刪除是O(1)
==常量時間),列表可能是更好的選擇。 根據您的需要,您可以使用輔助結構,但如果沒有進一步的信息,則無法實現。
---添加另一個想法(雖然有人已經提出這個想法)。
如果向量的順序無關緊要,您可以將要刪除的項目與向量中的最后一項swap
,然后使用pop_back()
。
這將是O(1)
。
- - 把想法大聲說出來。
另一個技巧是使用優先級隊列 。 它們是基於一個字段的“權重”重新排序的數據結構,在您的應用程序中它將是counter
字段。 它們能夠插入O(log n)
並從O(1)
頂部刪除。 所以用較高的counter
移除物品會很快,因為它們總是處於最頂層。
這是一個如何一次為三個向量應用擦除 - 移除習語的示例。
O( N )中的算法,即需要對矢量進行單次傳遞。
template<typename T1, typename T2, typename T3, typename P>
void erase3(T1& v1, T2& v2, T3& v3, P predicate) {
auto first1 = begin(v1);
auto first2 = begin(v2);
auto first3 = begin(v3);
while (first1 != end(v1) && !predicate(*first1)) {
++first1; ++first2; ++first3;
}
if (first1 != end(v1)) {
auto it1 = first1; auto it2 = first2; auto it3 = first3;
while (++it1 != end(v1)) {
++it2;
++it3;
if (!predicate(*it1)) {
*first1++ = std::move(*it1);
*first2++ = std::move(*it2);
*first3++ = std::move(*it3);
}
}
v1.erase(first1, end(v1));
v2.erase(first2, end(v2));
v3.erase(first3, end(v3));
}
}
int main()
{
std::vector<int> v1 = { 1,2,3,4,5 }, v2 = { 11,12,13,14,15 }, v3 = { 21,22,23,24,25 };
erase3(v1, v2, v3, [](int a) { return a == 3 || a == 4; });
}
這可以通過將所有剩余元素移動到向量的開頭,然后從末尾修剪掉移出的元素來實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.