Joe'nun cevabı son derece iyi ve tüm önemli anahtar kelimeleri veriyor.
Özlü veri yapısı araştırmasının hala erken bir aşamada olduğunu ve sonuçların çoğunun büyük ölçüde teorik olduğunu bilmelisiniz. Önerilen veri yapılarının çoğunun uygulanması oldukça karmaşıktır, ancak karmaşıklığın çoğu, hem evren büyüklüğü hem de depolanan eleman sayısı üzerinde asimtotik karmaşıklığı korumanız gerektiğinden kaynaklanmaktadır. Bunlardan herhangi biri nispeten sabitse, karmaşıklığın çoğu ortadan kalkar.
Koleksiyon yarı statik ise (yani, ekler nadirdir veya en azından düşük hacimli), o zaman bir güncelleme ile birlikte uygulanması kolay bir statik veri yapısı (Sadakane'in sdarray'ı iyi bir seçimdir) dikkate alınmalıdır. önbelleği. Temel olarak, geleneksel veri yapısındaki güncellemeleri kaydedersiniz (örn. B-ağacı, trie, karma tablosu) ve "ana" veri yapısını periyodik olarak toplu olarak güncellersiniz. Bu, bilgi edinmede çok popüler bir tekniktir, çünkü ters dizinlerin arama için birçok avantajı vardır, ancak yerinde güncellenmesi zordur. Bu durumda, lütfen bir yorumda bana bildirin, bu cevabı size bazı işaretçiler verecek şekilde değiştireceğim.
Ekler daha sık ise, özlü hash öneririm. Temel fikir burada açıklanacak kadar açıktır, bu yüzden yapacağım.
Temel bilgi teorik sonucu, öğelerin bir evreninden öğe saklıyorsanız ve başka bilgi yoksa (örneğin, öğeler arasında korelasyon yok), saklamak için bit. (Aksi belirtilmedikçe tüm logaritmalar baz-2'dir.) Bu kadar bite ihtiyacınız var . Etrafında bir yol yok.nulog(un)+O(1)
Şimdi bazı terminoloji:
- Verileri depolayabilecek ve bit alanlarındaki işlemlerinizi destekleyebilecek bir veri yapınız varsa , buna örtük bir veri yapısı diyoruz .log(un)+O(1)
- Verileri depolayabilen ve işlemlerinizi alan biti , buna kompakt veri yapısı diyoruz . Pratikte bunun göreceli yükün (teorik minimuma göre) bir sabit içinde olduğu anlamına geldiğini unutmayın. % 5 ek yük veya% 10 ek yük veya 10 kat ek yük olabilir.log(un)+O(log(un))=(1+O(1))log(un)
- Verileri depolayabilen ve işlemlerinizi alan bitini buna özlü veri yapısı diyoruz .log(un)+o(log(un))=(1+o(1))log(un)
Öz ve kompakt arasındaki fark, küçük-oh ve büyük-oh arasındaki farktır. Bir an için mutlak değeri göz ardı etmek ...
- g(n)=O(f(n)) sabit bir var olduğu anlamına gelir ve bir sayı bu şekilde tüm , .cn0n>n0g(n)<c⋅f(n)
- g(n)=o(f(n)) tüm sabitleri için sayısı olduğu, , olacağı anlamına gelir .cn0n>n0g(n)<c⋅f(n)
Gayri resmi olarak, big-oh ve little-oh her ikisi de "sabit bir faktör içinde", ancak big-oh ile sabit sizin için seçilir (algoritma tasarımcısı, CPU üreticisi, fizik yasaları veya her neyse), ancak çok az -oh sabiti kendiniz seçersiniz ve istediğiniz kadar küçük olabilir . Başka bir deyişle, özlü veri yapılarıyla, sorunun boyutu arttıkça göreli ek yük keyfi olarak küçülür.
Tabii ki, sorunun boyutu istediğiniz göreli yükü gerçekleştirmek için çok büyük olmak zorunda kalabilir, ancak her şeye sahip olamazsınız.
Tamam, bunun kemerlerimizin altında, soruna bazı sayılar koyalım. Anahtarların bit tamsayıları olduğunu varsayalım (yani evren boyutu ) ve bu tamsayıların saklamak istiyoruz . Diyelim ki tam doluluk ve israf olmadan sihirli bir şekilde idealleştirilmiş bir hash tablosu düzenleyebiliriz, böylece tam olarak hash slotlarına ihtiyacımız var.n2n2m2m
Bir arama işlemi, bit anahtarını hash eder , karma yuvalarını bulmak için bitlerini maskeler ve ardından tablodaki değerin anahtarla eşleşip eşleşmediğini kontrol eder. Çok uzak çok iyi.nm
Böyle bir karma tablosu bit kullanır . Bundan daha iyisini yapabilir miyiz?n2m
Kare işlevinin ters çevrilebilir olduğunu varsayalım . O zaman tüm anahtarı her bir hash yuvasında saklamak zorunda değiliz. Karma yuvasının konumu size karma değerinin bitlerini verir , bu nedenle yalnızca kalan bitlerini depoladıysanız , anahtarı bu iki bilgi parçasından (karma yuvası konumu ve burada depolanan değer) yeniden yapılandırabilirsiniz. Bu yüzden sadece bit depolama alanına ihtiyacınız olacaktır.hmn−m(n−m)2m
Eğer ile karşılaştırıldığında küçüktür , Stirling'in yaklaşımı ve biraz aritmetik (! Geçirmez bir alıştırma) ortaya koymaktadır:2m2n
(n−m)2m=log(2n2m)+o(log(2n2m))
Dolayısıyla bu veri yapısı özlüdür.
Ancak, iki yakalama vardır.
İlk yakalama "iyi" ters çevrilebilir hash fonksiyonları oluşturmaktır. Neyse ki, bu göründüğünden çok daha kolay; kriptograflar her zaman ters çevrilebilir işlevler yaparlar, sadece onlara "siber" derler. Örneğin, bir karma işlevini, ters çevrilemez karma işlevlerden ters çevrilebilir bir karma işlevler oluşturmanın basit bir yolu olan bir Feistel ağına dayandırabilirsiniz.
İkinci yakalama, doğum günü paradoksu sayesinde gerçek hash tablolarının ideal olmamasıdır. Bu nedenle, sizi dökülmeden tam doluluk oranına yaklaştıran daha sofistike bir karma tablo kullanmak istersiniz. Cuckoo hashing bunun için mükemmeldir, çünkü teoride ideale keyfi olarak yaklaşmanıza ve pratikte oldukça yakın olmanıza izin verir.
Guguklu karma, çoklu karma işlevleri gerektirir ve karma yuvalarındaki değerlerin karma işlevinin kullanıldığı etiketlenmesini gerektirir. Örneğin, dört karma işlevi kullanırsanız, her karma yuvasına ek iki bit daha depolamanız gerekir. büyüdükçe bu hala özlüdür , bu yüzden pratikte bir sorun değildir ve yine de tüm anahtarları depolamayı yener.m
Ah, van Emde Boas ağaçlarına da bakmak isteyebilirsiniz.
DAHA FAZLA DÜŞÜNCE
Eğer bir yere dönünce , ardından yaklaşık değerleri arasında başka bir korelasyon olduğunu varsayarak bu yüzden (bir kez daha), temelde herhangi yapamaz biraz vektörden daha iyi. Yukarıdaki karma çözümünün bu durumda etkili bir şekilde dejenere olduğunu (karma yuvası başına bir bit depoladığınız) not edeceksiniz, ancak bir karma işlevi kullanmak yerine anahtarı adres olarak kullanmak daha ucuzdur.nu2log(un)u
Eğer çok yakın olmaktır , özlü veri yapıları literatürde tüm sözlüğe şeklini ters çevirmek için tavsiye etmektedir. Değerleri Mağaza yok sette meydana gelir. Ancak, şimdi silme işlemini etkili bir şekilde desteklemeniz ve kısa ve öz davranışı sürdürmeniz için, daha fazla öğe "eklendiğinde" veri yapısını daraltabiliyor olmanız gerekir. Bir karma tablosunu genişletmek iyi anlaşılmış bir işlemdir, ancak bunu yapmak sözleşmeye bağlı değildir.nu