JavaScript dizilerinin büyük O'su


105

JavaScript'teki dizilerin öğe ekleyip çıkararak değiştirilmesi çok kolaydır. Bir şekilde çoğu dil dizisinin sabit boyutlu olduğu ve yeniden boyutlandırmak için karmaşık işlemler gerektirdiği gerçeğini maskeliyor. Görünüşe göre JavaScript, düşük performanslı dizi kodu yazmayı kolaylaştırıyor. Bu soruya yol açar:

Dizi performansı açısından JavaScript uygulamalarından (büyük O zamanı karmaşıklığı açısından) ne tür bir performans bekleyebilirim?

Tüm makul JavaScript uygulamalarının en fazla aşağıdaki büyük O'lara sahip olduğunu varsayıyorum.

  • Erişim - O (1)
  • Ekleniyor - O (n)
  • Başa eklenen - O (n)
  • Ekleme - O (n)
  • Silme - O (n)
  • Değiştirme - O (1)

JavaScript, new Array(length)sözdizimini kullanarak bir diziyi belirli bir boyuta kadar önceden doldurmanıza olanak tanır . (Bonus soru: Bu şekilde bir dizi oluşturmak mı O (1) veya O (n)) Bu daha çok geleneksel bir dizi gibidir ve önceden boyutlandırılmış bir dizi olarak kullanılırsa, O (1) eklemeye izin verebilir. Dairesel arabellek mantığı eklenirse, önceden O (1) eklemeyi başarabilirsiniz. Dinamik olarak genişleyen bir dizi kullanılırsa, O (log n) her ikisi için de ortalama durum olacaktır.

Bazı şeyler için buradaki varsayımlarımdan daha iyi performans bekleyebilir miyim? Herhangi bir spesifikasyonda hiçbir şeyin ana hatlarıyla belirtilmesini beklemiyorum, ancak pratikte, tüm büyük uygulamaların perde arkasında optimize edilmiş diziler kullanması olabilir. Dinamik olarak genişleyen diziler veya başka performans artırıcı algoritmalar var mı?

PS

Bunu merak etmemin nedeni, bazı sıralama algoritmalarını araştırıyor olmam, bunların çoğu ekleme ve silme işlemlerinin genel olarak büyük O (O) işlemlerini açıklarken O (1) işlemleri olduğunu varsayıyor olmam.


6
Bir boyuta sahip Array yapıcısı, modern JavaScript uygulamalarında hemen hemen işe yaramaz. O tek parametreli formda neredeyse hiçbir şey yapmaz. (Ayarlıyor .lengthama bununla ilgili.) Diziler, düz Object örneklerinden pek de farklı değil.
Pointy

3
Özelliği ayarlamak lengthve alanı önceden tahsis etmek tamamen farklı iki şeydir.
Pointy

1
@Pointy: array[5]a ayarının new Array(10)O (1) olmasını beklediğimde çok fazla şey mi bekliyorum ?
Kendall Frey

1
ECMAScript yok iken değil (sadece bazı semantik kurallar tanımlar) bir Array nesnesi nasıl uygulanacağını tanımlayan, farklı uygulamalar, örneğin boyutunda çok az bir n daha az diziler için bir "gerçek dizi" desteğine sahip (beklenen durum için optimize olacağı çok mümkündür ). Uygulamalar konusunda o kadar

5
@KendallFrey "En iyi yanıt", muhtemelen farklı n / erişim kalıpları için bazı jsperf test durumları yazacak ve ne olduğunu

Yanıtlar:


111

NOT: Bu cevap 2012'de doğru olsa da, motorlar bugün hem nesneler hem de diziler için çok farklı dahili temsiller kullanıyor. Bu cevap doğru olabilir veya olmayabilir.

