Vektör / liste ne zaman kullanılmalıdır?


17

Listeleri ne zaman kullanacağımı anlayabiliyorum, ancak vektörleri ne zaman kullanmanın video oyunlarında listeleri kullanmaktan daha iyi olduğunu anlamıyorum: hızlı rasgele erişime sahip olmak daha iyidir?

(Ve listelere eklemenin / silmenin neden daha hızlı olduğunu anlıyorum çünkü sadece işaretçileri kaldırıyor / ekliyor, ancak yine de karşılık gelen öğeyi bulması gerekiyor ...)


Buna vektör etiketi yeniden eklendi - liste geçerli bir etiketse, vektör de öyle.
Kylotan

Muhtemelen vektör çıkarılmıştır, çünkü std :: vector değil, matematiksel vektör anlamına gelir.

1
ikisini de karıştırmaya ve koymaya ne dersin container?
deft_code

@Kylotan: Joe'nun dediği gibi. Bu soru kesinlikle vektörlerle ilgiliydi, ancak vektör etiketine ait değildi.
doppelgreener

1
Belirsiz bir etiketi kaldırır mıyız? Bu benim için yanlış bir karara benziyor - aramanızın çok fazla bilgi bulması daha iyi. Eşanlamlıları bulmak için istenmeyen sonuçları atlamak beyin fırtınasından daha kolaydır.
Kylotan

Yanıtlar:


29

Genel kuralım ve eminim ki bu konuda tartışmalar olacaktır, asla listeler kullanmak değildir (büyük listelerin ortasından çok, çok sık bir şeyleri kaldırmanız gerekmedikçe).

Konteynırdaki tüm öğelerinizi bitişik bellekte (ve dolayısıyla daha fazla önbellek dostu) alarak kazanacağınız hız, vektör ekleme / çıkarma / yeniden boyutlandırma ek maliyetlerinin dengelenmesine değer.

