Deque ve list STL kapsayıcıları arasındaki fark nedir?


101

İkisi arasındaki fark nedir? Demek istediğim tüm yöntemler aynı. Yani, bir kullanıcı için aynı şekilde çalışırlar.

Bu doğru mu??


1
yineleme performansıyla ilgileniyorum .. baştan sona yinelemek için daha hızlı ne olabilir?
nkint

Yanıtlar:


63

(Tarihli ama yine de çok kullanışlı) SGI STL özetinden deque:

Bir deque, bir vektöre çok benzer: vektör gibi, öğelere rastgele erişimi, dizinin sonunda öğelerin sabit zamanda eklenmesini ve kaldırılmasını ve ortadaki öğelerin doğrusal zaman eklenmesini ve kaldırılmasını destekleyen bir dizidir.

Deque'in vektörden farklı olmasının ana yolu, deque'in aynı zamanda dizinin başlangıcında öğelerin sabit zamanda eklenmesini ve kaldırılmasını desteklemesidir. Ek olarak, deque vektörün kapasitesine () ve rezervine () benzer üye işlevlere sahip değildir ve bu üye işlevlerle ilişkili yineleyici geçerliliğine ilişkin garantilerin hiçbirini sağlamaz.

İşte listaynı sitenin özeti :

Liste, çift bağlantılı bir listedir. Yani, hem ileri hem de geri geçişi ve (amortize edilmiş) öğelerin başlangıçta veya sonda veya ortada sabit zamanlı yerleştirilmesini ve kaldırılmasını destekleyen bir Sıradır. Listeler, ekleme ve eklemenin öğeleri listelemek için yineleyicileri geçersiz kılmaması ve kaldırmanın bile yalnızca kaldırılan öğelere işaret eden yineleyicileri geçersiz kılması gibi önemli bir özelliğe sahiptir. Yineleyicilerin sıralaması değiştirilebilir (yani, list :: yineleyicinin bir liste işleminden sonra daha önce olduğundan farklı bir öncülü veya halefi olabilir), ancak yineleyiciler geçersiz kılınmayacak veya bu geçersiz kılma olmadığı sürece farklı öğeleri işaret edecek şekilde yapılmayacaktır. veya mutasyon açıktır.

Özet olarak, konteynerler paylaşılan rutinlere sahip olabilir, ancak bu rutinler için garanti süresi konteynerden konteynere farklılık gösterir . Bu kapsayıcılardan hangisinin bir görev için kullanılacağını düşünürken bu çok önemlidir: kapsayıcının en sık nasıl kullanılacağını hesaba katmak (örneğin, ekleme / silme yerine arama için daha fazla) sizi doğru kaba yönlendirmede uzun bir yol kat eder .


2
std :: list ayrıca iki listeyi birleştirmenize izin veren 'splice' yöntemine de sahiptir
Rick

25
Aslında zaman garantileri listenin en önemli ikinci özelliğidir. En listenin önemli özelliği ekleyip unsurları kaldırmak ve yineleyicinızı geçersiz olabilir! Diğer tüm STL konteynerlerinde (neredeyse?), Her düzenleme işlemi tüm yineleyicilerinizi geçersiz kılar - bu nedenle "eşleşen öğeleri silmek" için eşleşen öğeleri bir işlemde biriktirmeniz ve ardından bunları başka bir işlemde silmeniz gerekir. Bir listede, üzerinde gezinebilir, istediğiniz gibi kaldırabilir ve ekleyebilir ve bir yineleyiciyi asla yeniden hesaplamanız gerekmez.
Tom Swirly

2
Bunlar aynı zamanda soyut farklılıklardır, bu nedenle davanız için gerçekliği ölçün! Hem list hem de deque'de O (1) ekleme / silme vardır, ancak bunun k * O (1) anlamına geldiğini ve k'nin list ve deque için farklı değerlere sahip olduğunu unutmayın. Benim durumumda, listeye bir nesne eklemek bir deque'den on kat daha uzun sürdü çünkü listenin yeni / sil için daha fazla çağrıya ihtiyacı vardı. Bu, sahip olduğunuz STL uygulamasına bağlı olarak açıkça değişecektir.
Andy Krouwel

134

Farklılıkları listeleyeyim:

  • Deque , elemanlarını dinamik bir diziyle yönetir, rastgele erişim sağlar ve bir vektörle neredeyse aynı arayüze sahiptir.
  • Liste , öğelerini çift ​​bağlantılı bir liste olarak yönetir ve rastgele erişim sağlamaz .

  • Deque , hem sonunda hem de başında Hızlı eklemeler ve silmeler sağlar. Ortaya eleman eklemek ve silmek nispeten yavaştır, çünkü her iki uçtan birine kadar olan tüm elemanlar yer açmak veya bir boşluğu doldurmak için hareket ettirilebilir.
  • In List , ekleme ve unsurları kaldırarak iki ucunda dahil olmak üzere her pozisyonda en hızlı.

  • Deque : Başlangıç ​​veya son dışındaki öğelerin herhangi bir şekilde eklenmesi veya silinmesi, deque öğelerine atıfta bulunan tüm işaretçileri, referansları ve yineleyicileri geçersiz kılar.
  • Liste : Öğelerin eklenmesi ve silinmesi, diğer öğelere yönelik işaretçileri, referansları ve yineleyicileri geçersiz kılmaz.

