Upload
lupicinio-garcia-ortiz
View
11
Download
0
Embed Size (px)
DESCRIPTION
estructura de datos
Citation preview
Estructuras de Datos. Grado en Ingeniera Inform7ca, Ingeniera del So;ware e Ingeniera de Computadores ETSI Inform7ca Universidad de Mlaga
Jos E. Gallardo, Francisco Gu7rrez, Pablo Lpez, Blas C. Ruiz Dpto. Lenguajes y Ciencias de la Computacin Universidad de Mlaga
2
rboles Terminologa, Denicin formal rboles en Haskell
rboles binarios rboles binarios Autn7cos / Perfectos / Completos Relacin entre el peso y la altura rboles binarios en Haskell; recorrido . Construccin de un rbol binario de altura mnima
Colas con prioridad Especicacin. Implementacin lineal (Haskell)
MonYculos. Propiedad del monYculo (Heap-Order Prop.) MonYculo binario (Binary Heap) como AB completo Insercin y eliminacin. Representacin de un AB Completo con un Array MonYculos en Java; representacin va arrays
MonYculos zurdos (Weight Biased Le;ist Heaps) La espina derecha 7ene longitud logartmica Mezcla de monYculos zurdos (WBLH) Representacin de Colas de prioridad con monYculos
zurdos Comportamiento de los WBLHs Construccin de un monYculo zurdo en 7empo lineal Heap Sort MonYculos zurdos en Java
rboles binarios de bsqueda (Binary Search Tree,BST)
Insercin. Tree Sort Bsqueda de un elemento, del mximo y del mnimo Eliminacin Complejidad de las operaciones BST en Java
Iteradores para BST en Java Iterador En-Orden para BST Either: Tipo unin en Java Implementacin de iteradores
rboles AVL Altura de un rbol AVL. El nmero de oro Rotaciones en rboles binarios de bsqueda Insercin, descompensacin y rebalanceo por rotacin Bsqueda y eliminacin en un rbol AVL Complejidad de operaciones rboles AVL en Java
Diccionarios Signatura y axiomas Implementacin de diccionarios va rboles AVL.
Son las estructuras no lineales ms importantes
La relacin entre los objetos es jerrquica Ms rica que la relacin lineal (antes despus )
Son esenciales en la organizacin de datos Muchos algoritmos son ms ecientes va rboles
3
:->
:/\
:\/
Var
"p"
Var
"q"
No
Var
"q"
Var
"p"
10
155
83 12 20
Los rboles almacenan datos jerrquicamente Cada elemento 7ene un padre (salvo la raz) Cada elemento 7ene cero o ms hijos Los de cero hijos se denominan hojas Un nodo con algn hijo se llama interno
Se suelen dibujar inver&dos:
4
raz
hoja
interno
6 es un hijo de 2
2 es padre de 5 y 6
5 es un hijo de 2
1
2 3 4
5 6 7 8 9
El padre del padre es el abuelo Los hijos del mismo padre se llaman hermanos Un arco es un par de nodos (u,v) tal que u es el padre de v Un camino es una secuencia de nodos tal que: o es vaca, o 7ene un solo nodo, o 7ene varios , y cualesquiera dos consecu7vos forman un arco
5
Un arco
6 es hermano de 5
Un camino
1 es abuelo de 5, 6, 7, 8 y 9
1
2 3 4
5 6 7 8 9
Un rbol es un conjunto de nodos junto a una relacin padre-hijo tal que : Si el conjunto es vaco, el rbol es el rbol vaco En otro caso:
Es posible seleccionar un nodo r, llamado raz Los restantes nodos pueden agruparse en conjuntos disjuntos tales que cada uno de estos conjuntos es, a su vez, un rbol. Una raz (si existe) de cada uno de stos rboles se llama hijo de r.
Veamos como esta denicin se describe en Haskell
6
Los datos en un rbol se organizan en niveles: La raz est en el nivel 0 Los hijos de la raz en el nivel 1 Los nietos en el nivel 2 etc.
La altura de un rbol se dene como:
8
heightT :: Tree a -> IntheightT Empty = 0heightT (Node x []) = 1heightT (Node x ts) = 1 + maximum [heightT t | t
rbol binario: Cada nodo 7ene a lo sumo dos hijos
Los hijos se denominan hijo izquierdo e hijo derecho
9
rbol Binario Autn7co: Salvo las hojas, cada nodo 7ene dos hijos
rbol Binario Completo: Todos los nodos son completos (con dos hijos) salvo quizs los del l7mo nivel que aparecen todos pegados a la izquieda
rbol Binario Perfecto: Son autn7cos con todas las hojas en el nivel mximo
10
Se da la igualdad para cada rbol pefecto
n: nmero de nodos h: altura
Para todo rbol binario no vaco h n 2h-1 (= 1 + 2 + 22 + + 2h-1) 1+log2(n) h n
11
3 n 23 -1
1+log2(7) h 7
h= 3 n= 71+n
data TreeB a = EmptyB | NodeB a (TreeB a) (TreeB a) deriving Showtree2 :: TreeB Inttree2 = NodeB 1 (NodeB 2 (NodeB 4 EmptyB EmptyB) (NodeB 5 EmptyB EmptyB)) (NodeB 3 (NodeB 6 EmptyB EmptyB) EmptyB)
12
Constructor del rbol vacoSubrbol izquierdo
Subrbol derechoValor del nodo
-- suma de valores de los nodos sumB :: (Num a) => TreeB a -> asumB EmptyB = 0sumB (NodeB x lt rt) = x + sumB lt + sumB rt
Subrbol izquierdo (Le; subtree)
Right subtree
data TreeB a = EmptyB | NodeB a (TreeB a) (TreeB a) deriving Show
13
-- la lista de nodos de cierto nivel de un rbolatLevelB :: Int -> TreeB a -> [a]atLevelB _ EmptyB = []atLevelB 0 (NodeB x lt rt) = [x]atLevelB n (NodeB x lt rt) = atLevelB (n-1) lt ++ atLevelB (n-1) rt
Main> atLevelB 0 tree2 [1] Main> atLevelB 1 tree2 [2,3] Main> atLevelB 2 tree2 [4,5,6]
Nivel 0
Nivel 1
Nivel 2
14
-- caminos hasta cierto nodo (desde la raz) pathsToB :: (Eq a) => a -> TreeB a -> [[a]]pathsToB x EmptyB = []pathsToB x (NodeB y lt rt) | x==y = [y] : ps | otherwise = ps where ps = map (y:) (pathsToB x lt ++ pathsToB x rt)
Main> pathsToB 5 tree3 [[1,2,5]]Main> pathsToB 2 tree3 [ [1,2] , [1,3,2] ]Main> head $ pathsToB 2 tree3 [1,2]
Recorrido o exploracin de un rbol: proceso que visita cada nodo exactamente una vez
Los recorridos se clasican segn el orden de visita
Los rdenes de visita ms usuales para rboles binarios (que pueden generalizarse para cualquier rbol) son: Pre-Orden En-Orden (o en profundidad) Post-Orden En anchura (se vern ms tarde)
15
preOrderB :: TreeB a -> [a]preOrderB EmptyB = []preOrderB (NodeB x lt rt) = [x] ++ preOrderB lt ++ preOrderB rtinOrderB :: TreeB a -> [a] -- o recorrido en profundidadinOrderB EmptyB = []inOrderB (NodeB x lt rt) = inOrderB lt ++ [x] ++ inOrderB rtpostOrderB :: TreeB a -> [a]postOrderB EmptyB = []postOrderB (NodeB x lt rt) = postOrderB lt ++ postOrderB rt ++ [x]
16
Main> preOrderB tree4 [1,2,4,5,3,6,7]Main> inOrderB tree4 [4,2,5,1,6,3,7]Main> postOrderB tree4 [4,5,2,6,7,3,1]
Sea xs una lista Pretendemos construir un rbol binario t de altura mnima, vericando adems inOrderB t = xs
17
minTreeB [1..7] =>
minTreeB [1..6] =>
18
Prelude> splitAt 2 [10..15] ([10,11],[12,13,14,15])Prelude> splitAt 3 [10..15] ([10,11,12],[13,14,15])Prelude> quickCheck p_minTreeB+++ OK, passed 100 tests.minTreeB :: [a] -> TreeB aminTreeB [] = EmptyB
minTreeB xs = NodeB z (minTreeB yz) (minTreeB zs) where m = length xs `div` 2 (yz,z:zs) = splitAt m xsp_minTreeB xs = n>0 ==> inOrderB t == xs && heightB t == 1 + log2 n where t = minTreeB xs n = length xslog2 :: Int -> Intlog2 x = truncate (logBase 2 (fromIntegral x))
Es fcil demostrar estas dos igualdades por induccin sobre la longitud de la lista xs
19
minTreeB :: [a] -> TreeB aminTreeB [] = EmptyBminTreeB xs = NodeB z (minTreeB ys) (minTreeB zs) where m = length xs `div` 2 (ys,z:zs) = splitAt m xs Sea T(n) el nmero de pasos para evaluar minTreeB sobre una lista con n
elementos: T(0) = 1 T(n) = O(n) + 2 T(n/2), si n > 0
La solucin T(n) est en O(n log n) L
splitAt es O(n)
minTreeB' :: [a] -> TreeB aminTreeB' xs = fst (aux (length xs) xs)aux :: Int -> [a] -> (TreeB a, [a])aux 0 xs = (EmptyB, xs)aux 1 xs = (NodeB (head xs) EmptyB EmptyB, tail xs)aux n xs = (NodeB y t1 t2, zs) where m = div n 2 (t1, y:ys) = aux m xs (t2, zs) = aux (n-m-1) ys Sea T(n) el nmero de pasos para evaluar minTreeB' sobre una
lista con n elementos: T(0) = 1 T(n) = O(1) + 2 T(n/2), si n > 1
La solucin T(n) es de orden O(n) J 20
aux n xs devuelve un rbol con los n primeros elementos de xs y el resto de la lista (drop n xs). Estamos resolviendo
un problema ms general
Consideremos que existe una relacin de orden entre los elementos a encolar (edad, sueldo,), de forma que se a7enda antes a los de mayor prioridad: los ms jvenes, los de menor sueldo, en deni7va, los menores para la relacin de orden: SIFO (Smallest in, rst out)
Ser interesante organizar los elementos en la cola de forma que la seleccin del primero a atender, la eliminacin de ste, y la inclusin de uno nuevo sean ecientes.
21
vip
Los elementos pueden insertarse en cualquier orden pero son extrados de la cola de acuerdo con su prioridad.
-- devuelve una cola vaca empty :: PQueue a-- test para colas vacasisEmpty :: PQueue a -> Bool-- inserta un elemento en una cola de prioridadenqueue :: (Ord a) => a -> PQueue a -> PQueue a-- devuelve el elemento de mnima prioridadfirst :: (Ord a) => PQueue a -> a-- devuelve la cola obtenida al eliminar-- el elemento de mnima prioridaddequeue :: (Ord a) => PQueue a -> PQueue a
22
Los elementos con igual prioridad salen
en orden FIFO
isEmpty empty -- q1 not (isEmpty (enqueue x q)) -- q2
first (enqueue x empty) == x -- q3
dequeue (enqueue x empty) == empty -- q4Los anteriores axiomas coinciden con los de Queue. Tres adicionales capturan el comportamiento SIFO (smallest in, rst out) : first (enqueue y (enqueue x q)) == first (enqueue (min x y) q) -- pq1 dequeue (enqueue y (enqueue x q)) == enqueue (max x y ) (dequeue (enqueue (min x y ) q)) -- pq2Ejercicio: probar first $ enq 3 $ enq 1 $ enq 2 empty == 1
23
first :: PQueue a -> afirst Empty = error "first on empty queue"first (Node x _) = xdequeue :: PQueue a -> PQueue adequeue Empty = error "dequeue on empty queue"dequeue (Node _ q) = q
25
El elemento mnimo aparece al principio
Ejercicio: implementar la Cola con Prioridad en Java usando una lista enlazada
Coste para la implementacin lineal:
Veremos implementaciones de colas de prioridad que mejoran enqueue, pero empeoran dequeue.
26
Operacin Coste empty O(1) isEmpty O(1) enqueue O(n) first O(1) dequeue O(1)
L pero podemos mejorarla
Un monYculo (heap) es un rbol que verica la siguiente propiedad de orden (Heap-Order Property o HOP) El valor de cada nodo dis7nto de la raz, es mayor o igual al valor de su padre
Equivalentemente: la secuencia de nodos de cualquier camino desde la raz a una hoja es ascendente
El valor mnimo est en la raz J 27
0
Un heap JEste no es un heap L
Un monYculo binario es un rbol binario completo que sa7sface HOP (Heap-Order property)
R
Recordemos: la altura de un rbol binario completo con n elementos es 1+log2(n). Luego la altura de un monYculo binario ser mnima.
28
Un montculo binario J
Este no es un completo L
Un montculo binario J
Queremos aadir un elemento a un monYculo binario de forma que el resultado sea otro monYculo binario
29
insert(0)
Insercin: se realiza en dos fases (colocar al fondo, y reotar) 1) Colocar el nuevo elemento en la primera posicin libre:
A la derecha del l7mo nodo del l7mo nivel, o bien A la izquierda del siguiente nivel si el l7mo est completo
2) Mientras que el nuevo elemento sea menor que el padre: Intercambiar el nuevo con el padre
30
insert(0)
insert(0)
0
0
El resultado es un rbol completo J
Insercin: se realiza en dos fases 1) Colocar el nuevo elemento en la primera posicin libre:
A la derecha del l7mo nodo del l7mo nivel, o bien A la izquierda del siguiente nivel si el l7mo est completo
2) Mientras que el nuevo elemento sea menor que el padre: Intercambiar el nuevo con el padre
31
0
3 insert(0)
Para reestablecer la propiedad HOP J
Insercin: se realiza en dos fases 1) Colocar el nuevo elemento en la primera posicin libre:
A la derecha del l7mo nodo del l7mo nivel, o bien A la izquierda del siguiente nivel si el l7mo est completo
2) Mientras que el nuevo elemento sea menor que el padre: Intercambiar el nuevo con el padre
32
Swap 0 3
0
3
0
3
1 insert(0)
Para reestablecer la propiedad HOP J
Insercin: se realiza en dos fases 1) Colocar el nuevo elemento en la primera posicin libre:
A la derecha del l7mo nodo del l7mo nivel, o bien A la izquierda del siguiente nivel si el l7mo est completo
2) Mientras que el nuevo elemento sea menor que el padre: Intercambiar el nuevo con el padre
33
Swap 0 3
0
Swap 0 1
3
0
3
1
3
0
1 insert(0)
Un montculo binario J
Para reestablecer la propiedad HOP J
Recordemos que un rbol completo con n elementos 7ene altura 1+log2(n)
En el peor caso, la insercin necesita un nmero de pasos proporcional a log2(n)
Luego, insert est en O(log n) J
34
0
50
100
150
200
250
300
350
400
450
500
Nm
ero de
pasos
N de nodos
n
log n
Enorme diferencia entre n y log n
Sea minChild(u) el valor mnimo de los dos hijos del nodo u Este puede ser el izquierdo o el derecho
La eliminacin de la raz se realiza en dos fases (subir el l7mo, y hundirlo) 1) Pasar el l7mo elemento u a la raz 2) Mientras u > minChild(u) :
Intercambiar minChild(u) con u
35
7
6
Delete root
5 4 5 4
Esta fase conserva la completitud J
Sea minChild(n) el valor mnimo de los dos hijos del nodo n Este puede ser el izquierdo o el derecho
La eliminacin de la raz se realiza en dos fases 1) Pasar el l7mo elemento u a la raz 2) Mientras u > minChild(u) :
Intercambiar minChild(u) con u
36
7
6
Delete root
5 4 5 4
3 2
Reestablecer la propiedad HOP J
Sea minChild(n) el valor mnimo de los dos hijos del nodo n Este puede ser el izquierdo o el derecho
La eliminacin de la raz se realiza en dos fases 1) Pasar el l7mo elemento u a la raz 2) Mientras u > minChild(u) :
Intercambiar minChild(u) con u
37
7
6
Delete root 3 2 7
2 Swap 7 2
5 4 5 4 6
5 4
Reestablecer la propiedad HOP J
Sea minChild(n) el valor mnimo de los dos hijos del nodo n Este puede ser el izquierdo o el derecho
La eliminacin de la raz se realiza en dos fases 1) Pasar el l7mo elemento u a la raz 2) Mientras u > minChild(u) :
Intercambiar minChild(u) con u
38
7
6
Delete root 7
2
4 5
Swap 7 2
5 4 5 4 6
Reestablecer la propiedad HOP J
Sea minChild(n) el valor mnimo de los dos hijos del nodo n Este puede ser el izquierdo o el derecho
Eliminacin de la raz: se realiza en dos fases 1) Pasar el l7mo elemento u a la raz 2) Mientras u > minChild(u) :
Intercambiar minChild(u) con u
39
7
6
Delete root 7
2
4 5
Swap 7 2
5 4 5 4 7
2
5
Swap 7 4
6 6
4
El montculo final J
Reestablecer la propiedad HOP J
Los nodos de un ABC pueden colocarse fcilmente en forma consecu7va dentro de un array por niveles:
40
a b dc e f0 1 3 2 4 5 6
Nivel l 0 Nivel 1 Nive l 2
Nivel 0
Nivel 1
Nivel 2
Padres e hijos pueden localizarse fcilmente va aritmBca elemental: La raz 7ene ndice 0Para el nodo de ndice i:
El hijo izquierdo ocupa la pos. 2*i+1El hijo derecho ocupa la pos. 2*i+2 El padre ocupa la pos. (i-1)/2
a b dc e f0 1 3 2 4 5 6
hijos
padres
a
b c
d e f
// true if elems[idx1] < elems[idx2] private boolean lessThan(int idx1, int idx2) { return elems[idx1].compareTo(elems[idx2]) < 0; } // swaps elements in array elems at positions idx1 and idx2 private void swap(int idx1, int idx2) { T aux = elems[idx1]; elems[idx1] = elems [idx2]; elems[idx2] = aux; }
43
private void heapifyUp(int idx) { while(!isRoot(idx)) { int idxParent = parent(idx); if(lessThan(idx,idxParent)) { swap(idx,idxParent); idx = idxParent; // move to parent node for next iteration } else break; } } public void insert(T x) { ensureCapacity(); elems[size] = x; // put new element at right in last level of tree heapifyUp(size); // move element up to enforce heap-order property size++; }
45
= (idx-1) / 2
heapifyUp(n) est en O(log n)
public T minElem() { if(isEmpty()) throw new EmptyHeapException("minElem on empty heap"); else return elems[ROOT_INDEX]; }
46
El mnimo siempre se encuentra en la
raz J
private void heapifyDown() { int idx = ROOT_INDEX; // start at root of tree while(!isLeaf(idx)) { int idxChild = leftChild(idx); int idxRightChild = rightChild(idx); if(isNode(idxRightChild) && lessThan(idxRightChild,idxChild)) idxChild = idxRightChild; // idxCHild es el ndice del hijo con el menor de los valores if(lessThan(idxChild,idx)) { swap(idxChild,idx); idx = idxChild; // move to child node for next iteration } else break; } } public void delMin() { if(isEmpty()) throw new EmptyHeapException("delMin on empty heap"); else { elems[ROOT_INDEX] = elems[size-1]; // move last child to root of tree size--; heapifyDown(); // move element down to enforce heap-order property } } 47
=2*idx+1
2*idx+1 >= size
heapifyDown() est en O(log size)
Coste de las operaciones:
48
Operacin Coste BinaryHeap O(1) isEmpty O(1) minElem O(1) insert O(log n) delMin O(log n)
O(n) si redimensionamos el array
Llamamos peso de un nodo el nmero de elementos que cuelgan desde el nodo
Representaremos un monYculo va un rbol binario aumentado: en cada nodo aparece (adems de su valor y los hijos) su peso:
49
data Heap a = Empty | Node a Int (Heap a) (Heap a)weight :: Heap a -> Intweight Empty = 0weight (Node _ w _ _) = w
Peso del nodo
h1 :: Heap Charh1 = Node 'a' 6 (Node 'd' 3 (Node 'e' 1 Empty Empty) (Node 'f' 1 Empty Empty)) (Node 'b' 2 (Node 'c' 1 Empty Empty) Empty)
rbol con raz 'a' con 6 elementos
rbol con raz b' con 2 elementos
Un rbol es Weight Biased Le;ist si, para cualquier nodo en el rbol, el peso de su hijo izquierdo es mayor o igual que el peso de su hijo derecho
Un heap Weight Biased Le;ist (WBLH) es un rbol Weight Biased Le;ist que sa7sface la propiedad de Heap-order
50
isWeightedLeftist :: Heap a -> BoolisWeightedLeftist Empty = TrueisWeightedLeftist (Node _ _ lh rh) = weight lh >= weight rh && isWeightedLeftist lh && isWeightedLeftist rh
Es un WBLH J
Es un WBLH J
Es un WBLH J
module DataStructures.Heap.WeightBiasedLeftistHeap ( Heap , empty -- :: Heap a , isEmpty -- :: Heap a -> Bool , minElem -- :: Heap a -> a , delMin -- :: (Ord a) => Heap a -> Heap a , insert -- :: (Ord a) => a -> Heap a -> Heap a) wheredata Heap a = Empty | Node a Int (Heap a) (Heap a) deriving Showempty :: Heap aempty = EmptyisEmpty :: Heap a -> BoolisEmpty Empty = TrueisEmpty _ = FalseminElem :: Heap a -> aminElem Empty = error "minElem on empty heap"minElem (Node x _ _ _) = x
51
El mnimo del montculo es la raz del arbol
delMin :: (Ord a) => Heap a -> Heap adelMin Empty = error "delMin on empty heap"delMin (Node _ _ lh rh) = merge lh rhsingleton :: a -> Heap asingleton x = Node x 1 Empty Emptyinsert :: (Ord a) => a -> Heap a -> Heap ainsert x h = merge (singleton x) hmerge :: (Ord a) => Heap a -> Heap a -> Heap a...
52
elimina la raz (el menor) y mezcla los hijos
Crea un montculo de un elemento y lo mezcla con el montculo
En definitiva: las operaciones delicadas (insert, delMin) y su complejidad dependen de la definicin de merge.
Definiremos merge para que su complejidad sea logartmica J
Sea llama espina derecha de un rbol binario al camino desde la raz hasta el nodo terminal ms a la derecha
Para cualquier WBLT con n elementos, la longitud de su espina derecha es log2(n+1)
53
Espina derecharightSpine :: Heap a -> [a]rightSpine Empty = []rightSpine (Node x _ _ rh) = x : rightSpine rh
esto demostrar que la complejidad de merge es logartmica
Teorema.- Para cualquier monYculo zurdo (WBLT) t con n elementos, la longitud de la espina derecha sa7sface
lrs t log2(n+1)
Por induccin sobre t; hay que probar: Caso base: lrs Empty log2(0+1) Paso induc7vo: siendo p = weight lh, q = weight rh si lrs lh log2(p+1) && lrs rh log2(q+1) entonces lrs (Node x _ lh rh) log2(p+q+2) 54
-- longitud de la espina derechalrs :: Heap a -> Intlrs Empty = 0lrs (Node x _ _ rh) = 1 + lrs rh
Caso base:
lrs Empty log2(0+1) {- 1) ecuacin de lrs (parte izquierda) -} 0 log2(0+1) {- aritmtica de log (parte derecha) -} 0 0 True
55
-- length of right spinelrs :: Heap a -> Intlrs Empty = 0lrs (Node x _ _ rh) = 1 + lrs rh
Paso induc7vo: Sean p = weight lh y q = weight rh
si lrs lh log2(p+1) && lrs rh log2(q+1) entonces lrs (Node x _ lh rh) log2(p+q+2)
lrs (Node x _ lh rh) log2(p+q+2) {- 2) lrs al miembro izdo. de la desigualdad -} 1 + lrs rh log2(p+q+2) {- Hiptesis de induccin, transitividad de -} 1 + log2(q+1) log2(p+q+2) {- 1 = log2 2, log x + log y = log (xy) -} log2(2q+2) log2(p+q+2) {- _ y log2 son montonas} 2q+2 p+q+2 {- p q porque el montculo es zurdo -} True
56
-- longitud de la espina derechalrs :: Heap a -> Intlrs Empty = 0lrs (Node x _ _ rh) = 1 + lrs rh
Hiptesis de induccin
Dos monYculos zurdos construidos con 50 elementos aleatorios: la espina derecha es muy corta!
57
Pretendemos obtener un nuevo WBLH mezclando dos WBLHs
Y pretendemos obtenerlo ecientemente: Mezclndolos a travs de sus espinas derechas (O(log n))
58
merge => 1
Queremos mezclar dos listas ordenadas para obtener una lista ordenada:
merge [1,7,9] [0,2,4] -- sacamos la menor de las cabezas y seguimos mezclando 0 : merge [1,7,9] [2,4] 0 : 1 : merge [7,9] [2,4] 0 : 1 : 2 : merge [7,9] [4] 0 : 1 : 2 : 4 : merge [7,9] [] 0 : 1 : 2 : 4 : [7,9]
59
merge :: (Ord a) => [a] -> [a] -> [a]merge [] ys = ysmerge xs [] = xsmerge ls@(x:xs) rs@(y:ys) | x
Necesitamos una funcin auxiliar para construir un rbol zurdo a par7r de otros dos y de un valor:
60
node :: a -> Heap a -> Heap a -> Heap a node x h h' | w >= w' = Node x s h h' | otherwise = Node x s h' h where w = weight h w' = weight h' s = w + w' + 1
node 0 =>
El resultado es zurdo, pero no necesariamente ordenado, salvo que 0 no supere a las raices
El de ms peso a la izquierda
Manteniendo el invariante: los
argumentos son zurdos
Si los argumentos son monYculos zurdos, es posible demostrar por induccin:
1. la mezcla es un monYculo zurdo J 2. el nmero de llamadas a merge es menor que la suma
de las longitudes de las espinas izquierdas de los argumentos J
61
merge :: (Ord a) => Heap a -> Heap a -> Heap amerge Empty h' = h'merge h Empty = hmerge h@(Node x w lh rh) h'@(Node x' w' lh' rh') | x
62
merge :: (Ord a) => Heap a -> Heap a -> Heap amerge Empty h' = h'merge h Empty = hmerge h@(Node x w lh rh) h'@(Node x' w' lh' rh') | x
63
merge :: (Ord a) => Heap a -> Heap a -> Heap amerge Empty h' = h'merge h Empty = hmerge h@(Node x w lh rh) h'@(Node x' w' lh' rh') | x
64
merge :: (Ord a) => Heap a -> Heap a -> Heap amerge Empty h' = h'merge h Empty = hmerge h@(Node x w lh rh) h'@(Node x' w' lh' rh') | x
65
merge :: (Ord a) => Heap a -> Heap a -> Heap amerge Empty h' = h'merge h Empty = hmerge h@(Node x w lh rh) h'@(Node x' w' lh' rh') | x
module DataStructures.PriorityQueue.WBLeftistPriorityQueue ( PQueue , empty -- :: PQueue a , isEmpty -- :: PQueue a -> Bool , first -- :: PQueue a -> a , dequeue -- :: (Ord a) => PQueue a -> PQueue a , enqueue -- :: (Ord a) => a -> PQueue a -> PQueue a) whereimport qualified DataStructures.Heap.WeightBiasedLeftistHeap as Hdata PQueue a = PQ (H.Heap a) empty :: PQueue aempty = PQ H.emptyisEmpty :: PQueue a -> BoolisEmpty (PQ h) = H.isEmpty henqueue :: (Ord a) => a -> PQueue a -> PQueue aenqueue x (PQ h) = PQ (H.insert x h)first :: PQueue a -> afirst (PQ h) = H.minElem hdequeue :: (Ord a) => PQueue a -> PQueue adequeue (PQ h) = PQ (H.delMin h) 66
Eciencia de las operaciones:
67
Operacin Coste empty O(1) isEmpty O(1) minElem O(1) merge O(log n) insert O(log n) delMin O(log n)
El resultado es similar al obtenido con monYculos binarios en Java va arrays
-- construccin en forma ascendente (bottom-up): O(n)mkHeap :: (Ord a) => [a] -> Heap amkHeap [] = emptymkHeap xs = mergeLoop (map singleton xs) where mergeLoop [h] = h mergeLoop hs = mergeLoop (mergePairs hs) mergePairs [] = [] mergePairs [h] = [h] mergePairs (h:h':hs) = merge h h' : mergePairs hs Sea T(n) el nmero de pasos de mkHeap para una lista con n elementos:
T(n) = n/2 O(log2 1) + n/4 O(log2 2) + n/8 O(log2 4) + + 1 O(log2 (n/2))
La solucin T(n) es O(n) J
68
n/2 mezclas de montculos de 1
elemento
n/4 mezclas de montculos de 2
elementos
n/8 mezclas de montculos de 4
elementos
1 mezcla de montculos de n/2 elementos
Mezclamos dos a dos hasta obtener un solo
elemento
mezcla dos a dos
Construimos una lista de montculos simples
69
mergeLoop (mergePairs[ , , , , , , , ]) =>
mergeLoop (mergePairs [ , , , ]) =>
mergeLoop (mergePairs [ , ]) =>
mergeLoop [ ] =>
mergeLoop (map singleton [8, 3, 1, 6, 2, 4, 5, 7]) =>
heapSort :: (Ord a) => [a] -> [a]heapSort = heapToList . mkHeapheapToList :: (Ord a) => Heap a -> [a]heapToList h | isEmpty h = [] | otherwise = minElem h : heapToList (delMin h)
70
heapSort est en O(n log n)
[1,3,4,6,7,8,9] heapToList mkHeap [6,3,8,1,4,7,9]
n eliminaciones donde cada una realiza O(log n) pasos + O(n)
para la operacin mkHeap
private static Tree node(T x, Tree h, Tree hp) { !"int w = weight(h); !"int wp = weight(hp); !"Tree tree = new Tree(); !"tree.elem = x; !"tree.weight = 1 + w + wp; !"if (w >= wp) { !" "tree.left = h; !" "tree.right = hp; !"} else { !" "tree.left = hp; !" "tree.right = h; !"} !"return tree; !
} !"!
72
node :: a -> Heap a -> Heap a -> Heap a node x h h' | w >= w' = Node x s h h' | otherwise = Node x s h' h where w = weight h w' = weight h' s = w + w' + 1
public T minElem() { if(isEmpty()) throw new EmptyHeapException("minElem on empty heap"); else return root.elem; } public void delMin() { if(isEmpty()) throw new EmptyHeapException("delMin on empty heap"); else root = merge(root.left,root.right); } public void insert(T x) { Tree tree = new Tree(); tree.elem = x; tree.weight = 1; root = merge(root, tree); }
75
El mnimo en la raz
Mezclamos los hijos sin la raz
La insercin se produce al mezclar la raz con el
nuevo MZ
Creamos un nuevo MZ con un solo elemento
Un BST (Binary Search Tree) es un rbol binario tal que para cada nodo v, todos los elementos del subrbol
izquierdo son menores que v, y todos los elementos del subrbol
derecho son mayores que vdata BST a = Empty | Node a (BST a) (BST a) deriving ShowisBST :: (Ord a) => BST a -> BoolisBST Empty = TrueisBST (Node x lt rt) = forAll (x) rt && isBST lt && isBST rt where forAll :: (a -> Bool) -> BST a -> Bool forAll p Empty = True forAll p (Node x lt rt) = p x && forAll p lt && forAll p rt
76
Invariante de un BST
Problema: insertar un nuevo elemento en un BST de forma que el resultado sea otro BST (se conserve el invariante)
77
insert 7
Problema: insertar un nuevo elemento en un BST de forma que el resultado sea otro BST (se conserve el invariante)
78
7 7 debe quedar a la
derecha de 4
Problema: insertar un nuevo elemento en un BST de forma que el resultado sea otro BST (se conserve el invariante)
79
7 7 a la izquierda de 8
Problema: insertar un nuevo elemento en un BST de forma que el resultado sea otro BST (se conserve el invariante)
80
7
7 a la derecha de 6
Problema: insertar un nuevo elemento en un BST de forma que el resultado sea otro BST (se conserve el invariante)
81
7
7 debe quedar aqu
Problema: insertar un nuevo elemento en un BST de forma que el resultado sea otro BST (se conserve el invariante)
82
7
Dos BSTs generados con elementos aleatorios:
84
Los rboles quedan muy desequilibrados L
La insercin de una coleccin ordenada produce BSTs degenerados
85
Recorriendo en orden un BST obtenemos la lista ordenada de sus elementos (algoritmo tree sort)
mkBST :: (Ord a) => [a] -> BST a mkBST xs = foldr insert empty xs treeSort :: (Ord a) => [a] -> [a] treeSort = inOrderB . mkBST
86
[1,3,4,6,7,8,9] inOrderB mkBST [9,7,4,1,8,3,6]
search :: (Ord a) => a -> BST a -> Maybe asearch x' Empty = Nothingsearch x' (Node x lt rt) | x'==x = Just x | x' a -> BST a -> BoolisElem x t = isJust (search x t)
87
data Maybe a = Nothing | Just a isJust :: Maybe a -> Bool isJust (Just _) = True isJust Nothing = False
May
be
search 4 search 10
El mnimo elemento se encuentra en la posicin ms a la izquierda (al nal de la espina izquierda):
88
Mnimo elemento
minim :: BST a -> aminim Empty = error "minim on empty tree"minim (Node x Empty rt) = xminim (Node x lt rt) = minim lt
El mximo elemento se encuentra al nal de la espina derecha:
89
Mximo elemento
maxim :: BST a -> amaxim Empty = error "maxim on empty tree"maxim (Node x lt Empty) = xmaxim (Node x lt rt) = maxim rt
En la primera fase localizamos el elemento siguiendo un algoritmo parecido al de insercin.
(a) Si el nodo a eliminar es una hoja, se elimina sin ms
90
delete 'c' =>
hoja
Man7ene invariante el orden
En la primera fase localizamos el elemento siguiendo un algoritmo parecido al de insercin.
(b) Si el nodo a eliminar 7ene un solo hijo, el nodo padre puede conectarse con el nodo hijo.
91
delete b' =>
Solo 1 hijo
Man7ene invariante el orden
En la primera fase localizamos el elemento siguiendo un algoritmo parecido al de insercin.
(c) Si el nodo a borrar 7ene dos hijos: El mnimo elemento del hijo derecho sus7tuir al elemento a borrar. El rbol
resultante sigue siendo un BST
92
delete d' =>
2 hijos
Hijo derecho
Mnimo del hijo derecho
Man7ene Invariante el orden
En la primer fase localizamos el elemento siguiendo un algoritmo parecido al de insercin.
(c) Si el nodo a borrar 7ene dos hijos: Alterna7vamente: El mximo elemento del hijo izquierdo sus7tuir al
elemento a borrar. El rbol resultante sigue siendo un BST
93
delete d' =>
Hijo izquierdo
Man7ene invariante el orden
Mximo del hijo izquierdo
2 hijos
Quitar y devolver el mnimo elemento de un rbol:
94
split
split :: BST a -> (a,BST a)split (Node x Empty rt) = (x,rt)split (Node x lt rt) = (m,Node x lt' rt) where (m,lt') = split lt
=> ( , ) 1
delete :: (Ord a) => a -> BST a -> BST adelete x' Empty = Emptydelete x' (Node x lt rt) | x'==x = join lt rt | x' BST a -> BST ajoin Empty rt = rtjoin lt Empty = ltjoin lt rt = Node m lt rt' where (m,rt') = split rt
95
Mnimo elemento del rbol derecho
rbol derecho sin el elemento
mnimo
Uno de los hijos es vaco
Todas las claves de lt son menores que las de rt,
luego x es mayor que las claves de lt
(*) Podemos obtener complejidades en O(log n) si imponemos a los BST condiciones de balanceo; por ejemplo, AVL 96
Operacin Coste empty O(1) isEmpty O(1) insert O(n) isElem O(n) delete O(n) minim O(n) maxim O(n)
public void insert(K key, V value) { root = insertRec(root, key, value); } // returns modified tree private Tree insertRec(Tree node, K key, V value) { if (node == null) { node = new Tree(key,value); // new node size++; } else if (key.compareTo(node.key) == 0) node.value = value; // key was already present else if (key.compareTo(node.key) < 0) node.left = insertRec(node.left, key, value); else node.right = insertRec(node.right, key, value); return node; }
100
Inserta un nodo con clave key y valor value en el rbol. Si el nodo con key ya exista se
reemplaza el valor con el nuevo
// precondicin: node no es un rbol vaco // Elimina la clave mnima y su valor asociado del rbol primer // argumento, dejando la clave mnima y su valor en el segundo //argumento private static Tree
split(Tree node, Tree temp) { if (node.left == null) { // min encontrado: copia clave y valor al 2 arg. temp temp.key = node.key; temp.value = node.value; return node.right; // devuelve el hijo derecho } else { // elimina el mnimo de la subrama izquierda node.left = split(node.left, temp); return node; } }
101
2 hijos
Hijo derecho
Mnimo del hijo derecho
public void delete(K key) { root = deleteRec(root, key); } // Devuelve el rbol modificado private Tree deleteRec(Tree node, K key) { if (node == null) ; // key no encontrada; no hacemos nada else if (key.compareTo(node.key) == 0) { if (node.left == null) node = node.right; else if (node.right == null) node = node.left; else // tiene dos hijos node.right = split(node.right, node);
size--; } else if (key.compareTo(node.key) < 0) node.left = deleteRec(node.left, key); else node.right = deleteRec(node.right, key); return node; }
102
Borra el nodo con clave key
Quitamos el mnimo de node.right, pero copiando antes su contenido en node
2 hijos
103
Recordemos las interfaces: Consideraremos cinco mtodos para generar un objeto del 7po Iterable para recorrer (iterar) un BST, manipulando claves, valores, o ambos, u7lizando los recorridos estndar: - Por claves
Preorden: Iterable preOrder(); PostOrden: Iterable postOrder(); InOrden: Iterable inOrder();
- Por valores: Iterable values();- Por pares (clave, valor): Iterable keysValues();
public interface Iterator { boolean hasNext(); T next(); void remove();}
public interface Iterable { Iterator iterator();}
public interface SearchTree
de tipo Iterable
BST bst = new BST(); bst.insert(5, "five"); bst.insert(2, "two"); bst.insert(7, "seven"); bst.insert(1, "one"); bst.insert(3, "three"); System.out.println("InOrder traversal:"); for(int i : bst.inOrder()) { System.out.printf("%d ",i); } System.out.println(); System.out.println("InOrder traversal:"); Iterator it = bst.inOrder().iterator(); while(it.hasNext()) System.out.printf("%d ",it.next()); System.out.println(); System.out.println(KeysValues inOrder traversal:"); for(Tuple par : bst.keysValues()) { System.out.printf("%d %s", par._1(), par._2() ); } System.out.println(); 104
1 one 2 two 3 three 5 five 7 seven
Devuelve un iterador que recorre las claves del rbol
en orden
Ambos Imprimen: 1 2 3 5 7
Ambos Imprimen: 1 2 3 5 7
Usa un stack para organizar los nodos pendientes
105 stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
Visitaremos la clave y valor en segundo lugar
Para recorrer los elementos, se guardan en
un stack
Visitaremo la subrama derecha en tercer lugar
root
El stack se usar organizar el orden de los elementos a visitar. El stack debe guardar dos 7pos de rboles - rboles para visitar (red tree) - rboles de los que solo interesa la clave y el valor
del nodo raz (blue tree)
Visitaremos la subrama izquierda en primer lugar
Visitaremos la subrama izquierda en primer lugar
(red)
Visitaremos el nodo en segundo lugar (blue)
Visitaremos la subrama derecha en tercer lugar
(red)
106
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree() es un mtodo de la clase Traversal que encapsula el stack; las sucesivas llamadas cambian el stack y generan una secuencia de referencias a nodos
nextTree =>
107
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push right subtree in stack push key in stack if (node.left != null) push left subtree in stack}
nextTree =>
108
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
109
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push right subtree in stack push key in stack if (node.left != null) push left subtree in stack}
nextTree =>
110
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
111
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
112
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
113
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
114
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
115
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
116
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
117
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
118
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue nodein stack if (node.left != null) push red left subtree in stack}
nextTree =>
119
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
120
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
121
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
122
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
123
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
124
public Tree nextTree() { t = stack.top(); stack.pop(); while (t is a red tree) { save(t); t = stack.top(); stack.pop(); } return t; //blue tree }
t
stack
void save(Tree node) { // en orden inverso, el stack es LIFO if (node.right != null) push red right subtree in stack push blue node in stack if (node.left != null) push red left subtree in stack}
nextTree =>
El stack debe ser capaz de diferenciar los rboles almacenados (red o blue)
El 7po base del stack ser Either< Tree, Tree > Un objeto del 7po Either pueden guardar: o un valor de 7po A (izquierda), o un valor de 7po B (derecha) Los rboles blue son los de la izquierda y red los de la derecha EJEMPLO
Either either = new Left(5); if(either.isLeft()) Integer n = either.left(); either = new Right("five"); if(either.isRight()) String s = either.right();
125
Either guarda el Integer 5
true si either guarda un Integer
Either guarda el String "five"
true si either guarda un String
Devuelve el Integer de either
Devuelve el String de either
package dataStructures.either;public interface Either { boolean isLeft(); boolean isRight(); A left(); B right();}public class Left implements Either { private A left; public Left(A x) { left = x; } public boolean isLeft() { return true; } public boolean isRight() { return false; } public A left() { return left; } public B right() { throw new NoSuchElementException("right on Left object"); } public String toString() { return "Left("+left+")"; }}public class Right implements Either { private B right; public Right(B x) { right = x; } ... }
126
private abstract class Traversal { Stack stack = new LinkedStack(); abstract void save(Tree node); public Traversal() { if (root != null) save(root); } public boolean hasNext() { return !stack.isEmpty(); } public Tree nextTree() { if (!hasNext()) throw new NoSuchElementException(); Either either = stack.top(); stack.pop(); while (either.isRight()) { Tree node = either.right(); save(node); either = stack.top(); stack.pop(); } return either.left(); } public void remove() { throw new UnsupportedOperationException(); }}
127
Stack puede guardar o bien un rbol del que
nos interesan valor y raz (valor a la izquierda) o
bien un rbol para visitar (valor a la derecha)
Ser definido para cada recorrido: inOrder,
preOrder y postOrder
No hay ms elementos ya que el
stack est vacio
Mientras sea un rbol de la derecha hay que visitarlo
Es un rbol de la izquierda. Nos interesa solo la clave y el valor
Inicializa el stack
128
public class InOrderTravesal extends Travesal { void save(Tree node) { // in reverse order, cause stack is LIFO if (node.right != null) stack.push(new Right(node.right)); stack.push(new Left(node)); if (node.left != null) stack.push(new Right(node.left)); }}
Visitamos rbol con clave y valor en
segundo lugar (left)
Visitamos el subrbol izquierdo en primer
lugar (right)
Visitamos el subrbol derecho en
tercer lugar (right)
private class InOrderIt extends InOrderTraversal implements Iterator {"public K next() {" "return super.nextTree().key;"}
}public class BST
129
public class PreOrderTraversal extends Traversal { void save(Tree node) { // in reverse order, cause stack is LIFO if (node.right != null) stack.push(new Right(node.right)); if (node.left != null) stack.push(new Right(node.left)); stack.push(new Left(node)); }}
Visitamos rbol con clave y valor en primer lugar (left)
Visitamos el subrbol izquierdo en segundo
lugar (right)
Visitamos el subrbol derecho en
tercer lugar (right)
private class PreOrderIt extends PreOrderTraversal implements Iterator {"public K next() {" "return super.nextTree().key;"}
}public class BST
130
public class PostOrderTravesal extends Travesal { void save(Tree node) { // in reverse order, cause stack is LIFO stack.push(new Left(node)); if (node.right != null) stack.push(new Right(node.right)); if (node.left != null) stack.push(new Right(node.left)); }}
Visitamos rbol con clave y valor en tercer
lugar (left)
Visitamos el subrbol izquierdo en primer
lugar (right)
Visitamos el subrbol derecho en segundo lugar (right)
private class PostOrderIt extends PostOrderTraversal implements Iterator {"public K next() {" "return super.nextTree().key;"}
}public class BST
131
private class ValuesIt extends InOrderTraversal implements Iterator {"public V next() {" "return super.nextTree().value;"}
}
public class BST
132
private class KeyValuesIt extends InOrderTraversal !! ! ! ! !implements Iterator {"public Tuple2 next() {" "Tree node = super.nextTree();" "return new Tuple2(node.key, node.value);"}
}
public class BST
Si las operaciones de insercin y eliminacin en un BST man7enen la altura pequea, el rbol se dice balanceado en altura; tales operaciones pueden llegar a tener una complejidad p7ma O(log n); sin balanceo pueden elevarse hasta O(n)
Existen varias aproximaciones a los rboles balanceados: rboles AVL rboles 2-3 y 2-3-4 rboles Rojo-negro (Red-Black)
133
h|p://en.wikipedia.org/wiki/Self-balancing_binary_search_tree
Llamados as por el nombre de sus creadores, Adelson-Velskii y Landis: "An algorithm for the organiza7on of informa7on (1962)
Los rboles AVL son rboles binarios de bsqueda que sa7sfacen la propiedad de balanceado-en-altura (height-balance) :
en cada nodo, las alturas de sus hijos dieren a lo sumo en 1
134
h|p://en.wikipedia.org/wiki/AVL_tree
Todos estos son rboles AVL
data AVL a = Empty | Node a Int (AVL a) (AVL a)height :: AVL a -> Intheight Empty = 0height (Node k h lt rt) = hisAVL :: (Ord a) => AVL a -> BoolisAVL Empty = TrueisAVL (Node k h lt rt) = forAll (k) rt && abs (height lt - height rt) Bool) -> AVL a -> Bool forAll p Empty = True forAll p (Node x h lt rt) =
p x && forAll p lt && forAll p rt
135
2
1 1
4
1 1 1
22
3
000 00 0
0 00 0 0
En cada nodo mantenemos su altura Altura
Dos rboles AVL con 50 elementos aleatorios:
136
La altura h de un rbol AVL con n elementos es O(log n) h log (n+1) Sea N(h) el mnimo nmero de nodos de un AVL de altura h:
N(1) = 1 N(2) = 2 N(h) = 1 + N(h - 1) + N(h - 2) , h > 2
Probaremos: h 1 N(h), luego h log (n+1)
137
rboles AVL trees con alturas 1,2 y 3
La altura de un hijo debe ser
h -1
La diferencia de las alturas de los hijos debe ser 1, y el mnimo de
nodos corresponde a h-2
Nodo de la raz de un rbol de
atura h
= 1+5/2
El nmero de oro es la raz posi7va de la ecuacin
x2 = 1 + x, es decir
Por tanto, 2 = 1 + , y de aqu: n+2 = n + n+1
138
... 87498951.618033982
51 =+=
Usando h = h-1 + h-2, es fcil demostrar (por induccin sobre h) que la funcin N(h) denida por la recurrencia: N(0) = 0, N(1) = 1, N(h) = 1 + N(h - 1) + N(h - 2) , h > 1
sa7sface h 1 N(h) h+1 1 Pero si n es nmero de nodos de un rbol AVL de altura h, entonces N(h) n, de donde h 1 n y de aqu: h log (n+1) Recordemos que para todo rbol: log2 (n+1) h
139
El nmero de oro (de Fidias?) y los nmeros de Fibonacci aparecen de mltiples formas - en la arquitectura y el arte
el Partenn de Fidias, la Gioconda de Leonardo da Vinci, - en el reino vegetal, animal, astronoma
girasol, concha del Nautilus, la forma de algunas galaxias
- en todas las ciencias, y en computacin ! geometra, grafos, recurrencias,
Relacin con los nmeros de Fibonacci:
140
( )nnnf = )(51
n
n
ff 1lim += 1+= nn
n ff
Origen del nmero ureo o divina proporcin Segn Euclides en sus Elementos (Libro VI), es la proporcin entre media y extrema razn: el todo es a la parte como la parte al resto. Es decir,
o tambin Construccin de un Rectngulo ureo
Fernando Corbaln, La proporcin urea, RBA (2010) Entrevista a Fernando Corbaln (You Tube)
141
11
1 =x
xba
aba=
+
Una rotacin es una operacin que cambia ligeramente la estructura de un rbol binario de bsqueda sin violar el invariante del orden
Una rotacin mueve un nodo hacia arriba y otro hacia abajo. Un subrbol es desconectado del nodo subido y enganchado al nodo bajado
Las rotaciones se usan para rebalancear la altura de los rboles binarios de bsqueda
142
Construye un nuevo nodo a par7r de dos rboles AVL y un valor, memorizando la altura del nuevo nodo
node :: a -> AVL a -> AVL a -> AVL a node k lt rt = Node k h lt rt where h = 1 + max (height lt) (height rt)
143
node 4 => 2 23
144
rotR :: AVL a -> AVL arotR (Node k h (Node lk lh llt lrt) rt) = node lk llt (node k lrt rt)
0 5
3
7
9
lrt
rt
llt
lk
k
9 5
7
3
0
lrt rt
llt
lk
k
145
rotR :: AVL a -> AVL arotR (Node k h (Node lk lh llt lrt) rt) = node lk llt (node k lrt rt)
3
7
lrt
rt
llt
lk
k
mayores que 3 y
menores que 7 menores
que 3
mayores que 7
7
3
lrt rt
llt
lk
k
Man7ene invariante el orden
menores que 3
mayores que 3 y
menores que 7 mayores
que 7
146
rotL :: AVL a -> AVL arotL (Node k h lt (Node rk rh rlt rrt)) = node rk (node k lt rlt) rrt
9 5
7
3
0
rlt rrt
lt
k
rk
0 5
3
7
9
lrt
rrt
lt
k
rk
147
rotL :: AVL a -> AVL arotL (Node k h lt (Node rk rh rlt rrt)) = node rk (node k lt rlt) rrt
7
3
rlt rrt
lt
k
rk 3
7
rlt
rrt
lt
k
rk
Man7ene invariante el orden
mayores que 7
menores que 3
mayores que 3 y
menores que 7
mayores que 7
menores que 3
mayores que 3 y
menores que 7
La insercin en un AVL 7ene dos fases: - insercin como en un BST - rebalanceo de los nodos modicados:
148
insert 0
1 0 No necesita rebalanceo
La insercin en un AVL 7ene dos fases: - insercin como en un BST - rebalanceo de los nodos modicados:
149
insert 0 1
No necesita rebalanceo
2
La insercin en un AVL 7ene dos fases: - insercin como en un BST - rebalanceo de los nodos modicados:
150
insert 0 1
Necesita rotacin simple rotR ya que la altura del hijo es
dos unidades mayor que la del hijo
derecho
3
La insercin en un AVL 7ene dos fases: - insercin como en un BST - rebalanceo de los nodos modicados:
151
insert 0 rotR
Este es un rbol AVL
152
insert 7
0 1 No necesita rebalanceo
Una rotacin simple a la derecha no produce el balanceo
153
insert 7 1
No necesita rebalanceo 2
154
insert 7 0 1
Necesita doble rotacin
Inclinado a la derecha
155
insert 7 rotL
hijo izquierdo
156
insert 7
Este es un rbol AVL
rotL hijo izquierdo
Igual que la insercin en un rbol Binario de Bsqueda pero restaurando el balanceo en todos los nodos modicados:
insert :: (Ord a) => a -> AVL a -> AVL ainsert k' Empty = node k' Empty Emptyinsert k' (Node k h lt rt) | k == k = Node k' h lt rt | k < k = balance k (insert k' lt) rt | otherwise = balance k lt (insert k' rt)
157
Solo deben ser rebalanceados los nodos modicados en el camino desde la raz
hasta el punto de insercin
158
h
h+1
h+2
h
h+1
h+2
h
h+1
h+2
insert
Este es un rbol AVL
Puede volver a balancearse con una
simple rotacin
Tras la insercin la rama izquierda se
descompensa
Ahora no es un rbol AVL
L 1
159
h
h+1
h+2
h
h+1
h+2
h
h+1
h+2
1
Este es un rbol AVL
Puede rebalancearse con una doble
rotacin
Tras la insercin, la rama izquierda se
descompensa
Ahora no es un rbol AVL
L
insert
160
h
h+1
h+2
insert
Este es un rbol AVL
Puede rebalancearse con una simple
rotacin
Tras la insercin, la rama derecha se
descompensa
Ahora no es un rbol AVL
L h
h+1
h+2
h
h+1
h+2
1
161
h
h+1
h+2
insert
Este es un rbol AVL
Puede rebalancearse con una doble
rotacin
Tras la insercin, la rama derecha se
descompensa
Ahora no es un rbol AVL
L h
h+1
h+2
h
h+1
h+2
1
rightLeaning :: AVL a -> Bool rightLeaning (Node x h lt rt) = height lt < height rt leftLeaning :: AVL a -> Bool leftLeaning (Node x h lt rt) = height lt > height rt
162
163
h
h+1
h+2
lt
k
rt
2
balance :: a -> AVL a -> AVL a -> AVL abalance k lt rt | (lh-rh > 1) && leftLeaning lt = rotR (node k lt rt) | (lh-rh > 1) = rotR (node k (rotL lt) rt) | (rh-lh > 1) && rightLeaning rt = rotL (node k lt rt) | (rh-lh > 1) = rotL (node k lt (rotR rt)) | otherwise = node k lt rt where lh = height lt rh = height rt
Rotacin a la derecha
rotR (node k lt rt)
h
h+1
h+2
164
h
h+1
h+2
rt
k
lt
2
Rotacin a la izquierda
rotL (node k lt rt)
h
h+1
h+2
balance :: a -> AVL a -> AVL a -> AVL abalance k lt rt | (lh-rh > 1) && leftLeaning lt = rotR (node k lt rt) | (lh-rh > 1) = rotR (node k (rotL lt) rt) | (rh-lh > 1) && rightLeaning rt = rotL (node k lt rt) | (rh-lh > 1) = rotL (node k lt (rotR rt)) | otherwise = node k lt rt where lh = height lt rh = height rt
165
h
h+1
h+2
lt
k
rt
2
h
h+1
h+2
h
h+1
h+2
k
Rotacin a la izquierda en el subrbol izquierdo (lt)
Rotacin a la derecha en la raz
rotR (node k (rotL lt) rt)
balance :: a -> AVL a -> AVL a -> AVL abalance k lt rt | (lh-rh > 1) && leftLeaning lt = rotR (node k lt rt) | (lh-rh > 1) = rotR (node k (rotL lt) rt) | (rh-lh > 1) && rightLeaning rt = rotL (node k lt rt) | (rh-lh > 1) = rotL (node k lt (rotR rt)) | otherwise = node k lt rt where lh = height lt rh = height rt
Solo una de estas ramas tiene h+2
166
h
h+1
h+2
rt
k
lt
2
h
h+1
h+2
h
h+1
h+2
k
Rotacin a la derecha en el subrbol derecho (rt)
rotL (node k lt (rotR rt))
balance :: a -> AVL a -> AVL a -> AVL abalance k lt rt | (lh-rh > 1) && leftLeaning lt = rotR (node k lt rt) | (lh-rh > 1) = rotR (node k (rotL lt) rt) | (rh-lh > 1) && rightLeaning rt = rotL (node k lt rt) | (rh-lh > 1) = rotL (node k lt (rotR rt)) | otherwise = node k lt rt where lh = height lt rh = height rt
Rotacin a la izquierda en la raz
Solo una de estas ramas tiene h+2
Igual que en rboles Binarios de Bsqueda: search :: (Ord a) => a -> AVL a -> Maybe a search k' Empty = Nothing search k' (Node k h lt rt) | k'==k = Just k | k' a -> AVL a -> Bool isElem k t = isJust (search k t)
167
data Maybe a = Nothing | Just a isJust :: Maybe a -> Bool isJust (Just _) = True isJust Nothing = False
May
be
search 4 search 10
Igual que en un rbol Binario de Bsqueda, pero restaurando el balanceo en los nodos modicados:
delete :: (Ord a) => a -> AVL a -> AVL a delete k' Empty = Empty delete k' (Node k h lt rt) | k'==k = join lt rt | k' AVL a -> AVL a join Empty rt = rt join lt Empty = lt join lt rt = balance k' lt rt' where (k',rt') = split rt -- Elimina y devuelve el mnimo elemento de un rbol split :: AVL a -> (a,AVL a) split (Node k h Empty rt) = (k,rt) split (Node k h lt rt) = (k',balance k lt' rt) where (k',lt') = split lt
168
(*) Comprense con los costes para un BST estndar
169
Operacin Coste empty O(1) isEmpty O(1) insert O(log n) isElem O(log n) delete O(log n) minim O(log n) maxim O(log n)
public static int height(Tree tree) { return tree == null ? 0 : tree.height; } public boolean rightLeaning() { return height(left) < height(right); } public boolean leftLeaning() { return height(left) > height(right); } void setHeight() { height = 1 + Math.max(height(left), height(right)); }
171
// rota a la derecha el receptor. Devuelve la nueva raz public Tree rotR() { Tree lt = this.left; Tree lrt = lt.right; this.left = lrt; this.setHeight(); lt.right = this; lt.setHeight(); return lt; }
172
0 5
3
7
9
lrt
lt
this
9 5
7
3
0
lrt
lt
this
// Rota a la izquierda el receptor. Devuelve la nueva raz public Tree rotL() { Tree rt = this.right; Tree rlt = rt.left; this.right = rlt; this.setHeight(); rt.left = this; rt.setHeight(); return rt; }
173
9 5
7
3
0
rlt
this
rt
0 5
3
7
9
lrt
this
rt
// Balancea el receptor. Devuelve el nodo despues de balancearlopublic Tree balance() { int lh = height(left); int rh = height(right);
Tree balanced;
if (lh - rh > 1 && left.leftLeaning()) { balanced = this.rotR(); //Se necesita simple rotacin } else if (lh - rh > 1) { left = left.rotL(); //Se necesita doble rotacin balanced = this.rotR(); } else if (rh - lh > 1 && right.rightLeaning()) { balanced = this.rotL(); //Se necesita simple rotacin } else if (rh - lh > 1) { right = right.rotR(); //Se necesita doble rotacin balanced = this.rotL(); } else { balanced = this; //No se necesita rotacin balanced.setHeight(); } return balanced; } 174
Igual que la insercin en un rbol Binario de Bsqueda pero restaurando el balanceo en todos los nodos modicados:
public void insert(K k, V v) { root = AVL.insertRec(root, k, v); } // returns modified tree private static
Un diccionario permite manejar echas (asociaciones) entre un conjunto de claves a y un conjunto de valores b: data Dict a b -- un diccionario vacoempty :: Dict a b isEmpty :: Dict a b -> Bool -- inserta/aade una asociacin en un diccionarioinsert :: (Eq a) => a -> b -> Dict a b -> Dict a b-- recupera el valor en el diccionariovalueOf :: (Eq a) => a -> Dict a b -> Maybe b
177
True ==> isEmpty emptyTrue ==> not (isEmpty (insert k v d))True ==> valueOf k empty == Nothingk==k' ==> valueOf k (insert k' v' d) == Just v'k/=k' ==> valueOf k (insert k' v' d) == valueOf k dTrue ==> insert k v' (insert k v d) = insert k v' dk/=k' ==> insert k' v' (insert k v d) == insert k v (insert k' v' d)
178
Un diccionario puede ser implementado ecientemente usando un rbol AVL con claves y valores en los nodos
Los nodos deberan ordenarse segn la clave
179
1 "one" 3 "three"
9 "nine"
5 "five"
2 "two"
Clave Valor
data Dict a b = D (T.AVL (Rel a b)) -- las operaciones son delegadas a operaciones con AVLempty :: Dict a bempty = D T.emptyisEmpty :: Dict a b -> BoolisEmpty (D avl) = T.isEmpty avlinsert :: (Ord a) => a -> b -> Dict a b -> Dict a binsert k v (D avl) = D (T.insert (k :-> v) avl)valueOf :: (Ord a) => a -> Dict a b -> Maybe bvalueOf k (D avl) = case T.search (k :-> undefined) avl of Nothing -> Nothing Just (_ :-> v) -> Just v
181
Un diccionario es vaco si lo es como rbol AVL
La complejidad de las operaciones son las correspondientes a un rbol AVL:
182
Operacin Coste empty O(1) isEmpty O(1) insert O(log n) valueOf O(log n)