Düzenleme: Sadece biraz daha açıklığa kavuşturmak için, tabii ki "hangi daha hızlı" sorusunun herhangi bir tür özel ihtiyaçları için ne olursa olsun veri setleri ile herhangi bir platformda test edilmesi gerektiğini söylemeden gitmek gerekir. Sadece bir eleman koleksiyonuna ihtiyacım varsa, vektörü (ya da neredeyse aynı şey olan deque'yi) kullanmamam için iyi bir neden yoksa kullanırım.


1
Bence bu sizin ihtiyaçlarınıza bağlıdır, eğer belirli bir elemana asla erişmeniz gerekmiyorsa ve hepsini okumanız gerekiyorsa ve öğeleri sık sık ekleyip kaldırıyorsanız, liste daha iyi bir çözümdür.
Frédérick Imbeault

11
@ Frédérick: Bu standart C ++ bilgeliği, ama aynı zamanda neredeyse her zaman yanlış. Vektörler, özellikle de işaretçiler vektörleri ile uğraşırken (neredeyse her zaman oyunlar için olan), bir şeyleri ortadan kaldırmak için son derece hızlıdır - doğrusal bir zamandır, ancak öğe başına çok çok küçük bir ek yüktür. Ayrıca , bir vektör üzerinde sırayla yineleme yapmak çok daha hızlıdır.

1
Tam olarak ne tür bir yapıya sahip olduğunuzdan emin değilim - bu tür bir optimizasyon, kesin bir şey söylemek için somut örnekler gerektirir. Örneğin, kullanım durumunuza ilk tepkim, eşit derecede hızlı yerleştirme, silme ve aramaya olanak tanıyan sıralanmamış bir küme olacaktır; benim deneyim setleri editörlerde nesneler için mükemmeldir. Ancak editörlerin çok daha gerçek zamanlı performans gereksinimleri olduğu için - örneğin, "Sil" düğmesine basmak yanıt vermek saniyenin 1 / 20'sini alıyorsa veya zamanın% 10'unun 1 / 2'sini alıyorsa iyi olur - bu optimizasyon seviyesi nadiren onlar için de geçerlidir.

1
@ Frédérick Imbeault Değiştirilmiş bir sorun değil, sorun yaratan Ekle \ Kaldır. Ekle \ kaldırıldı noktasından vektörün sonuna kadar vektör bitişik kalmak için kopyalanır. Öğe sırası önemli değilse, silinen öğeyi son öğeyle değiştirebilir, ardından silmek için bu öğeyi pop ve ekleme için sonuna ekleyebilirsiniz.
stonemetal

4
Elbette, bir vektördeki bir öğenin adresini almak ve bunu saklamak güvenli değildir. Ancak genel olarak konuşursak, bunu yapmak neredeyse hiç yapmaz, bunun yerine bir eleman işaretçisi vektörüne sahip olmayı ve işaretçiyi etrafına kopyalamayı (veya benzer bir şeyi) tercih eder.
Tetrad

8

Veri yapınızın ortasını değiştirmenin neden olduğu yineleyici geçersiz kılmasının bir soruna neden olacağı bir liste kullanın veya hızlı orta toplama silmeleri için takas ve pop hile işe yaramayacak ve büyük bir ortadaki toplama sayısı silinir.

Deque kullanmayı da düşünebilirsiniz. Bir vektöre benzer performans özelliklerine sahiptir, ancak vektörün bitişik hafızaya ihtiyacı yoktur ve biraz daha esnektir.


Deques'den bahseten tek kişi olmak için +1 - her iki uçta hızlı ekleme / çıkarma ile vektörlerin bitişik bellek ve arama hızı avantajlarını elde edersiniz.

5

Seçiminiz ihtiyaçlarınızı yansıtmalıdır. Vektörlerin tüm öğeleri bellekte süreklidir ve listeler sonraki / önceki öğelere işaret eder, böylece her birinin avantajları / dezavantajları vardır:

Listeler:

  • Her öğe, önceki ve sonraki öğeleri işaret etmek için 2 tamsayı alır, bu nedenle en yaygın olarak, listenizdeki her öğe için 8 bayt daha fazladır
  • Kesici uç zamanla doğrusal: O (n)
  • Kaldır sabit bir işlemdir: O (1)
  • X öğesine erişim zaman içinde doğrusaldır: O (n)

Vektörler:

  • Daha az hafızaya ihtiyaç duyar (diğer öğelere işaret yoktur, basit bir matematik algoritmasıdır)
  • Kaldırma süresi doğrusal: O (n)
  • X elemanına erişim sabittir: O (1) (Bunun nedeni elemanların bellekte sürekli olmasıdır, bu yüzden basit bir matematik işlemi vectorPtr + (x * bytesOfTheType))
  • Ekleme doğrusal zamanda olabilir, ancak en yaygın olarak sabit bir işlemdir: O (1) (Bunun nedeni bir dizideki vektörün, ancak dizi dolduğunda her zaman kapasitesinin 2 katını ayırmasıdır, böylece dizi kopyası sık değildir)

Bu nedenle, programın öğeleri sık sık eklemesi ve kaldırması gerektiğinde, ancak daha önce diğerlerine ihtiyaç duymadan belirli bir öğeye asla erişmeyin (veya nadiren erişin). Vektör daha iyi erişim süresi için kullanılmalıdır, ancak elemanları çıkarmanız veya eklemeniz gerektiğinde etkinlikten yoksundur.

Stackoverflow'daki bu gönderiyi kontrol edin, ihtiyaçlarınızla ilgili temel soruları içeren, cevaplarınıza bağlı olarak sizi belirli bir konteynere yönlendiren gerçekten güzel bir grafik sunar:

/programming/366432/extending-stdlist


3
Bu grafik gerçekten "İşaretçiler mi saklıyorsunuz ve binden az mı?" Hayır -> vektör "düğümü ile başlamalıdır.

Evet belki haklısın, saklanan tipin de analiz edilmesi gerektiğini düşünmedim.
Frédérick Imbeault

2

Genellikle listeler çok fazla ekleme ve kaldırma işlemi olan kuyruklar gibi yapılar için kullanılır. Örnek: Güncellenmesi gereken varlıkların sürekli listesi. Listenin kendisi yalnızca ekranda varlıkları içerir ve bu nedenle sık sık değişir.

Vektörler (veya diziler), çok fazla değişmeyen ve koleksiyon içindeki öğelere tek tek hızlı erişmeniz gereken bir koleksiyon için daha uygundur. Örnek: Belirli bir dizinde döşemeleri aramak zorunda olduğunuz döşeme haritası.

Tetrads'ın görüşü doğru olabilir, ancak kullanılan programlama diline bağlıdır. Sorunuzu etiketlediğinizi görüyorum c++, ancak dile özgü olmayan bir yanıt vermeye çalıştım.


Ben de C'yi koyabilirdim, ama C'de böyle kaplar yok, ama bu düşünülmesi gereken bir şey: C için STL benzeri bir tibrary var mı?
jokoon

Geçmişte C için bir dizi standart veri yapısı uygulayan glib ( library.gnome.org/devel/glib ) kullandım . Bundan nefret ediyorum çünkü genellikle çok ayrıntılı ve umutsuzca C ++ olmak istiyor, ancak olgun ve kararlı.

0

Konsol oyunlarında asla std :: list kullanmıyoruz çünkü:

  1. yeni bir öğe eklediğinizde bellek ayırmaları yapar. bellek ayırma yavaş.
  2. işaretçilerle dolu. işaretçiler kötü. bir işaretçi bir önbellek özledim. önbellek kaçırma kötü.

hatta std :: vector konsollarda iyilik kaybediyor çünkü:

  1. sık sık yalnızca tüm nesnelerin konumlarını önemsersiniz. örneğin, nesneleri birbirleriyle çarpıştırmak istiyorsunuz, bu durumda renklerinin ne olduğu umurumda değil. böylece tüm konumların bellekte bitişik olmasını ve önbelleğin kirlenmesini önlemek için renklerin başka bir yerde olmasını istersiniz. ancak std :: vector, her nesne için her şeyi bitişik bir bellek yığınına (örn. sonra konum, sonra renk) depolamanızı gerektirir, bu nedenle yalnızca konumları okuyan bir iş yaparsanız, tüm renkleri de önbelleğe okumalısınız, hatta eğer onları kullanmazsan. bu israftır.

5
@bmcnett "[] .. ancak std :: vector, her nesne için her şeyi bitişik bir bellek yığınında saklamanızı gerektirir" - bu konteynerin bir sorunu değildir, bu veri düzeninizin bir sorusudur, tüm pozisyonlara sahip olabilirsiniz bir std ile sürekli bir bellek struct point{float x, y, z, w}; std::vector<point> positions;
yığınına

okulum bunu sevecek :)
jokoon

2
-1 çünkü bu cevap listeye hiçbir şey eklemiyor ve burada vektör tartışmasına karşı ve Maik'in söylediği gibi önbelleği kirleten vektör ile ilgili iddiası yanlış.

iddiamı yanlış anladın. tüm kaplar arasında std :: vector özellikle önbelleği kirleten suçlu olduğunu söylemedim . tüm kaplar ve hatta aslında diziler de aynı ölçüde suçlu. std :: vector iyilikten düşüyor çünkü C ++ nesnelerinin kendileri iyilikten düşüyor. C ++ her nesnenin verilerinin bellekte bitişik olmasını zorunlu kılar. C ++ nesnelerinden kaçınarak bunun üstesinden gelebilirsiniz, örneğin yukarıda belirtildiği gibi std :: vector <position> kullanarak.
bmcnett

3
Dışında pointbir C ++ nesnesidir (olduğu std::vectorgibi basit bir şey gibi float). Çizmeye çalıştığınız ayrımı biliyorum, ama bunu açıklamakta kötü bir iş çıkarıyorsunuz.
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.