Neden vektörü kullanarak deque


87

Dan beri

  1. her ikisi de bitişik bellek kapsayıcılarıdır;
  2. özellik açısından deque, vektörün sahip olduğu hemen hemen her şeye ama daha fazlasına sahiptir, çünkü öne yerleştirmek daha verimlidir.

Neden whould kimse tercih std::vectoretmek std::deque?


2
Visual C ++ uygulamasının std::dequeçok küçük bir maksimum blok boyutu var (~ 16 bayt, doğru hatırlıyorsam; belki 32) ve bu nedenle gerçekçi uygulamalar için çok iyi performans göstermiyor. Bir deque<T>nerede sizeof(T) > 8(veya 16? Bu küçük bir sayı), vector<T*>her bir öğenin dinamik olarak tahsis edildiği a ile yaklaşık aynı performans özelliklerine sahiptir . Diğer uygulamalar farklı maksimum blok boyutlarına sahiptir, bu nedenle farklı platformlarda nispeten aynı performans özelliklerine sahip kod yazmak zordur deque.
James McNellis

13
Deque, sürekli bir bellek kabı değildir.
Mohamed El-Nakib

@ravil Hayır, bu soruya işaret eden kopya bu.

1
Bir sabitlenmemiş bariz olgusal hata ile bir soru 34 oy denge oturuyordu inanmak zor
underscore_d

2
@underscore_d bu yüzden bir soru. Cevapsa farklı hikaye;)
Assimilater

Yanıtlar:


115

Bir Elements dequeolan olmayan bellekte bitişik; vectorelemanların olması garantilidir. Dolayısıyla, bitişik dizilere ihtiyaç duyan düz bir C kitaplığıyla etkileşime girmeniz gerekiyorsa veya uzamsal yerelliği (çok) önemsiyorsanız, o zaman tercih edebilirsiniz vector. Ek olarak, ekstra defter tutma olduğu için, diğer operasyonlar muhtemelen eşdeğer vectoroperasyonlarından (biraz) daha pahalıdır . Öte yandan, çok / büyük örneklerini kullanmak vector, gereksiz yığın parçalanmasına (çağrıları yavaşlatarak new) yol açabilir .

Ayrıca, StackOverflow'da başka bir yerde belirtildiği gibi , burada daha iyi tartışma var: http://www.gotw.ca/gotw/054.htm .


3
Görünüşe göre "başka bir yer" bağlantısı artık kesildi (ılımlılık nedeniyle mi?).
esilk

37

Farkı bilmek dequeiçin genel olarak nasıl uygulandığını bilmek gerekir . Bellek eşit büyüklükteki bloklar halinde tahsis edilir ve birbirlerine zincirlenir (bir dizi veya muhtemelen bir vektör olarak).

Yani n'inci elemanı bulmak için uygun bloğu bulup içindeki elemana erişirsiniz. Bu sabit zamandır, çünkü her zaman tam olarak 2 aramadır, ancak bu yine de vektörden fazladır.

