2つの違いは何ですか?つまり、方法はすべて同じです。したがって、ユーザーにとっては、それらは同じように機能します。
あれは正しいですか??
回答:
の(時代遅れだがまだ非常に有用な)SGI STLの要約からdeque
:
両端キューはベクトルに非常に似ています。ベクトルと同様に、要素へのランダムアクセス、シーケンスの最後での要素の一定時間の挿入と削除、および途中での要素の線形時間の挿入と削除をサポートするシーケンスです。
dequeがvectorと異なる主な方法は、dequeがシーケンスの先頭での要素の一定時間の挿入と削除もサポートすることです。さらに、dequeには、vectorのcapacity()およびreserve()に類似したメンバー関数がなく、これらのメンバー関数に関連付けられているイテレーターの有効性に関する保証はありません。
これlist
は同じサイトからの要約です:
リストは二重にリンクされたリストです。つまり、順方向と逆方向の両方のトラバーサル、および要素の最初または最後、または途中での(償却された)一定時間の挿入と削除をサポートするシーケンスです。リストには、挿入とスプライシングによって要素をリストするためのイテレーターが無効にならないという重要な特性があり、削除によっても、削除される要素を指すイテレーターのみが無効になるという特性があります。イテレータの順序は変更される可能性があります(つまり、list :: iteratorは、リスト操作の前と後の結果が以前とは異なる場合があります)。または突然変異は明示的です。
要約すると、コンテナはルーチンを共有している可能性がありますが、これらのルーチンの時間保証はコンテナごとに異なります。これは、これらのコンテナーのどれをタスクに使用するかを検討する場合に非常に重要です。コンテナーが最も頻繁に使用される方法(たとえば、挿入/削除よりも検索に使用)を考慮すると、正しいコンテナーに移動するのに役立ちます。
違いをリストアップしましょう:
複雑
Insert/erase at the beginning in middle at the end
Deque: Amortized constant Linear Amortized constant
List: Constant Constant Constant
constant
とはamortized constant
?
std::list
基本的には二重にリンクされたリストです。
std::deque
一方、はのように実装されますstd::vector
。インデックスごとに一定のアクセス時間があり、最初と最後に挿入と削除があるため、リストとは劇的に異なるパフォーマンス特性を提供します。
もう1つの重要な保証は、各コンテナーがデータをメモリに保存する方法です。
両端キューは、ベクターとリストの両方の利点をそれぞれの欠点なしにバランスさせるように設計されていることに注意してください。これは、マイクロコントローラなど、メモリが限られたプラットフォームで特に興味深いコンテナです。
メモリストレージ戦略は見過ごされがちですが、特定のアプリケーションに最適なコンテナを選択することは、多くの場合最も重要な理由の1つです。
いいえ。両端キューはO(1)の挿入と削除のみを前後でサポートします。たとえば、ラップアラウンドでベクターに実装できます。また、O(1)ランダムアクセスも保証されているため、二重リンクリストを(ただ)使用していないことを確認できます。
以下は、O(1)ルックアップとO(1)の正確なLRUメンテナンスを提供するリストの無秩序なマップの概念実証コードの使用です。消去操作を生き残るためには、(消去されていない)イテレータが必要です。GPUメモリ上のCPUポインター用のO(1)の任意の大きなソフトウェア管理キャッシュでの使用を計画します。Linux O(1)スケジューラーへの同意(プロセッサーごとのLRU <->実行キュー)。unordered_mapは、ハッシュテーブルを介して一定時間アクセスします。
#include <iostream>
#include <list>
#include <unordered_map>
using namespace std;
struct MapEntry {
list<uint64_t>::iterator LRU_entry;
uint64_t CpuPtr;
};
typedef unordered_map<uint64_t,MapEntry> Table;
typedef list<uint64_t> FIFO;
FIFO LRU; // LRU list at a given priority
Table DeviceBuffer; // Table of device buffers
void Print(void){
for (FIFO::iterator l = LRU.begin(); l != LRU.end(); l++) {
std::cout<< "LRU entry "<< *l << " : " ;
std::cout<< "Buffer entry "<< DeviceBuffer[*l].CpuPtr <<endl;
}
}
int main()
{
LRU.push_back(0);
LRU.push_back(1);
LRU.push_back(2);
LRU.push_back(3);
LRU.push_back(4);
for (FIFO::iterator i = LRU.begin(); i != LRU.end(); i++) {
MapEntry ME = { i, *i};
DeviceBuffer[*i] = ME;
}
std::cout<< "************ Initial set of CpuPtrs" <<endl;
Print();
{
// Suppose evict an entry - find it via "key - memory address uin64_t" and remove from
// cache "tag" table AND LRU list with O(1) operations
uint64_t key=2;
LRU.erase(DeviceBuffer[2].LRU_entry);
DeviceBuffer.erase(2);
}
std::cout<< "************ Remove item 2 " <<endl;
Print();
{
// Insert a new allocation in both tag table, and LRU ordering wiith O(1) operations
uint64_t key=9;
LRU.push_front(key);
MapEntry ME = { LRU.begin(), key };
DeviceBuffer[key]=ME;
}
std::cout<< "************ Add item 9 " <<endl;
Print();
std::cout << "Victim "<<LRU.back()<<endl;
}
との顕著な違いの間deque
でlist
の場合deque
:
並べて保管されるアイテム。
2つの側面(前面、背面)からデータを追加するために最適化されています。
数値でインデックス付けされた要素(整数)。
イテレータや要素のインデックスでさえ参照できます。
データへの時間アクセスが高速です。
ために list
メモリに「ランダムに」格納されたアイテム。
イテレータのみが閲覧できます。
真ん中の挿入と削除に最適化されています。
空間的な局所性が非常に低いため、データへの時間アクセスは遅く、反復に時間がかかります。
非常に大きな要素を処理します
2つのSTLコンテナー間のパフォーマンスを比較する次のLinkも確認できます(std :: vectorを使用)
私はいくつかの有用な情報を共有したいと思います。