Aktualizacja: zobacz poniżej aktualizację dotyczącą nieprawidłowości tej operacji łączenia
Oto bardzo przybliżony szkic możliwego rozwiązania:
Myślę, że mogę rozwiązać ten problem, używając pewnego rodzaju losowo zrównoważonego drzewa B +. Podobnie jak pułapki, drzewa te mają unikalną reprezentację. W przeciwieństwie do pułapek przechowują niektóre klucze wiele razy. Można to naprawić za pomocą sztuczki z „Biased Search Trees” Benta i innych, polegającej na przechowywaniu każdego klucza tylko na najwyższym (tj. Najbliższym rootowi) poziomie, na którym się pojawia)
Drzewo dla uporządkowanego zestawu unikalnych wartości jest tworzone przez pierwsze skojarzenie każdej wartości ze strumieniem bitów, podobnie do sposobu, w jaki każda wartość w pułapce jest powiązana z priorytetem. Każdy węzeł w drzewie zawiera zarówno strumień klucza, jak i strumień bitów. Węzły inne niż liście zawierają ponadto liczbę naturalną wskazującą wysokość drzewa zakorzenionego w tym węźle. Wewnętrzne węzły mogą mieć dowolną niezerową liczbę dzieci. Podobnie jak drzewa B +, każda nie przecinająca się ścieżka od korzenia do liścia ma tę samą długość.
vkivki+1vvja1vja
Aby utworzyć drzewo z posortowanej listy kluczy ze skojarzonymi strumieniami bitów, najpierw zbierz klucze do ciągłych grup na podstawie pierwszego bitu w ich strumieniach. Dla każdej z tych grup utwórz element nadrzędny ze strumieniem klucza i bitów największego klucza w grupie, ale z pominięciem pierwszego bitu strumienia. Teraz wykonaj tę samą procedurę grupowania nowych rodziców, aby utworzyć dziadków. Kontynuuj, aż pozostanie tylko jeden węzeł; to jest korzeń drzewa.
Poniższa lista kluczy i (bitów) strumieni bitów jest reprezentowana przez drzewo poniżej. W prefiksach strumienia bitów „.” znaczy trochę Oznacza to, że dowolny strumień bitów dla klucza A z 0 na pierwszym miejscu daje takie samo drzewo jak każdy inny, zakładając, że strumień bitów innego klucza nie jest inny.
A 0...
B 00..
C 10..
D 0...
E 0011
F 1...
G 110.
H 0001
____H____
/ \
E H
| / \
__E__ G H
/ | \ | |
B C E G H
/ \ | / \ / \ |
A B C D E F G H
Każde dziecko określonego węzła wewnętrznego ma ten sam bit na pierwszym miejscu swojego strumienia bitów. Nazywa się to „kolorem” rodzica - 0 to czerwony, 1 to zielony. Dziecko ma „smak” w zależności od pierwszego kawałka strumienia bitów - 0 to wiśnia, 1 to mięta. Liście mają smaki, ale nie mają koloru. Z definicji węzeł wiśniowy nie może mieć zielonego elementu nadrzędnego, a węzeł mięty nie może mieć czerwonego elementu nadrzędnego.
n2)1 - n ( n - 1i - 1)
a oczekiwana wartość to ( n + 1 ) / 2. Dla wszystkichn ≥ 2, to jest ≤ 34n, więc oczekiwana wysokość drzewa wynosi O ( lgn ).
Aby połączyć dwa drzewa o równej wysokości, najpierw sprawdź, czy ich korzenie są tego samego koloru. Jeśli tak, oderwij od lewego korzenia jego najbardziej potomne dziecko, a od prawego korzenia jego lewe dziecko, a następnie rekurencyjnie połącz te dwa drzewa. Rezultatem będzie drzewo o tej samej wysokości lub o jeden wyższy, ponieważ drzewa mają ten sam smak (patrz poniżej). Jeśli wynik rekurencyjnego łączenia dwóch drzew ma taką samą wysokość jak dwa odcięte dzieci, uczyń je środkowym dzieckiem korzenia z pozostałymi dziećmi lewego korzenia przed nim, a pozostałymi dziećmi prawego korzenia za nim. Jeśli jest wyższy o 1, uczyń jego dzieci środkowymi dziećmi korzenia z pozostałymi dziećmi lewego korzenia przed nim, a pozostałymi dziećmi prawego korzenia za nim. Jeśli korzenie mają różne kolory, sprawdź, czy mają ten sam smak. Jeśli to zrobią, nadaj im nowego rodzica ze strumieniem klucza i bitów odpowiedniego katalogu głównego, unikając pierwszego bitu. Jeśli nie, daj każdemu rootowi nowego rodzica ze strumieniem klucza i bitów starego roota (unikając każdego pierwszego bitu), a następnie rekurencyjnie dołącz do tych drzew.
There are two recursive calls in this algorithm.
The first is when the roots have the same color, the second is when the roots have different colors and different flavors.
The roots have the same color with probability 1/2.
The recursive call in this case always sees roots with the same flavor, so the second type of recursion never occurs after the first.
However, the first can occur repeatedly, but each time with probability 1/2, so the expected running time is still O(1).
The second recursive call happens with probability 1/4, and subsequent recursive calls are always on trees with different colors, so the same analysis applies.
Aby połączyć dwa drzewa o nierównej wysokości, najpierw przeszukaj lewy kręgosłup prawego drzewa, zakładając, że prawe drzewo jest wyższe. (Drugi przypadek jest symetryczny). Po osiągnięciu dwóch drzew o równej wysokości wykonaj operację łączenia dla dwóch drzew o równej wysokości, zmodyfikowanych w następujący sposób: Jeśli wynik ma tę samą wysokość, zastąp drzewo, które było dzieckiem, wynikiem dołączenia. Jeśli wynik jest wyższy, dołącz element nadrzędny drzewa po prawej stronie do katalogu głównego drugiego drzewa, po tym, jak zostanie on podniesiony o jeden przez dodanie elementu nadrzędnego dla katalogu głównego. Drzewo będzie prawdopodobnie tej samej wysokości1 / 2, więc to kończy się w O ( 1 ) spodziewany.
Update: Thanks to QuickCheck, I discovered that the above join method does not produce the same trees as the uniquely represented trees above. The problem is that parent choices near the leaves may change depending on the available siblings. To fix up those changes, join would have to traverse all the way to the leaves, which is not O(1). Here is the example QuickCheck found:
a 01110
b 110..
c 10...
d 00000
The the tree made by [a,b]
has height 2, the tree made by [c,d]
has height 2, and the tree made by joinEqual (tree [a,b]) (tree [c,d])
has height 3. However, the tree made by [a,b,c,d]
has height 5.
Here is the code I used to find this error.