Dizilerle birlikte dizileri uygulayan çoğu dilin aksine, Javascript Dizileri nesnelerdir ve değerler, tıpkı normal nesne değerleri gibi bir hashtable'da saklanır. Gibi:

  • Erişim - O (1)
  • Ekleniyor - Amortize Edilmiş O (1) (bazen hashtable'ın yeniden boyutlandırılması gerekir; genellikle yalnızca ekleme gerekir)
  • Önceden ekleniyor - unshiftTüm dizinlerin yeniden atanmasını gerektirdiğinden O (n) aracılığıyla
  • Ekleme - Değer yoksa amortisman O (1). O (n) mevcut değerleri değiştirmek istiyorsanız (Örn splice. Kullanarak ).
  • Silme - Bir değeri kaldırmak için amortize edilmiş O (1), endeksleri yeniden atamak istiyorsanız O (n) splice.
  • Değiştirme - O (1)

Genel olarak, bir diktede herhangi bir anahtarın ayarlanması veya ayarının kaldırılması, O (1) olarak amorti edilir ve aynısı, indeksin ne olduğuna bakılmaksızın diziler için de geçerlidir. Mevcut değerlerin yeniden numaralandırılmasını gerektiren herhangi bir işlem O (n) 'dur çünkü etkilenen tüm değerleri güncellemeniz gerekir.


4
Başına O (n) eklenmemeli mi? Çünkü tüm endekslerin kaydırılması gerekiyor. Ekleme ve silme için aynıdır (keyfi dizinde ve öğeleri kaydır / daralt).
nhahtdh

2
Ayrıca, lengthArray mutasyonunda ayarlanmış mı, yoksa getuzunluğu alacak ve muhtemelen onu ezberleyecek mi?
alex

27
Bu yanıttan bahsetmeye değer artık doğru değil. Modern motorlar, seyrek olmadıkları sürece Dizileri (veya dizinlenmiş tamsayı anahtarları olan nesneleri) hashtable olarak (ama C'deki gibi diziler gibi) depolamaz. Başlamanıza yardımcı olmak için, bunu gösteren 'klasik' bir kriter
Benjamin Gruenbaum

4
Bu standart tarafından mı tanımlanıyor yoksa bu sadece JS motorlarında yaygın bir uygulama mı? V8 ne olacak?
Albert

4
@BenjaminGruenbaum Nasıl depolandıkları konusunda biraz geliştirebilirseniz iyi olur. Veya bazı kaynaklar verin.
Ced

1

garanti

Herhangi bir dizi işlemi için belirli bir zaman karmaşıklığı garantisi yoktur. Dizilerin nasıl performans göstereceği, motorun seçtiği temel veri yapısına bağlıdır. Motorlar ayrıca farklı temsillere sahip olabilir ve belirli buluşsal yöntemlere bağlı olarak aralarında geçiş yapabilir. İlk dizi boyutu bu kadar sezgisel olabilir veya olmayabilir.

gerçeklik

Örneğin, V8 (bugün itibariyle) kullanımları hem karışık tablolar ve dizi listeleri dizileri temsil etmek. Ayrıca nesneler için çeşitli farklı temsillere sahiptir, bu nedenle diziler ve nesneler karşılaştırılamaz. Bu nedenle dizi erişimi her zaman O (n) kadar iyidir ve hatta bir C ++ dizi erişimi kadar hızlı olabilir . Veri yapısının boyutuna ulaşmadığınız ve ölçeklenmesi gerekmediği sürece (O (n)), O (1) 'dir. Önceden harcama daha kötü. delete array[index]Motorun temsilini değiştirmeye zorlayabileceği için (yapma!) Gibi bir şey yaparsanız silme daha da kötü olabilir.

tavsiye

Sayısal veri yapıları için dizileri kullanın. Onlar bunun için var. Motorlar bunun için onları optimize edecek. Seyrek dizilerden kaçının (ya da gerekiyorsa, daha kötü performans bekleyin). Karma veri türlerine sahip dizilerden kaçının (bu, dahili gösterimleri daha karmaşık hale getirir ).

Belirli bir motor (ve sürüm) için gerçekten optimize etmek istiyorsanız , mutlak cevap için kaynak kodunu kontrol edin .


Bir saniye bekleyin, karışık veri türlerine sahip dizilerimiz olabilir mi? Javascript çok havalı!
Anurag

@Anurag tam olarak, ancak vakaların% 99'unda bu özelliğe ihtiyacınız olmaz
Desiigner
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.