Küçük bellek alanına sahip belirli bir uygulama mı arıyorsunuz?


9

Set veri türünün uygulanmasını arıyorum. Yani, yapmalıyız

  • dinamik bir alt kümesi muhafaza (büyüklüğü evrenin) U = \ {0, 1, 2, 3, \ noktalar, u - 1 \} boyutta u ileSnU={0,1,2,3,,u1}u
  • işlemleri insert(x)(bir eleman eklemek xiçin S ve) find(x)(eleman olmadığını kontrol eder xüyesidir S ).

Diğer operasyonları umursamıyorum. Oryantasyon için, birlikte çalıştığım uygulamalarda u1010 .

O (1) zamanında her iki işlemi de sağlayan uygulamaları biliyorum O(1), bu yüzden çoğunlukla veri yapısının boyutu hakkında endişeleniyorum. Milyarlarca giriş bekliyorum ama mümkün olduğunca takastan kaçınmak istiyorum.

Gerekirse çalışma zamanını feda etmeye hazırım. O itfa edilebilir çalışma zamanı (\ log n)O(logn) itiraf edebilirim; \ omega (\ log n) içinde beklenen çalışma zamanları veya çalışma zamanları ω(logn)kabul edilemez.

Sahip olduğum bir fikir, eğer S bir dizi birliği olarak temsil edilebilirse [xmin, xmax], bazı performans düşüşlerinin fiyatı ile depolama alanından tasarruf edebileceğiz. Ayrıca, başka veri desenleri de mümkündür [0, 2, 4, 6].

Beni böyle bir şey yapabilecek veri yapılarına yönlendirir misiniz?



Öğelerin sayısı resme nasıl girer? Yani, bir eleman yerleştirilirse ve zaten varsa ne olur ? nn
vonbrand

@vonbrand - nset S'nin boyutudur. Her biri ile artabilir insertveya eleman xzaten sette ise aynı kalabilir .
HEKTO

3
Küçük bir yanlış pozitif olasılığını kabul edebilir misiniz? Öyleyse, bir çiçek filtresi ideal olabilir: en.wikipedia.org/wiki/Bloom_filter
Joe

1
@AlekseyYakovlev, bir çiçek filtresinin yanlış pozitif oranının evren büyüklüğü ile ilgisi yoktur (sadece karma fonksiyonlarının sayısı , veri yapısının boyutu ve öğelerinin sayısı ile ), ancak gerçekten ise yakın (demek küçük sabit için ), sabit, yalnızca sona bence basit bir bit_vector daha iyi yapmak zor olacaktır toplam bit alanı. kmnnuu=ncccn
Joe

Yanıtlar:


8

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)<cf(n)
  • g(n)=o(f(n)) tüm sabitleri için sayısı olduğu, , olacağı anlamına gelir .cn0n>n0g(n)<cf(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.hmnm(nm)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

(nm)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


Merhaba, cevabınızın ikinci paragrafında olduğu gibi - her çağrıya aynı argümanla insertbir çağrı eşlik etmesini bekliyorum find. Yani, eğer findgeri dönerse true, o zaman atlarız insert. Bu nedenle, findaramaların sıklığı, aramaların sıklığından daha fazladır insert, ayrıca nyakınlaştığında u, insertaramalar çok nadir hale gelir.
HEKTO

Ama beklemek yakın olsun sonunda? un
Takma ad

Gerçek dünyada n, u'ya ulaşana kadar büyüyor, ancak bunun gerçekleşip gerçekleşmeyeceğini tahmin edemeyiz. Veri yapısı herkes için iyi çalışmalıdırn <= u
HEKTO

Sağ. Öyleyse, (yukarıdaki anlamda) özlü olan ve bunu tüm aralığında gerçekleştiren tek bir veri yapısını bilmediğimizi söylemek doğru olur . Sanırım olduğunda seyrek bir veri yapısı isteyeceksiniz , sonra civarında olduğunda yoğun bir (örneğin biraz vektör) , sonra tersine çevrilmiş bir seyrek veri yapısına geçeceksiniz. duyu zaman yakın olmaktır . nun<unu2nu
Takma ad

5

Dinamik üyelik sorunu için kısa ve öz bir veri yapısı istediğiniz anlaşılıyor .

Özlü bir veri yapısının , alan gereksiniminin bilgi-teorik alt sınırına "yakın" bir yapı olduğunu, ancak sıkıştırılmış bir veri yapısının aksine, hala etkili sorgulara izin verdiğini hatırlayın .

Üyelik sorun senin soru açıklamak tam olarak ne:

bir alt muhafaza (büyüklüğü evrenin) boyutta işlemleri ile:SnU={0,1,2,3,,u1}u

  • find(x)(öğeninx üyesi olup olmadığını kontrol eder ).S
  • insert(x)(bir eleman eklemek xiçin )S
  • delete(x)(Bir öğe kaldırmak xgelen )S

Yalnızca findişlem destekleniyorsa, bu statik üyelik sorunudur. İkisinden biri destekleniyorsa insertveya deletedesteklenmiyorsa, her ikisi de desteklenmiyorsa, yarı dinamik olarak adlandırılır ve her üç işlem de destekleniyorsa, dinamik üyelik sorunu olarak adlandırılır .

Teknik olarak, sadece yarı dinamik üyelik sorunu için bir veri yapısı istediğini düşünüyorum, ancak bu kısıtlamadan yararlanan ve diğer gereksinimlerinizi karşılayan herhangi bir veri yapısı bilmiyorum. Ancak, aşağıdaki referans var:

Sabit Zamanlı ve Neredeyse Minimum Uzayda Üyelik makalesinin 5.1. Teorisinde Brodnik ve Munro şu sonucu vermektedir:

bitleri gerektiren ve sabit zamanda aramaları ve beklenen beklenen amortize edilmiş zamanda eklemeleri ve silmeleri destekleyen bir veri yapısı vardır .O(B)

burada , gerekli bilgi teorik minimum bit sayısıdır.B=log(un)

Temel fikir, evreni özyinelemeyle özenle seçilmiş boyutların aralıklarına böldükleridir, bu yüzden bu teknikler düşündüğünüz çizgiler boyunca bile olabilir.

Ancak, aslında uygulayabileceğiniz bir şey arıyorsanız, bunun en iyi bahsiniz olup olmayacağını bilmiyorum. Sadece makaleyi gözden kaçırdım ve ayrıntıları açıklamaya çalışmak bu cevabın kapsamı dışındadır. ve göreceli boyutlarına bağlı olarak farklı stratejiler kullanarak çözümlerini parametrelendirirler . Ve veri yapısının dinamik versiyonu sadece makalede gösterilmiştir.un


1
Brodnik ve Munro bildiri özü, kesici uçlar hakkında hiçbir şey söylemez. Ama sonuçları beklediğimiz şey, değil mi? Eğer n = u/2öyleyse, gerekli alan maksimumdur.
HEKTO

@AlekseyYakovlev Özette dinamik durumdan gerçekten bahsetmiyorlar, ancak dinamik durumla ilgili teorem cevabımda (bölüm 5'ten) alıntılanıyor.
Joe
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.