arboles

download arboles

of 182

description

estructura de datos

Transcript of arboles

  • 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

  • data Tree a = Empty | Node a [Tree a] deriving Showtree1 :: Tree Inttree1 = Node 1 [ Node 2 [ Node 4 [ ] , Node 5 [ ] , Node 6 [ ] ] , Node 3 [ Node 7 [ ] ] ]sumT :: (Num a) => Tree a -> asumT Empty = 0sumT (Node x ts) = x + sum [sumT t | t
  • 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

  • module DataStructures.PriorityQueue.LinearPriorityQueue ( PQueue empty -- :: PQueue a isEmpty -- :: PQueue a -> Bool enqueue -- :: (Ord a) => a -> PQueue a -> PQueue a first -- :: PQueue a -> a dequeue -- :: PQueue a -> PQueue a ) wheredata PQueue a = Empty | Node a (PQueue a) empty :: PQueue aempty = EmptyisEmpty :: PQueue a -> BoolisEmpty Empty = TrueisEmpty _ = Falseenqueue :: (Ord a) => a -> PQueue a -> PQueue aenqueue x Empty = Node x Emptyenqueue x (Node y q) | y
  • 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

  • package dataStructures.heap;public interface Heap
  • package dataStructures.heap; public class BinaryHeap
  • // 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 static int ROOT_INDEX = 0; // root of heap is at index 0 private boolean isRoot(int idx) { // true if idx is index at root of tree return idx==ROOT_INDEX; } private int parent(int idx) { // index for parent of node with index idx return (idx-1) / 2; // integer division } private int leftChild(int idx) { // index for left child of node with index idx return 2*idx+1; } private int rightChild(int idx) { // index for right child of node with index idx return 1+leftChild(idx); } private boolean isNode(int idx) { // true if idx corresponds to index of a node in tree return idx
  • 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

  • package dataStructures.heap;public class WeigthBiasedLeftistHeap
  • 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

  • // Merges two heap trees along their right spines.!// Returns merged heap.!private static
  • // mezcla dos MZs a lo largo de sus espinas derechas, devolviendo un MZ private static
  • 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

  • insert :: (Ord a) => a -> BST a -> BST ainsert x' Empty = Node x' Empty Emptyinsert x' (Node x lt rt) | x'==x = Node x' lt rt | x'
  • 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)

  • Ser interesante disponer de una interfaz para dis7ntas versiones de los BST (los puros y los equilibrados AVL) package dataStructures.binarySearchTree;import dataStructures.tuple.Tuple2;public interface SearchTree
  • package dataStructures.binarySearchTree;public class BST
  • public V search(K key) { return BST.searchRec(root, key); } private static
  • 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)

  • package dataStructures.SearchTree;public class AVL
  • 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 en un rbol Binario de Bsqueda: public V search(K key) { return AVL.searchRec(root, key); } private static
  • 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

  • module DataStructures.Dictionary.AVLDictionary ( Dict , empty , isEmpty , insert , get ) whereimport qualified DataStructures.BinarySearchTree.AVL as Tdata Rel a b = a :-> binstance (Eq a) => Eq (Rel a b) where (k :-> _) == (k' :-> _) = (k == k') instance (Ord a) => Ord (Rel a b) where (k :-> _)
  • 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)