簡體   English   中英

從多個std :: vectors中刪除項目的最快方法

[英]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元素的存在。 如果擦除中間的一個元素,則必須移動從該位置到結尾的所有元素,以便在移除元素之前調整元素。 這是通過

  • 每個元素一個復制構造,如果沒有移動ctor或者移動ctor沒有標記為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM