https://en.wikipedia.org/wiki/Day%E2%80%93Stout%E2%80%93Warren_algorithm
Algorytm DSW (Day, Stout, Warren) służy do zrównoważenia drzewa BST. Algorytm działa w miejscu i w czasie O(n).
W oryginalnym algorytmie DSW wprowadza się pseudo-root, którego prawym dzieckiem jest zwykły root. Chyba chodzi o to, żeby nie robić rotacji pseudo-root, tylko poniżej, więc pseudo-root jest zawsze rodzicem poddrzewa. Przy równoważeniu drzewa ciągle trzeba osobno traktować root, bo on nie ma rodzica.
Pełne drzewa binarne z m wierzchołkami. m=1, liście 1, wysokość h=1 m=3=2^2-1, liście 2, wysokość h=2 m=7=2^3-1, liście 4=2^2, wysokość h=3 m=15=2^4-1, liście 8=2^3, wysokość h=4 m=31=2^5-1, liście 16=2^4, wysokość h=5 m=2^h-1, liście 2^(h-1), wysokość h Przejście do nowego poziomu: m = 2*m+1. h = log2(m+1), ale ogólnie dla n będzie wystawać parę liści h = |_log2(n+1)_| h = math.floor(math.log(n+1, 2)) # Py m = int(math.pow(2, math.floor(math.log(n+1, 2)))) -1 # Py2, Py3 m = int(math.pow(2, math.floor(math.log2(n+1)))) -1 # Py3.3+ better
| Przykład drzewa z wierzchołkami od 1 do 10. Mniejsze pełne drzewo ma m=7. | Po fazie I mamy faktycznie listę jednokierunkową o długości n=10. | Robimy wstępne n-m rotacji, żeby została wysokość drzewa m=7. | (1) rot1 2 rot2 2 rot3 (2) | \ / \ / \ / \ | 2 1 (3) 1 4 1 4 | \ \ / \ / \ | 3 4 3 (5) 3 6 | \ \ \ / \ | 4 5 6 5 7 | \ \ \ \ | 5... 6... 7... 8...
| Pierwsza pętla z m=3. | 4 4 (4) | / \ / \ / \ | 2 (6) 2 7 2 7 | / \ / \ / \ / \ / \ / \ | 1 3 5 7 1 3 6 (8) 1 3 6 9 | \ / \ / / \ | 8... 5 9... 5 8 10
| Druga pętla z m=1. | 7 | / \ | 4 9 | / \ / \ | 2 6 8 10 | / \ / | 1 3 5
# Wersja wg Wikipedii z pseudo_root.
def dsw(top):
if top is None: return
# Faza I. Tworzenie kręgosłupa. Równolegle zliczamy węzły.
pseudo_root = Node()
pseudo_root.right = top
n = tree_to_vine(pseudo_root)
# Faza II. Równoważenie drzewa.
vine_to_tree(pseudo_root, n)
return pseudo_root.right
def tree_to_vine(pseudo_root):
parent = pseudo_root
node = pseudo_root.right
n = 0 # jednocześnie zliczamy węzły drzewa
while node:
while node.left:
node = rotate_right(node)
parent.right = node # zmienił się wierzchołek poddrzewa
parent = node
node = node.right
n += 1
return n
def vine_to_tree(pseudo_root, n):
# Obliczenie liczby węzłow najbliższego pełnego drzewa binarnego.
m = 1 # drzewo pełne z jednym wierzchołkiem
while m <= n:
m = m * 2 + 1 # dodajemy kolejne poziomy drzewa
# Teraz m jest większe od n, nawet gdy n jest pełnym drzewem.
m = (m - 1) // 2 # za dużo o jeden poziom
#m = int(math.pow(2, math.floor(math.log2(n+1)))) -1 # Py3.3+
# Potrzebujemy n-m rotacji co drugi wierzchołek z prawej strony.
# Na najniższym poziomie drzewa będzie n-m liści.
compress(pseudo_root, n-m)
while m > 1:
m = m // 2
compress(pseudo_root, m) # m to obecna wysokość drzewa
def compress(pseudo_root, counter):
parent = pseudo_root
for i in range(counter):
parent.right = rotate_left(parent.right)
parent = parent.right