Algorytmy i struktury danych Koszt zamortyzowany Drzewa dwumianowe Kopce dwumianowe Kopce Fibonacciego
Koszt zamortyzowany Średni koszt poj. operacji w kontekście całej sekwencji Koszt średni – wymaga rozkładu prawdopodobienstwa danych we. i probabilistycznej analizy czasu wykonania alg. Koszt zamortyzowany – rozważa sie np. wymagane sekwencje operacji i na tej postawie okresla koszt jednostkowej operacji Przyklad: ciąg operacji na stosie.
Kopce – koszt operacji Kopce binarne* / dwumianowe* / fibonacciego** wstawianie elementów (log n) / O(log n) / (1) znajdowanie minimalnego węzła (1) / O(log n) / (1) usuwanie minimalnego węzła (log n) / (log n) / O(log n) czas łączenia – (n) / O(log n) / (1) zmniejszanie klucza elementu (log n) / (log n) / (1) usuwanie węzła (log n) / (log n) / O(log n) * Koszt pesymistyczny **Koszt zamortyzowany
Drzewa dwumianowe Definicja: Bk-1 B0 Bk-1 Bk B0 B1 B2 B3 B4
Drzewa dwumianowe – właściwości Bk . . . . B0 B1 B2 Bk-2 Bk-1 Bk Liczba węzłów = 2k Wysokość = k Na głębokości i znajduje się węzłów Stopień korzenia jest k i jest największy w całym drzewie k i
Kopiec dwumianowy Każde drzewo w H jest uporządkowane kopcowo (klucz w węźle jest nie mniejszy niż klucz ojca) Dla każdego d0 istnieje w H co najwyżej jedno drzewo którego korzeń ma stopień = d Reprezentacja poszczególnych drzew w notacji na lewo syn na prawo brat H 10 12 18 1 25 11 27 8 17 14 38 6 29
Kopce dwumianowe - deklaracja class BNNODE : key = None degree = 0 child = None sibling = None parent = None data = None root = None
Kopce dwumianowe - Min def MinBNHeap(heap): min = heap while heap != None: if heap.key < min.key: min = heap heap = heap.sibling return min
Kopce dwumianowe - TreeLink z’ y z + = Bz Bz By By z y z’ 1 4 1 + = 12 18 25 11 19 27 4 12 18 25 11 19 27
Kopce dwumianowe - TreeLink def LinkBNTree(newSon, newParent) newSon.parent = newParent newSon.sibling = newParent.child newParent.child = newSon newParent.degree = newParent.degree +1
Kopce dwumianowe - Union Scal listy drzew dla łączonych kopców (zachowując uporzadkowanie wg. stopni Tak długo jak na liscie są drzewa o jednakowych stopniach scalaj drzewa
Kopce dwumianowe - Union 12 17 25 15 18 3 27 6 28 41 33 8 29 10 17 9 30 11 24 22 48 50 31 45 51 35 12 18 17 25 3 27 15 6 28 41 33 8 29 10 17 9 30 11 24 22 48 50 31 45 51 35 12 17 25 3 27 12 3 18 18 17 25 27
Kopce dwumianowe - Union 12 3 15 6 18 17 25 27 28 41 33 8 29 10 17 9 30 11 24 22 48 50 31 45 51 35 12 3 6 18 15 17 25 27 8 29 10 17 9 28 41 33 30 11 24 22 48 50 31 45 51 35
Union - przypadki X NextX a b a b c d Bk Bl Bm 1 l > k przejdz w prawo tj. X = NextX, NextX = NextX.sibling 2 l = k = m przejdz w prawo tj. X = NextX, NextX = NextX.sibling 3 l = k < m, a<=b TreeLink(NextX, X) 4 l = k < m, a>b TreeLink(X, NextX)
Union - implementacja def MergeBNHeap(h1, h2) ret = None cur = None while h1!=None and h2!=None: if h1.degree<=h2.degree: next,h1 = h1,h1.sibling else: next,h2 = h2,h2.sibling if ret == None: ret, cur = next, next else: cur.sibling,cur = next,next if h1==None: h1,h2=h2,h1 if ret==None: return h1 else cur.sibling = h1 return ret def UnionBNHeap(y, z): ret = MergeBNHeap(y, z) if ret == None: return None prevX = None X = ret nextX = ret.sibling while nextX != None: # przypadki 1..4 return ret
Union – implementacja cd. if X.degree != nextX.degree or\ #przypadek 1 (nextX.sibling!=None and\ nextX.degree == nextX.sibling.degree): #przypadek 2 prevX,X,nextX = X,nextX,nextX.sibling elif X.key <= nextX.key: #przypadek 3 X.sibling = nextX.sibling nextX.sibling = None LinkBNTree(nextX, X) nextX=X.sibling else: # przypadek 4 if prevX==None: ret = nextX else: prevX.sibling = nextX LinkBNTree(X, nextX) x.sibling = None X,nextX = nextX,nextX.sibling
Kopce dwumianowe - Insert def InsertBNHeap(heap, key, data) node = PBNNODE() #node.sibling = node.parent = node.child = None #node.degree = 0 node.key = key node.data = data return UnionBNHeap(heap, node)
Kopce - ExtractMin 18 13 37 7 8 29 10 17 21 30 19 24 11 42 51 32 40 50 32 18 13 37 + 44 10 17 29 8 42 51 32 30 19 24 21 40 50 32
ExtractMin - Implementacja Dla minimalnego węzła MIN usun drzewo zaczynające się od MIN z kopca H Utwórz nowy kopiec H’ z synów MIN Wykonaj Union na H i H’ def ExtractMinBNHeap(heap): ret = MinBNHeap(heap) usun_ret_z_listy_korzeni_w_heap h1 = odwroc_kolejnosc_synow_ret_i_zwroc_ich_liste heap = UnionBNHeap(heap, h1) ret.sibling = None ret.child = None return heap,ret
Kopce – Decrease Key 18 3 15 4 8 21 10 15 40 30 23 24 22 48 50 31 7 45 32 18 3 15 4 55 8 21 10 15 40 7 23 24 22 48 50 31 30 32 55 18 3 15 4 7 21 10 15 40 8 23 24 22 48 50 31 30 32 55
Decrease Key - Implementacja Zmien klucz dla węzła w while w jest mniejszy od ojca: zamień oba węzły def DecKeyBNHeap(node, newKey): if newKey > node.key: ERROR node.key = newKey while node.parent!=None and node.key<node.parent.key: node.key, node.parent.key = node.parent.key, node.key node.data,node.parent.data=node.parent.data,node.data node = node.parent
Remove Node - Implementacja def RemoveBNHeap(heap, node): tmp = node.key DecKeyBNHeap(node, MINKEYVALUE) heap,node = ExtractMinBNHeap(heap) node.key = tmp return heap,node MINKEYVALUE musi byc MNIEJSZY od wszystkich kluczy lub można poszukać minimalnego klucza
Kopce Fibbonacciego Zbliżone do kopców dwumianowych, mają jednak luźniejszą strukturę. zamortyzowany czas wstawiania – O(1) zamortyzowany czas min– O(1) zamortyzowany czas łączenia – O(1) zamortyzowany czas zmniejszenia klucza – O(1) zamortyzowany czas usuwania i ExtractMin O(log n) Koszt zamortyzowany – w odróżnieniu od analizy średniego przypadku nie wymaga rozważań probabilistycznych.
Kopiec Fibonacciego Każde drzewo w H jest jest uporządkowane kopcowo (klucz w węźle jest nie mniejszy niż klucz ojca) a początek drzewa wskazuje na minimalny węzeł Drzewa nie są uporządkowane między sobą Reprezentacja poszczególnych drzew: listy cykliczne dla poziomów drzewa i wskaźnik do jednego z synów; usuwanie wierzchołka i sklejanie list = O(1) Zaznaczenie wybranych wierzchołków (węzły które utraciły syna od chwili kiedy ostatnio zostały synem) Maksymalny stopien D(n) = logf n; f=(1+5) /2 HF 52 11 26 35 24 40 6 38 41 18 30 3 17 31
Sklejanie list cyklicznych def JoincycleLists(L1, L2): if L1==None: return L2 if L2==None: return L1 if L1.next==L1 : L1.prev = L2.prev #L1 miala 1 el. else: L1.next.prev = L2.prev if L2.prev==L2 : L2.next = L1.next #L2 miala 1 el. else: L2.prev.next = L1.next L1.next,L2.prev = L2, L1 data next prev data next prev data next prev data next prev data next prev L2 data next prev L1 data next prev L2'
Kopce Fibonacciego - deklaracja class HFNODE: key=None degree=0 child=None left=None right=None parent=None marked=False data=None HF=None size=0 HF 11 6 3 17 24 18 52 38 31 26 40 30 41 35
Kopce Fibonicciego - Insert Dodawany wezeł staje się oddzielnym drzewem i nie jest zaznaczony HF + 11 6 3 52 17 31 24 21 18 30 38 41 26 46 35 HF 11 6 21 3 52 17 31 24 18 30 38 41 26 46 35
Kopce Fibonicciego - Insert def InsertFibHeap(heap, key, size, data): node = PHFNODE() #node.parent = node.child = NULL #node.marked = false node.left = node node.right = node node.key = key node.data = data heap = JoinCycleLists( heap, node ) size = size+1 if heap.key<node.key: return heap,size else: return node,size
Kopce Fibonicciego - Union def UnionFibHeap (heap1, heap2, size1, size2): heap = JoinCycleLists( heap1, heap1) size = size1 + size2 if heap1.key < heap2.key: return heap1,size else return heap2,size
Kopce Fibonicciego - ExtractMin przenieś synów Min do H dopóki korzeń każdego drzewa w FH nie ma innego stopnia znajdź dwa korzenie x, y o tym samym stopniu, takie że x->key <= y->key usuń y z listy korzeni H dołącz y do x zwieksz stopien x Consolidate: FibHeapLink:
Kopce Fibonicciego - ExtractMin HF 11 6 21 3 52 17 31 24 11 6 21 18 30 52 38 41 17 31 24 18 30 38 41 26 46 26 46 35 35 1 2 3 4 1 2 3 4 w,x x 11 6 21 18 30 52 38 41 17 31 24 6 21 18 30 52 38 41 17 31 24 26 46 w 11 26 46 35 35 1 2 3 4 1 2 3 4 x 6 21 18 30 52 38 41 x 6 21 18 30 52 38 41 24 w 11 17 31 24 11 17 31 w 26 46 26 46 35 35
Kopce Fibonicciego - ExtractMin 1 2 3 4 1 2 3 4 w,x w,x 6 21 18 30 52 38 41 7 18 38 41 17 11 31 24 23 17 31 24 21 30 26 46 26 46 52 35 35 1 2 3 4 HF w,x 6 18 38 41 17 11 31 24 21 30 26 46 52 35
Kopce Fibonicciego - ExtractMin def ExtractMinFibHeap(heap, size): min = heap if min != None: heap = RemoveFromCycleList(heap, min) for c in all_children_of_min c.parent = None heap = JoinCycleList(heap, min.child) size = size-1 if heap != heap.left: heap = Consolidate(heap) return heap, size, min
Kopce Fibonicciego - Consolidate def Consolidate(heap, size): A = Array(D(size),None) for x in all_nodes_in_heap: d = x.degree; while A[d] != None: y = A[d] if x.key > y.key: x,y = y,x heap = FibHeapLink(heap, x, y) A[d] = None d = d+1 A[d] = x heap = None # merge nodes from A into heap for i in range(0, D(size)): if A[i] != NULL ): A[i].left = A[i] A[i].right = A[i] heap = JoinCycleList(heap, A[i]) if heap.key > A[i].key: heap = A[i]
Kopce Fibonicciego - Consolidate def FibHeapLink(heap, x, y): heap = RemoveNodeFromCycleList( heap, y ) x.child = JoinCycleList( x.child, y) x.degree = x.degree+1 y.mark = False return heap
Kopiec Fibonacciego Jeżeli nie wykonujemy operacji: ExtractMin Delete to drzewa w kopcu pozostają nieuporządkowanymi drzewami wielomianowymi Przy wykonywaniu ExtractMin i Delete maksymalny stopień węzła wynosi D(n) = D(n) = logf n; f=(1+5) /2 i taki jest koszt zamortyzowany obu operacji
Kopce Fibonicciego - DecKey HF HF 17 11 31 6 26 35 46 24 18 30 38 41 21 52 6 18 38 41 15 17 11 30 24 21 30 15 26 52 35 HF HF 6 18 38 41 15 6 18 38 41 15 4 17 11 31 24 21 39 17 11 31 24 21 30 26 52 26 52 4 35 HF HF 6 18 38 41 15 4 26 6 18 38 41 15 4 26 24 17 11 31 24 21 30 17 11 31 21 30 52 52
Kopce Fibonicciego - ExtractMin parent = x.parent if parent != None and x.key < parent.key : przenieś_x_do_korzenia_kopca x.marked = False if parent.marked: powtorz_cala_procedure_rekurencyjnie dla parent else: parent.marked = True
Kopce Fibonicciego - DecKey def DecKeyFibHeap(heap, x, newK): if x.key < newK : ERROR x->key = newK p = x.parent if p != None and x.key < p.key: heap = CutFibHeap(heap, x, p) heap = CascadingCutFibHeap (heap,p) if x.key < heap.key: heap = x;
Kopce Fibonicciego – Cut def CutFibHeap(heap, x, p): RemoveFromCycleList(p.son, x) p.degree = p.degree –1 x.left, x.right = x, x heap = JoinCycleList(heap, x) x.parent = None x.mark = False def CascadingCutFibHeap(heap, p): z = p.parent if z != None: if not z.marked: z.marked = True else: CutFibHeap(heap, p, z ) CascadingCutFibHeap(heap, z)
Kopce Fibonicciego – DelKey Zmniejsz klucz do najmniejszej możliwej wartosci Wykonaj ExtractMin def DelKeyFibHeap(heap, x, size): heap = DecKeyFibHeap(heap, x, MINKEYVALUE) heap,size,x = ExtractMinFibHeap(heap, size) return heap,size MINKEYVALUE musi byc MNIEJSZY od wszystkich kluczy lub można poszukać minimalnego klucza