Karmaşıklık

             Insert/erase at the beginning       in middle        at the end

Deque:       Amortized constant                  Linear           Amortized constant
List:        Constant                            Constant         Constant

6
@aJ: constantve arasındaki fark nedir amortized constant?
Lazer

18
Uzun vadede operasyonlar anlatıldığı gibi davranır. Ancak tek bir işlem belirtilenden daha uzun sürebilir. Ör: mevcut kapasitesi 10 olan ve boyutu zaten 9 olan bir vektöre bir eleman eklemek için, burada kapasite 10 ve boyut da 10 ise zaman doğrusaldır. Bunun nedeni, tüm elemanları yeni belleğe ayırması ve kopyalaması gerektiğidir. .
aJ.

5
@aJ: deque rastgele erişimi nasıl sağlar? Ayrıca bu yapı nasıl uygulanır?

11

std::list temelde çift bağlantılı bir listedir.

std::dequedaha çok benziyor std::vector. Dizine göre sabit erişim süresinin yanı sıra başında ve sonunda ekleme ve çıkarma özelliği vardır, bu da bir listeden önemli ölçüde farklı performans özellikleri sağlar.


6

Bir diğer önemli garanti, her bir farklı kabın verilerini bellekte saklama şeklidir:

  • Bir vektör, tek bir bitişik bellek bloğudur.
  • Bir deque, her bellek bloğunda birden fazla elemanın depolandığı bir dizi bağlantılı bellek bloğu grubudur.
  • Bir liste, belleğe dağılmış bir dizi öğedir, yani: bellek "bloğu" başına yalnızca bir öğe saklanır.

Deque tasarlanmıştır Not deneyin kendi dezavantajları iki vektör ve listenin avantajı denge. Mikro denetleyiciler gibi bellek sınırlı platformlarda özellikle ilginç bir kaptır.

Bellek depolama stratejisi genellikle göz ardı edilir, ancak belirli bir uygulama için en uygun kabı seçmenin en önemli nedenlerinden biridir.


4

Hayır. A deque, sadece önden ve arkadan O (1) ekleme ve silme işlemini destekler. Örneğin, etrafını saran bir vektörde uygulanabilir. Aynı zamanda O (1) rasgele erişimi garanti ettiğinden, (sadece) çift bağlantılı bir liste kullanmadığından emin olabilirsiniz.


2

Arasındaki seçkin farklar arasında dequevelist

  • Şunun için deque:

    Yan yana depolanan ürünler;

    İki taraftan (ön, arka) veri eklemek için optimize edilmiştir;

    Sayılarla (tam sayılar) indekslenen öğeler.

    Yineleyiciler ve hatta eleman indeksi ile göz atılabilir.

    Verilere erişim süresi daha hızlıdır.

  • İçin list

    Hafızada "rastgele" saklanan öğeler;

    Yalnızca yineleyiciler tarafından göz atılabilir;

    Ortaya yerleştirme ve çıkarma için optimize edilmiştir.

    Verilere erişim süresi daha yavaştır, uzamsal konumunun çok zayıf olması nedeniyle yinelenmesi yavaştır.

    Büyük parçaları çok iyi idare eder

Ayrıca, iki STL kabı arasındaki performansı karşılaştıran aşağıdaki Bağlantı'yı da kontrol edebilirsiniz (std :: vector ile)

Umarım bazı faydalı bilgiler paylaşmışımdır.


1

Performans farklılıkları başkaları tarafından iyi açıklanmıştır. Nesne yönelimli yazılım yazma genel metodolojisinin bir parçası olan nesne yönelimli programlamada benzer ve hatta aynı arabirimlerin yaygın olduğunu eklemek istedim. HİÇBİR ŞEKİLDE, iki sınıfın aynı arayüzü uyguladıkları için aynı şekilde çalıştığını varsaymalısınız, at bir köpek gibi çalıştığını varsaymanız gerekenden daha fazlasını çünkü ikisi de attack () ve make_noise () uygular.


1

İşte listenin kavram kanıtı kodu kullanımı, O (1) arama ve O (1) tam LRU bakımı sağlayan ölçülmemiş harita. Silme işlemlerinden kurtulmak için (silinmeyen) yineleyicilere ihtiyaç duyar. GPU belleğindeki CPU işaretçileri için isteğe bağlı olarak büyük yazılımla yönetilen bir O (1) önbellekte kullanmayı planlayın. Linux O (1) zamanlayıcısına selam verir (işlemci başına LRU <-> çalıştırma kuyruğu). Unordered_map, hash tablosu aracılığıyla sabit zamanlı erişime sahiptir.

#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;
} 

Bunu doğru yere mi gönderdin? Bu sorunun cevabı değil.
Blastfurnace
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.