簡體   English   中英

std:container c ++移到前面

[英]std: container c++ move to front

我正在尋找像std :: list這樣的std容器,它可以有效地將元素移動到前面:

a-b-c-d-e

將“b”移到前面:

a-c-d-e-b

std容器中沒有這樣的功能。 因此,我認為我必須結合使用remove和push_front函數,但任何人都可以找到更好的主意嗎?

預先感謝。

std::vector ,你可以使用std::rotate ,它具有線性復雜性

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

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

int main()
{
   std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ",")); 
   std::cout << "\n";

   // swap ranges [1, 2) and [2, 5)
   auto it = std::next(v.begin(), 1); // O(1)
   auto rb = std::next(it);
   auto re = v.end();
   std::rotate(it, rb, re); // O(N)

   std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));   
   std::cout << "\n";
}

std::list您可以使用成員函數splice ,它(給定迭代器)具有恆定的復雜性

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

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

int main()
{
   std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ",")); 
   std::cout << "\n";

   auto it = std::next(v.begin(), 1); // O(N)
   auto rb = std::next(it);
   auto re = v.end();   
   v.splice(it, v, rb, re); // O(1)

   std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
   std::cout << "\n";   
}

注意 :最后一個元素通常表示為STL容器中的back ,第一個元素作為front 對於std::vector ,獲取某個元素的迭代器是常量時間,交換是線性時間。 對於std::list ,獲取迭代器是線性時間,但是拼接到同一個列表是常量時間。 然而,正如Stroustrup的這個基准所示,矢量更好的內存緩存行為也很重要。

更新 :幾個評論者提到簡單交換元素:這僅適用於你想將abcde轉換為aecdb 在這種情況下, std::iter_swap在您喜歡的任何容器上使用std::iter_swap acdeb abcde轉換為acdeb ,請使用std::rotatelist::splice

如果您不必維護其他元素的順序,那么最簡單的解決方案無疑只是將您想要的元素與容器中的第一個元素交換。 這對所有容器都有效。

否則, std::list提供可以使用的splice操作。 我認為如下:

void
moveToFront( 
    std::list<MyType>& list,
    std::list<MyType>::iterator element )
{
    if ( element != list.begin() ) {
        list.splice( list.begin(), list, element, std::next( element ) );
    }
}

這應該只有幾個指針操作,而不是副本。 另一方面, std::list一般來說可能非常慢(因為它的局部性很差); 我會非常小心地使用std::vector來衡量天真的實現,以確保它是一個全局的勝利。 如果迭代找到你想要移動到前面的元素,那么消除這里的所有副本可能不是一個勝利。 (這很大程度上取決於MyType復制的成本,以及它的大小。如果sizeof(MyType)接近頁面的大小,或者訪問MyType最終訪問了大量間接分配的對象,則locality參數不會舉行。)

使用std::vector ,而不是明顯的erase / insert

void
moveToFront( 
    std::vector<MyType>& list,
    std::vector<MyType>::iterator element )
{
    MyType tmp( *element );
    std::copy_backwards( list.begin(), std::prev( element ), element );
    *list.begin() = tmp;
}

這將導致比erase (復制以下所有元素) insert更少的副本(它還復制所有以下元素 - 這意味着所有元素,因為我們在開頭插入)模式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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