C # sözlüklerinin etkinliği


14

C # sözlükler vb bir şey varsa bulmak için basit bir yol vb. Nasıl çalıştıklarına rağmen bir sorum var. Diyelim ki sözlük yerine ArrayList kullanıyorum. Kullanmak ContainsKey(veya başka bir dilde eşdeğer bir yöntem) yerine, orada bir şey olup olmadığını kontrol etmek için ArrayList üzerinden döngü yapıyorum (veya veriler sıralanırsa veya benzer bir şey varsa ikili arama gerçekleştirir). Verimlilik farkı nedir? ContainsKeyYöntem anahtarlar arasında döngü yerine daha verimli bir şekilde kullanıyor mu ve ben ne aradığını kontrol edin?

Diyelim ki, sahip olduğum veri türüne karşılık gelen belirli bir hash fonksiyonu oluşturduğumu ve bu veri seti için özel olarak tasarlandığımı varsayalım, bu hash fonksiyonu gerçekten veriler arasında döngü yapmaktan daha hızlıdır. Ancak sözlükler geneldir. ContainsKey yöntemi aldığı verilere özgü değildir, genel bir arama yöntemidir.

Temelde sorduğum şey. Sözlükler programcılar için faydalıdır. Birçok şeye yardımcı olan yöntemler içerir ve dizeleri tamsayılarla (anahtarlar ve değerler) ve çok daha fazlasını birleştirir. Ancak verimlilik konusunda ne sunuyorlar? Bir sahip olmanın ne fark dictionarybir vs ArrayListarasındastructs(string,int)


Burada elmaları portakallarla gerçekten karşılaştırıyorsunuz. Ben aradığınız anahtar kelime olduğunu düşünüyorum Data Structures Bu wiki bağlantı size daha fazla yardımcı olabilir
Ampt

Yanıtlar:


23

Sözlük C # nasıl uygulandığını görmek için biraz kazmak zorunda - Bu HashMap (karma tablo) veya TreeMap (sıralanmış bir ağaç) (veya ConcurrentSkipListMap - bir atlama listesi ) kadar belirgin değil .

"Açıklamalar" bölümüne girerseniz:

Dictionary generic sınıfı, bir anahtar kümesinden bir değer kümesine eşleme sağlar. Sözlüğe her ekleme bir değer ve onunla ilişkili anahtardan oluşur. Bir sınıfı anahtarını kullanarak almak çok hızlıdır, O (1) 'e yakındır, çünkü Dictionary sınıfı bir karma tablosu olarak uygulanır.

Ve işte burada. Bu bir karma tablo . Wikipedia makalesini orada bağladığımı unutmayın - oldukça iyi bir okuma. Çarpışma çözümü ile ilgili bölümü okumak isteyebilirsiniz. Aramanın O (N) 'ye dönüştüğü patolojik bir veri seti elde etmek mümkündür (örneğin, eklediğiniz her şey bir nedenle karma tablosundaki aynı karma değerine veya dizine düşer ve doğrusal problama ile kalırsınız ).

Sözlük genel amaçlı bir çözüm olsa da, somut türlerden (Sözlük gibi) geçmemelisiniz - arayüzlerin etrafından geçmelisiniz. Bu durumda, bu arayüz IDictionary( dokümanlar ) ' dır . Bunun için, sahip olduğunuz veriler için işleri en iyi şekilde yapan kendi sözlük uygulamanızı mükemmel bir şekilde yazabilirsiniz.

Çeşitli arama verimliliği içerir / içerir?

  • Sıralanmamış bir listeye yürüme: O (N)
  • Sıralanmış bir dizinin ikili araması: O (log N)
  • Sıralanmış ağaç: O (log N)
  • Karma tablosu: O (1)

Çoğu insan için, hash tablosu istedikleri şeydir.

Sen bulabilirsiniz SortedDictionary yerine istediğim şey:

SortedDictionary<TKey, TValue>Jenerik sınıf n sözlükte eleman sayısıdır O (log n) alma, bir ikili arama ağacı. Bu bakımdan SortedList<TKey, TValue>jenerik sınıfa benzer . İki sınıf benzer nesne modellerine sahiptir ve her ikisinde de O (log n) alımı vardır.

Yine de, veri yapısı verilerinizle ideal olarak çalışan bir yapı değilse, verileriniz için en uygun olanı yazabilmeniz için size araçlar (arayüzler) verilir.

Sözlüğün kendisi soyut bir veri türüdür . Bana bir Sözlük veriyorsun ve bununla ne yapabileceğimi ve oradaki tüm araçları Sözlük olmanın doğası gereği kullanmam gerektiğini biliyorum. Bana bir ArrayList verdiyseniz, kendimi listeden öğeleri aramak, eklemek veya listeden silmek için kendi kodumu yazarken bulurdum. Bu, zamanımı boşa harcıyor ve aynı zamanda kodu tekrar tekrar kopyaladığım için bir hata için daha fazla olasılık olduğu anlamına geliyor.


5
O (1) mutlaka "hızlı" değildir. Bir liste boyunca döngü yapmak, uygulamanın ele aldığı koleksiyon boyutları için bir karma tablodan daha hızlı olabilir.
whatsisname

5
@whatsisname hiçbir noktada O (1) 'in hızlı olduğunu iddia etmiyorum. Kesinlikle en hızlı olma potansiyeline sahiptir. Bir hashtable'ın anahtarları üzerinde yineleme yapmak, ArrayList'in anahtarından daha yavaştır ( Java'nın sağladığı LinkedHashMap gibi bir şey kullanmıyorsanız ). Verilerinizi ve nasıl davrandığını bilmek ve ona uygun koleksiyonu seçmek önemlidir - ve eğer yoksa, yazın. Tabii ki, böyle bir çabanın aslında zaman ayırmaya değer olduğunu varsayarsak (önce profil!).

Teklifiniz "Anahtarını kullanarak bir değeri almak çok hızlıdır, O (1) 'e yakındır, çünkü Dictionary sınıfı bir karma tablosu olarak uygulanır.", Böylece OP iki kavramı karıştırabilir. Diğer bir deyişle, büyük O'nun "hız" ile ilgili tüm hikayeyi anlatmadığını açıkça belirtmek istedim.
whatsisname

3
@whatsisname doğrudan Microsoft'tan. Patolojik bir hashtable (başka bir mekanizma ile hash çarpışmalarını çözen) yoksa, bir değeri aramak için bir anahtar kullanmak, onu bir ağaçta veya sıralı listede (veya sıralanmamış listede) aramaktan daha hızlı olacaktır. Örneğin Java, çarpışma çözünürlüğü için doğrusal problama (adım 1) kullanır ; bu, tablonun çok dolu veya çok fazla karmanın çarpıştığı durumlarda daha yavaş olabilir . Genel durum için, yeterince iyi.

İlgili bir örnek olarak, son zamanlarda c ++ 'da başlangıçta yaklaşık 20 girişlik veri kümeleri için bir karma tablo kullanan ve tamamlamak için yaklaşık 400 ms süren bazı kod optimize. İkili bir ağaca geçmek, 200ms'ye kadar düştü, çünkü ağaca erişilmesi daha kolay. Ancak, bir dizi isim değeri çifti ve geçmiş erişim kalıplarına dayanarak nereden bakmaya başlayacağını tahmin eden sezgisel bir arama fonksiyonu kullanarak daha da kesebildim. Yani bu, ne kadar verinin olduğu ve erişimlerde ne tür bir kalıp olduğu (örn. Yerellik) meselesidir.
Jules
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.