vectorayrıca C API'leri oldukları veya bir işaretçi ve uzunluk almada daha çok yönlü oldukları için bitişik bir arabellek isteyen API'lerle de iyi çalışır. (Böylece altında bir vektöre veya normal bir diziye sahip olabilir ve bellek bloğunuzdan API'yi çağırabilirsiniz).

Nerede dequebulunur en büyük avantajları vardır:

  1. Koleksiyonu her iki uçtan büyütürken veya küçültürken
  2. Çok büyük koleksiyon boyutlarıyla uğraşırken.
  3. Bool'larla uğraşırken ve gerçekten bir bit seti yerine bools istersiniz.

Bunlardan ikincisi daha az bilinir, ancak çok büyük koleksiyon boyutları için:

  1. Yeniden dağıtımın maliyeti büyük
  2. Bitişik bir bellek bloğu bulma zorunluluğu kısıtlayıcıdır, bu nedenle belleğiniz daha hızlı tükenebilir.

Geçmişte büyük koleksiyonlarla uğraşırken ve bitişik bir modelden bir blok modele geçtiğimde, 32 bitlik bir sistemde bellek dolmadan önce yaklaşık 5 kat daha büyük bir koleksiyon depolayabildik. Bunun nedeni kısmen, yeniden tahsis ederken, eski bloğu ve yeni bloğu, öğeleri kopyalamadan önce depolaması gerektiğidir.

Tüm bunları söyledikten sonra, std::deque"iyimser" bellek tahsisi kullanan sistemlerde sorun yaşayabilirsiniz . A'nın yeniden tahsisi için büyük bir tampon boyutu talep etme girişimleri vectormuhtemelen bir noktada a ile reddedilse de bad_alloc, ayırıcının iyimser doğası muhtemelen a tarafından talep edilen daha küçük tampon için talebi dequekarşılayacaktır ve bu muhtemelen işletim sistemi bir işlemi öldürmek için bir miktar bellek elde etmeye çalışır. Hangisini seçerse seçsin pek hoş olmayabilir.

Böyle bir durumda geçici çözümler iyimser tahsisi geçersiz kılmak için sistem düzeyinde bayrakları ayarlamak (her zaman mümkün değildir) veya belleği biraz daha manuel olarak yönetmek, örneğin bellek kullanımını kontrol eden kendi ayırıcınızı veya benzerini kullanmaktır. Açıkçası ideal değil. (Sorunuza vektörü tercih etme konusunda cevap verebilir ...)


30

Hem vektör hem de deque'i birçok kez uyguladım. deque, uygulama açısından çok daha karmaşıktır. Bu karmaşıklık, daha fazla koda ve daha karmaşık koda dönüşür. Dolayısıyla, vektör yerine geri döndürmeyi seçtiğinizde genellikle bir kod boyutunun isabet ettiğini görürsünüz. Kodunuz yalnızca vektörün üstün olduğu şeyleri (yani geri itme) kullanırsa, küçük bir hız vuruşu yaşayabilirsiniz.

Çift uçlu bir sıraya ihtiyacınız varsa, deque açık ara kazanır. Ancak, ekleme ve silme işlemlerinin çoğunu arka tarafta yapıyorsanız, vektör açık ara kazanan olacaktır. Emin olmadığınızda, kapsayıcınızı bir typedef ile bildirin (böylece ileri geri geçiş yapmak kolaydır) ve ölçün.


3
Soru - komite, C ++ 'ya ikisinin bir melezini (örneğin, bir "deste") eklemeyi düşündü mü? (yani uçlu çift vector.) Ben aşağıda bağlantılı bir uygulama yazdım Cevabıma . O kadar hızlı olabilir, vectorancak çok daha yaygın olarak uygulanabilir (örneğin, hızlı bir kuyruk oluştururken).
user541686

5

std::dequegarantili sürekli belleğe sahip değildir - ve dizinli erişim için genellikle biraz daha yavaştır. Bir deque tipik olarak bir "vektör listesi" olarak uygulanır.


14
Bir "vektör listesi" nin doğru olduğunu düşünmüyorum: Benim anlayışım, çoğu uygulamanın "dizilere işaretçilerin vektörü" olduğuydu, ancak bu sizin "liste" tanımınıza bağlıdır ("list" i "bağlantılı liste" olarak okudum , "karmaşıklık gereksinimlerini karşılamayacak.)
James McNellis

2

Http://www.cplusplus.com/reference/stl/deque/ 'e göre , "vektörlerin aksine, dekorların tüm öğelerinin bitişik depolama konumlarında olması garanti edilmez, bu nedenle işaretçi aritmetikleri aracılığıyla güvenli erişim olasılığını ortadan kaldırır."

Deques'lar biraz daha karmaşıktır, çünkü kısmen bitişik bir bellek düzenine sahip olmadıkları için. Bu özelliğe ihtiyacınız varsa, deko kullanmamalısınız.

(Önceden, cevabım standardizasyon eksikliğini ortaya çıkardı (yukarıdaki ile aynı kaynaktan, "sıralar belirli kütüphaneler tarafından farklı şekillerde uygulanabilir"), ancak bu aslında hemen hemen her standart kütüphane veri türü için geçerliydi.)


5
std::dequedaha az standart değildir std::vector. std::dequeBitişik depolamayla karmaşıklık gereksinimlerinin karşılanabileceğine inanmıyorum .
Jerry Coffin

1
Belki de ifadem zayıftı: anladığım kadarıyla standardizasyonun tam olmadığı doğru olsa da, vektörler eşzamanlı bir dizi olacak şekilde standartlaştırıldı ve deques'ler değil. Tek belirleyici faktör bu gibi görünüyor.
pattivacek

1
@JerryCoffin: dequeBitişik depolamayla hangi karmaşıklık gereksinimleri karşılanamıyor?
user541686

1
@Mehrdad: Dürüst olmak gerekirse aklımda ne olduğunu hatırlamıyorum. Son zamanlarda standardın o kısmına yeterince bakmadım ki, önceki yorumumun yanlış olduğunu kategorik olarak ifade etmekte rahat hissediyorum, ancak şu anda ona baktığımda, nasıl doğru olacağını da düşünemiyorum.
Jerry Coffin

3
@JerryCoffin: Karmaşıklık gereksinimleri aslında önemsiz: büyük bir dizi ayırabilir ve dizinizi ortadan dışarıya doğru itmeye başlayabilirsiniz (sanırım Mehrdad uygulamasının yaptığı şey budur), sonra sonuna geldiğinizde yeniden tahsis edebilirsiniz. Bu yaklaşımla ilgili sorun, şu gerekliliklerden birini deque, yani uçlara yerleştirmenin mevcut elemanlara atıfta bulunulan geçersiz kılmamasıdır . Bu gereksinim, süreksiz bellek anlamına gelir.
Yakov Galka

0

Bir deque, öğelerine rastgele erişime izin veren bir sıra kapsayıcısıdır, ancak bitişik depolamaya sahip olması garanti edilmez.


0

Her vakanın performansını test etmenin iyi bir fikir olduğunu düşünüyorum. Ve bu testlere dayanarak karar verin.

Ben tercih ediyorum std::dequedaha std::vectorçoğu durumda.


1
Gerçek hatalar ve eksik kelimeler arasından herhangi bir şey ayrıştırılabilecek bir soru, birinin neden tercih edeceğiydi vector. Bunun neden böyle olmadığını anlayabiliriz . dequeBilinmeyen nedenlerle, belirsiz testlerden tercih ettiğinizi söylemek bir cevap değildir.
underscore_d


0

Bir yandan, vektör oldukça sıklıkla deque'den daha hızlıdır. Deque'in tüm özelliklerine gerçekten ihtiyacınız yoksa bir vektör kullanın.

Öte yandan, bazen vektörün size vermediği özelliklere ihtiyaç duyarsınız, bu durumda bir deque kullanmanız gerekir. Örneğin, herhangi birini bir deque kullanmadan ve algoritmayı çok fazla değiştirmeden bu kodu yeniden yazmaya çalışmaya davet ediyorum .


Aslında, aynı seri push_backve pop_backoperasyonlarda deque<int>her zaman vector<int>testlerimden (O3 ile gcc) en az% 20 daha hızlıdır . Sanırım bu yüzden dequeböyle şeyler için standart seçim std::stack...
igel

-1

Dizi büyüdükçe vektör belleğinin yeniden tahsis edildiğini unutmayın. Öğeleri vektör yapmak için işaretçileriniz varsa, bunlar geçersiz hale gelecektir.

Ayrıca, bir öğeyi silerseniz yineleyiciler geçersiz olur (ancak "for (auto ...)" değil).

Düzenleme: "deque", "vektör" olarak değiştirildi


-1: Başlangıçta veya sonda ekleme ve silme, diğer öğelere yönelik referansları ve işaretçileri geçersiz kılmaz. (Ortaya yerleştir ve sil)
Sjoerd

@Sjoerd 'vektör' olarak değiştirdim.
Pierre
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.