[英]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::rotate
或list::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.