Aralıklarla harita için veri yapısı


11

Let bir tamsayı ve izin tüm tamsayılar kümesini belirtir. Let tamsayılar anlamında olabildikleri aralığı .nZ[a,b]{a,a+1,a+2,,b}

Bir harita temsil etmek için bir veri yapısı arıyorum . Veri yapısının aşağıdaki işlemleri desteklemesini istiyorum:f:[1,n]Z

  • f ( i )get(i) , döndürmelidir .f(i)

  • f f ( a ) = f ( a + 1 ) = = f ( b ) = y f f f ( i ) = y i [ a , b ] f ( i ) = f ( i ) i [set([a,b],y) güncellemelidir, böylece , yani yeni bir haritaya günceller bu şekilde için ve için .ff(a)=f(a+1)==f(b)=yfff(i)=yi[a,b]f(i)=f(i)i[a,b]

  • [ a , b ] i [ a , b ] fstab(i) en büyük aralığı dönmelidir bu şekilde ve sabit olduğundan (diğer bir deyişle, ).[a,b]i[a,b]f[a,b]f(a)=f(a+1)==f(b)

  • add([a,b],δ) güncellemelidir yeni harita için , öyle ki için ve için .f f ( i ) = f ( i ) + δ i [ a , b ] f ( i ) = f ( i ) i [ a , b ]fff(i)=f(i)+δi[a,b]f(i)=f(i)i[a,b]

Bu işlemlerin her birinin verimli olmasını istiyorum. veya süresini etkili olarak sayabilirim , ancak süresi çok yavaş. Çalışma süreleri itfa edilmiş çalışma süreleri olduğunda sorun yoktur. Tüm bu işlemleri aynı anda verimli hale getiren bir veri yapısı var mı?O ( lg n ) O ( n )O(1)O(lgn)O(n)

(Benzer bir modelin çeşitli programlama zorluklarında ortaya çıktığını fark ettim. Bu, tüm bu zorluk sorunları için yeterli olacak bir genellemedir.)


Sanırım yayvan ağaçlar başlangıç ​​noktası. addyine de alt aralıkları sayısında doğrusal olacaktır ; tembel olarak sıkıştırılmış ek " " düğümleri olan bir yayvan ağacı düşündünüz mü? + δ[a,b]+δ
Gilles 'SO- kötü olmayı durdur

Düşünün bu şekilde için tüm , . O zaman bir yerde değerinin depolanması gerekir . Sahne yeniden yapılandırmaya veya onları atarak nasılsa bu değerler (kurtulmak için var - GC ile erteleyebilir, ama yapmak zorunda olacak operasyonları bir noktada). Bu nedenle, operasyon . f ( i ) f ( j ) i j n seti ( [ a , b ] , y ) O ( n ) O ( n )ff(i)f(j)ijnset([a,b],y)O(n)O(n)
avakar

@avakar, GC'yi etkin bir şekilde "özgür" olarak gören bir çözümden memnun olurum. Daha genel olarak, çalışma sürelerinin amortisman çalışma süreleri olduğu bir çözümden memnun olurum (böylece GC maliyeti, ilk etapta değeri yaratma maliyetinde itfa edilebilir).
DW

Sabit ve logaritmik zamanın verimli ve doğrusal zamanın yavaş olduğunu fark ettiniz. Misiniz zaman ihtiyaçlarınız için çok yavaş? O(nlgn)
jbapple

@jbapple, hey, bu bir başlangıç! Bence bu bir cevap olarak belgelenmeye değer.
DW

Yanıtlar:


4

Tüm sorgular için logaritmik zamanın elde edilebileceğine inanıyorum. Ana fikir, ağaçtaki her düğümün bir indeks aralığına karşılık geldiği bir aralık ağacı kullanmaktır. Veri yapısının daha basit bir sürümü ile başlayıp (diğer işlemleri destekleyebilen ancak diğer işlemleri destekleyemeyen) temel fikirleri oluşturacağım, ardından diğer özellikleri de destekleyecek özellikler ekleyeceğim.

Basit bir şema (get ve set'i destekler, ancak ekleme veya bıçaklama yapmaz)

Bir aralık ki bu olan düz fonksiyonu ise sabit olan , yani, eğer .f [ a , b ] f ( a ) = f ( a + 1 ) = = f ( b )[a,b]f[a,b]f(a)=f(a+1)==f(b)

Basit veri yapımız bir aralık ağacı olacaktır. Başka bir deyişle, her düğümün bir aralığa (indeksler) karşılık geldiği ikili bir ağacımız var. Ağacın her bir düğümünde karşılık gelen aralığını depolayacağız . Her yaprak düz bir aralığa karşılık gelecek ve yaprakların soldan sağa okunması bize ayrık olan ve birleşimi tümü olan ardışık düz aralıklar dizisi verecek şekilde düzenlenecektir . Bir iç düğümün aralığı, iki çocuğunun aralıklarının birleşimi olacaktır. Ayrıca, her yaprak düğümünde işlevinin değerini aralığında depolayacağızv [ 1 , n ] V ( ) f I ( ) f fI(v)v[1,n]V()fI()bu düğüme karşılık gelir (bu aralığın düz olduğuna dikkat edin, bu nedenle aralıkta sabittir, bu nedenle her yaprak düğümünde tek bir değeri saklarız ).ff

Eşdeğer olarak, yi düz aralıklara böldüğümüzü hayal edebilirsiniz ve daha sonra veri yapısı, anahtarların bu aralıkların sol uç noktaları olduğu ikili bir arama ağacıdır. Yapraklar sabit olduğu bazı indeks aralıklarında değerini içerir .f f[1,n]ff

İkili ağacın dengeli kalmasını sağlamak için standart yöntemler kullanın, yani derinliği (burada ağaçtaki mevcut yaprak sayısını sayar). Tabii ki, , böylece derinlik her zaman en fazla . Bu aşağıda yardımcı olacaktır.m m n O ( lg n )O(lgm)mmnO(lgn)

Artık alma ve ayarlama işlemlerini aşağıdaki gibi destekleyebiliriz:

  • i O ( lg n ) O ( lg n )get(i) kolaydır: aralığı içeren yaprağı bulmak için ağaçtan geçeriz . Bu temelde sadece bir ikili arama ağacından geçer. Derinlik olduğu için çalışma süresi .iO(lgn)O(lgn)

  • set([a,b],y) daha karmaşıktır. Şöyle çalışır:

    1. İlk olarak yaprak aralığını içeren ; eğer , o zaman iki aralıklarla içine bu yaprak aralığını bölünmüş ve (böylece bir iç düğüm içine bu yaprak düğümü torna ve iki çocuk tanıtan).[a0,b0]aa0<a[a0,a1][a,b0]

    2. Ardından, içeren yaprak aralığını ; eğer , iki aralıklarla içine bu yaprak aralığını bölünmüş ve (böylece bir iç düğüm içine bu yaprak düğümü torna ve iki çocuk tanıtan).[a1,b1]bb<b1[a1,b][b+1,b1]

    3. Bu noktada, aralığının , ağaçtaki düğümlerinin bazı alt kümelerine karşılık gelen aralıklarının ayrık birleşimi olarak ifade edilebileceğini iddia ediyorum . Bu nedenle, bu düğümlerin tüm alt öğelerini silin (onları yapraklara dönüştürerek) ve bu düğümlerde depolanan değeri .[a,b]O(lgn)O(lgn)y

    4. Son olarak, ağacın şeklini değiştirdiğimizden, ağacı yeniden dengelemek için gerekli rotasyonları yapacağız (bir ağacı dengeli tutmak için herhangi bir standart teknik kullanarak).

    Bu işlem düğümlerinde birkaç basit işlem içerdiğinden (ve bu düğüm kümesi zamanında kolayca bulunabilir ), bu işlem için toplam süre .O(lgn)O(lgn)O(lgn)

Bu, işlem başına zamanında hem alma hem de ayarlama işlemlerini destekleyebileceğimizi gösterir . Aslında, çalışma süresi , burada şimdiye kadar yapılan ayarlanmış işlemlerin sayısıdır.O(lgn)O(lgmin(n,s))s

Eklemek için destek ekleme

Yukarıdaki veri yapısını, ekleme işlemini de destekleyecek şekilde değiştirebiliriz. Özellikle, fonksiyonun değerini yapraklarda saklamak yerine, bir düğüm kümesinde saklanan sayıların toplamı olarak temsil edilecektir.

Daha kesin olarak, değeri girişindeki fonksiyon olan aralığı içerir yaprak aşağı ağacının köküne uzanan yolun düğümleri içinde depolanmış değerler toplamı olarak geri kazanılma . Her düğüm değerini depolayacağız ; Eğer bir yaprak atası (yaprak kendisi de dahil olmak üzere), daha sonra, fonksiyon değeri olacaktır .f(i)iivV(v)v0,v1,,vkvkI(vk)V(v0)++V(vk)

Yukarıda açıklanan tekniklerin bir çeşidini kullanarak alma ve ayarlama işlemlerini desteklemek kolaydır. Temel olarak, ağacı aşağı doğru hareket ettirdikçe, değerlerin çalışan toplamını izleriz, böylece her geçiş ziyaretinde, kökten giden yoldaki düğümlerin değerlerinin toplamını bileceğiz . Bunu yaptığımızda, yukarıda açıklanan get ve set uygulamasında basit ayarlamalar yeterli olacaktır.xx

Ve şimdi verimli bir şekilde destekleyebiliriz. İlk olarak, ağaçtaki bazı düğüm kümesine karşılık gelen aralıklarının birleşimi olarak aralığını ifade ederiz gerekirse bir düğümü sol uç noktaya ve sağ uç noktaya bölerek ), ayarlanan işlemin 1-3. adımlarında olduğu gibi. Şimdi, bu düğümlerinin her birinde depolanan değere ekliyoruz . (Biz onların torunlarını silmiyoruz.)add([a,b],δ)[a,b]O(lgn)O(lgn)δO(lgn)

Bu, işlem başına zamanında alma , ayarlama ve ekleme işlemlerini desteklemenin bir yolunu sunar . Aslında, işlem başına çalışma süresi burada ayarlanmış işlemlerin sayısını artı toplama işlemlerinin sayısını sayar.O(lgn)O(lgmin(n,s))s

Bıçaklama işleminin desteklenmesi

Bıçaklama sorgusu desteklenmesi en zor olanıdır. Temel fikir, aşağıdaki ek değişmezi korumak için yukarıdaki veri yapısını değiştirmek olacaktır:

(*) Aralığı her yaprağa tekabül maksimal düz aralığıdır.I()

Burada bir aralık söylemek olan maksimal düz aralığı : (i) eğer düzdür ve (ii) aşağıdakileri içeren bir aralık tüm, bir başka deyişle (düz tatmin eder , veya düz değildir).[a,b][a,b][a,b]a,b1aabbn[a,b]=[a,b][a,b]

Bu, bıçak işleminin uygulanmasını kolaylaştırır:

  • stab(i) , aralığı içeren yaprağı bulur ve sonra bu aralığı döndürür.i

Ancak, artık değişmezi (*) korumak için seti değiştirmeli ve işlemler eklemeliyiz. Bir yaprağı ikiye böldüğümüzde, bazı bitişik yaprak aralıkları işlevinin aynı değerine sahipse değişmezi ihlal edebiliriz . Neyse ki, her set / add işlemi en fazla 4 yeni yaprak aralığı ekler. Ayrıca, her yeni aralık için, yaprak aralığını hemen solunda ve sağında bulmak kolaydır. Bu nedenle, değişmezin ihlal edilip edilmediğini söyleyebiliriz; öyleyse, aynı değere sahip olduğu bitişik aralıkları birleştiririz . Neyse ki, iki bitişik aralığın birleştirilmesi basamaklı değişiklikleri tetiklemez (bu nedenle birleşmenin değişmez ek ihlaller içerip içermediğini kontrol etmemiz gerekmez). Toplamda, bu incelemesini içerirf 12 = O ( 1 ) O ( lg n )ff12=O(1)çift ​​aralıklarla ve muhtemelen onları birleştirerek. Son olarak, bir birleşme ağacın şeklini değiştirdiğinden, eğer denge değişmezlerini ihlal ederse, ağacı dengede tutmak için gerekli rotasyonları gerçekleştirin (ikili ağaçları dengeli tutmak için standart teknikleri takip edin). Toplamda, set / add işlemlerine en fazla ek iş ekler.O(lgn)

Bu nedenle, bu son veri yapısı dört işlemin tümünü destekler ve her işlem için çalışma süresi . Daha kesin bir tahmin, işlem başına süresidir; burada , set ve add işlemlerinin sayısını sayar.O ( lg dk. ( N , s ) ) sO(lgn)O(lgmin(n,s))s

Ayrılık düşünceleri

Vay be, bu oldukça karmaşık bir plandı. Umarım hata yapmadım. Lütfen bu çözüme güvenmeden önce çalışmalarımı dikkatlice kontrol edin.

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.