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
rboles
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
MonYculo
binario
(Binary
Heap)
como
AB
completo
Insercin
y
eliminacin.
Representacin
de
un
AB
Completo
con
un
Array
MonYculos
en
Java;
representacin
va
arrays
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
Iterador
En-Orden
para
BST
Either:
Tipo
unin
en
Java
Implementacin
de
iteradores
rboles
AVL
MonYculos
zurdos
(Weight
Biased
Le;ist
Heaps)
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
Especicacin.
Implementacin
lineal
(Haskell)
MonYculos.
Propiedad
del
monYculo
(Heap-Order
Prop.)
Terminologa,
Denicin
formal
rboles
en
Haskell
rboles
binarios
rboles
binarios
de
bsqueda
(Binary
Search
Tree,BST)
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
10
:->
:/\
:\/
Var
No
Var
Var
Var
"p"
"q"
"q"
15
"p"
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:
raz
2
es
padre
de
5
y
6
interno
2
5
es
un
hijo
de
2
hoja
6
es
un
hijo
de
2
9
4
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,
1
es
abuelo
de
5,
6,
7,
8
y
9
o
7ene
varios
,
y
cualesquiera
dos
consecu7vos
forman
un
arco
Un
camino
1
Un
arco
6
es
hermano
de
5
9
5
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
data Tree a = Empty | Node a [Tree a] deriving Show
Lista
de
subrboles
hijos
Valor
del
nodo
Constructor
del
rbol
vaco
tree1 :: Tree Int
tree1 =
Node 1 [ Node 2 [ Node 4 [ ]
, Node 5 [ ]
, Node 6 [ ]
]
, Node 3 [ Node 7 [ ] ]
]
Una
hoja
Suma
los
valores
de
los
nodos
4
sumT :: (Num a) => Tree a -> a
sumT Empty
= 0
sumT (Node x ts) = x + sum [sumT t | t <- ts]
Los
datos
en
un
rbol
se
organizan
en
niveles:
Nivel
0
La
raz
est
en
el
nivel
0
Los
hijos
de
la
raz
en
el
nivel
1
Los
nietos
en
el
nivel
2
Nivel
1
etc.
4
Nivel
2
La
altura
de
un
rbol
se
dene
como:
heightT
heightT
heightT
heightT
:: Tree a -> Int
Empty
= 0
(Node x []) = 1
(Node x ts) = 1 + maximum [heightT t | t <- ts]
rbol
binario:
Cada
nodo
7ene
a
lo
sumo
dos
hijos
Los
hijos
se
denominan
hijo
izquierdo
e
hijo
derecho
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
n:
nmero
de
nodos
h:
altura
Se
da
la
igualdad
para
cada
rbol
pefecto
Para
todo
rbol
binario
no
vaco
h
n 2h-1 (= 1
+
2
+
22 +
+
2h-1)
1+log2(n)
h n
1+n
<=2h
log2(1+n)
<=
h
log2(n)
<
log2
(1+n)
<=
h
1
+log2(n)
<=
h
3
n
23
-1
h=
3
n=
7
1+log2(7)
h
7
11
data TreeB a = EmptyB | NodeB a (TreeB a) (TreeB a) deriving Show
Constructor
del
rbol
vaco
Valor
del
nodo
Subrbol
derecho
Subrbol
i
zquierdo
tree2 :: TreeB Int
tree2 =
NodeB 1 (NodeB 2 (NodeB 4 EmptyB EmptyB)
(NodeB 5 EmptyB EmptyB))
(NodeB 3 (NodeB 6 EmptyB EmptyB)
EmptyB)
-- suma de valores de los nodos
sumB :: (Num a) => TreeB a -> a
sumB EmptyB
= 0
sumB (NodeB x lt rt) = x + sumB lt + sumB rt
Subrbol
izquierdo
(Le;
subtree)
Right
subtree
12
data TreeB a = EmptyB | NodeB a (TreeB a) (TreeB a) deriving Show
la lista de nodos de cierto nivel de un rbol
-
atLevelB
:: 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
Nivel
0
Main> atLevelB 0 tree2
[1]
Nivel
1
Main> atLevelB 1 tree2
[2,3]
Nivel
2
Main> atLevelB 2 tree2
[4,5,6]
13
- 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]
14
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 rt
inOrderB :: TreeB a -> [a]
-- o recorrido en profundidad
inOrderB EmptyB
= []
inOrderB (NodeB x lt rt) = inOrderB lt ++ [x] ++ inOrderB rt
postOrderB :: TreeB a -> [a]
postOrderB EmptyB
= []
postOrderB (NodeB x lt rt) = postOrderB lt ++ postOrderB rt ++ [x]
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]
16
Sea
xs
una
lista
Pretendemos
construir
un
rbol
binario
t
de
altura
mnima,
vericando
adems
inOrderB t = xs
minTreeB [1..7] =>
minTreeB [1..6] =>
17
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
minTreeB :: [a] -> TreeB a
+++ OK, passed 100 tests.
minTreeB []
= EmptyB
minTreeB xs
= NodeB z (minTreeB yz) (minTreeB zs)
where
m = length xs `div` 2
(yz,z:zs) = splitAt m xs
p_minTreeB xs = n>0 ==> inOrderB t == xs
&& heightB t == 1 + log2 n
where
t = minTreeB xs
n = length xs
Es
fcil
demostrar
estas
dos
igualdades
por
induccin
sobre
la
longitud
de
la
lista xs
log2 :: Int -> Int
log2 x = truncate (logBase 2 (fromIntegral x))
18
minTreeB :: [a] -> TreeB a
minTreeB []
= EmptyB
minTreeB 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
splitAt
es
O(n)
La
solucin
T(n)
est
en
O(n
log
n)
L
19
minTreeB' :: [a] -> TreeB a
minTreeB' 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,
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
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
tail xs)
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
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.
vip
Los
elementos
pueden
insertarse
en
cualquier
orden
pero
son
extrados
de
la
cola
de
acuerdo
con
su
prioridad.
21
-- devuelve una cola vaca
empty :: PQueue a
-- test para colas vacas
isEmpty :: PQueue a -> Bool
-- inserta un elemento en una cola de prioridad
enqueue :: (Ord a) => a -> PQueue a -> PQueue a
-- devuelve el elemento de mnima prioridad
first :: (Ord a) => PQueue a -> a
-- devuelve la cola obtenida al eliminar
-- el elemento de mnima prioridad
dequeue :: (Ord a) => PQueue a -> PQueue a
22
isEmpty empty
-- q1
not (isEmpty (enqueue x q))
-- q2
first (enqueue x empty) == x
-- q3
dequeue (enqueue x empty) == empty
-- q4
Los
anteriores
axiomas
coinciden
con
los
de
Queue.
Tres
adicionales
capturan
el
comportamiento
SIFO
(smallest
in,
rst
out)
:
Los elementos con
igual prioridad salen
first (enqueue y (enqueue x q)) ==
first (enqueue (min x y) q)
en orden FIFO
dequeue (enqueue y (enqueue x q)) ==
enqueue (max x y ) (dequeue (enqueue (min x y ) q))
Ejercicio:
probar
first $ enq 3 $ enq 1 $ enq 2 empty == 1
-- pq1
-- pq2
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
) where
data PQueue a = Empty | Node a (PQueue a)
empty :: PQueue a
empty = Empty
isEmpty :: PQueue a -> Bool
isEmpty Empty = True
isEmpty _
= False
enqueue :: (Ord a) => a -> PQueue a -> PQueue a
Los elementos son encolados
enqueue x Empty = Node x Empty
en orden ascendente
enqueue x (Node y q)
Recursivamente, encola
| y <= x
= Node y (enqueue x q)
x detrs de y
| otherwise
= Node x (Node y q)
24
first :: PQueue a -> a
first Empty
= error "first on empty queue"
first (Node x _) = x
El elemento mnimo
aparece al principio
dequeue :: PQueue a -> PQueue a
dequeue Empty
= error "dequeue on empty queue"
dequeue (Node _ q) = q
Ejercicio:
implementar
la
Cola
con
Prioridad
en
Java
usando
una
lista
enlazada
25
Coste
para
la
implementacin
lineal:
Operacin
Coste
empty
O(1)
isEmpty
O(1)
enqueue
O(n)
first
O(1)
dequeue
O(1)
L pero podemos mejorarla
Veremos
implementaciones
de
colas
de
prioridad
que
mejoran
enqueue,
pero
empeoran
dequeue.
26
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
Este no es
un heap L
Un heap J
0
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
Un
monYculo
binario
es
un
rbol
binario
completo
que
sa7sface
HOP
(Heap-Order
property)
Un montculo
binario J
Un montculo
binario J
Este no es un
completo L
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
Queremos
aadir
un
elemento
a
un
monYculo
binario
de
forma
que
el
resultado
sea
otro
monYculo
binario
insert(0)
29
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
El resultado es un
rbol completo J
2)
Mientras
que
el
nuevo
elemento
sea
menor
que
el
padre:
Intercambiar
el
nuevo
con
el
padre
insert(0)
0
insert(0)
30
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
Para reestablecer la
propiedad HOP J
insert(0)
3
0
31
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
insert(0)
Swap 0 3
Para reestablecer la
propiedad HOP J
32
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
Para reestablecer la
propiedad HOP J
Un montculo
binario J
insert(0)
Swap 0 3
Swap 0 1
1
3
33
Recordemos
que
un
rbol
completo
con
n
elementos
7ene
altura
1+log2(n)
500
450
400
350
Nmero
de
pasos
En
el
peor
caso,
la
insercin
necesita
un
nmero
de
pasos
proporcional
a
log2(n)
300
250
Enorme
diferencia
entre
n
y
log
n
200
150
Luego,
insert est
en
O(log
n)
J
100
50
log
n
N
de
nodos
34
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
Esta fase conserva la
completitud J
7
Delete root
35
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)
c
on
u
Reestablecer la
propiedad HOP J
7
Delete root
2
5
3
4
36
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
Reestablecer la
propiedad HOP J
2)
Mientras
u
>
minChild(u)
:
Intercambiar
minChild(u)
c
on
u
7
Delete root
2
5
3
4
Swap 7 2
7
5
37
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
Reestablecer la
propiedad HOP J
2)
Mientras
u
>
minChild(u)
:
Intercambiar
minChild(u)
c
on
u
Swap 7 2
Delete root
7
5
38
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
Reestablecer la
propiedad HOP J
2)
Mientras
u
>
minChild(u)
:
Intercambiar
minChild(u)
c
on
u
El montculo
final J
Swap 7 2
Delete root
Swap 7 4
7
5
4
5
39
Los
nodos
de
un
ABC
pueden
colocarse
fcilmente
en
forma
consecu7va
dentro
de
un
array
por
niveles:
a
Nivel
0
Nivel
1
Nivel
2
b
d
0
a
Nivel
l
0
1
b
2
c
3
d
4
e
Nivel
1
5
f
Nive
l
2
f
hijos
Padres
e
hijos
pueden
localizarse
fcilmente
va
aritmBca
elemental:
La
raz
7ene
ndice
0
Para
el
nodo
de
ndice
i:
El
hijo
izquierdo
ocupa
la
pos.
2*i+1
El
hijo
derecho
ocupa
la
pos.
2*i+2
El
padre
ocupa
la
pos.
(i-1)/2
0
a
1
b
2
c
3
d
4
e
5
f
padres
40
package dataStructures.heap;
public interface Heap<T extends Comparable<? super T>> {
boolean isEmpty();
El tipo T de los elementos del
montculo debe implementar
int
size();
el mtodo (relacin de orden)
compareTo
void
insert(T x);
T
minElem();
void
delMin();
}
41
package dataStructures.heap;
public class BinaryHeap<T extends Comparable<? super T>>
implements Heap<T> {
private T elems[];
private int size; // number of elements in heap
private static int INITIAL_CAPACITY = 128;
public BinaryHeap() {
elems = (T[]) new Comparable[INITIAL_CAPACITY];
size = 0;
}
private void ensureCapacity() {
if(size == elems.length)
elems = Arrays.copyOf(elems,2*elems.length);
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
El tipo T de los elementos del
montculo debe implementar
el mtodo (relacin de orden)
compareTo
42
// 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<size;
}
private boolean hasLeftChild(int idx) { // true if node with index idx has a left child
return leftChild(idx)<size;
}
private boolean isLeaf(int idx) { //returns true if node with index idx is a leaf node
return !hasLeftChild(idx); // !hasLeftChild(idx) !hasRightChild(idx)
44
}
private void heapifyUp(int idx) {
while(!isRoot(idx)) {
= (idx-1) / 2
int idxParent = parent(idx);
if(lessThan(idx,idxParent)) {
swap(idx,idxParent);
idx = idxParent; // move to parent node for next iteration
} else
break;
heapifyUp(n) est en O(log n)
}
}
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
public T minElem() {
if(isEmpty())
throw new EmptyHeapException("minElem on empty heap");
else
return elems[ROOT_INDEX];
}
El mnimo siempre
se encuentra en la
raz J
46
private void heapifyDown() {
int idx = ROOT_INDEX; // start at root of tree
2*idx+1 >= size
while(!isLeaf(idx)) {
int idxChild = leftChild(idx);
=2*idx+1
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;
}
heapifyDown() est en O(log size)
}
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
}
Coste
de
las
operaciones:
Operacin
BinaryHeap
isEmpty
minElem
insert
delMin
Coste
O(1)
O(1)
O(1)
O(log
n)
O(log
n)
O(n) si redimensionamos
el array
48
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:
data Heap a = Empty | Node a Int (Heap a) (Heap a)
weight :: Heap a -> Int
Peso del nodo
weight Empty
= 0
weight (Node _ w _ _) = w
rbol con raz 'a'
con 6 elementos
h1 :: Heap Char
h1 = 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 b'
con 2 elementos
49
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
isWeightedLeftist :: Heap a -> Bool
isWeightedLeftist Empty
= True
isWeightedLeftist (Node _ _ lh rh) = weight lh >= weight rh
&& isWeightedLeftist lh
&& isWeightedLeftist rh
Un
heap
Weight
Biased
Le;ist
(WBLH)
es
un
rbol
Weight
Biased
Le;ist
que
sa7sface
la
propiedad
de
Heap-order
Es un
WBLH J
Es un
WBLH J
Es un
WBLH J
50
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
) where
data Heap a = Empty | Node a Int (Heap a) (Heap a) deriving Show
empty :: Heap a
empty = Empty
isEmpty :: Heap a -> Bool
isEmpty Empty = True
isEmpty _
= False
minElem :: Heap a -> a
minElem Empty
= error "minElem on empty heap"
minElem (Node x _ _ _) = x
El mnimo del montculo
es la raz del arbol
51
delMin :: (Ord a) => Heap a -> Heap a
delMin Empty
= error "delMin on empty heap"
delMin (Node _ _ lh rh) = merge lh rh
elimina la raz (el menor)
y mezcla los hijos
singleton :: a -> Heap a
singleton x = Node x 1 Empty Empty
insert :: (Ord a) => a -> Heap a -> Heap a
Crea un montculo de un elemento y
lo mezcla con el montculo
insert x h = merge (singleton x) h
merge :: (Ord a) => Heap a -> Heap a -> Heap a
...
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
52
Sea
llama
espina
derecha
de
un
rbol
binario
al
camino
desde
la
raz
hasta
el
nodo
terminal
ms
a
la
derecha
Espina derecha
rightSpine :: Heap a -> [a]
rightSpine Empty
= []
rightSpine (Node x _ _ rh) = x : rightSpine rh
Para
cualquier
WBLT
con
n
elementos,
la
longitud
de
su
espina
derecha
es
log2(n+1)
esto demostrar que la complejidad de merge es logartmica
53
-- longitud de la espina derecha
lrs :: Heap a -> Int
lrs Empty
= 0
lrs (Node x _ _ rh) = 1 + lrs rh
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
si
lrs lh
entonces
lh, q
=
weight rh
log2(p+1) && lrs rh log2(q+1)
lrs (Node x _ lh rh) log2(p+q+2) 54
Caso
base:
-- length of right spine
lrs :: Heap a -> Int
lrs Empty
= 0
lrs (Node x _ _ rh) = 1 + lrs rh
lrs Empty log2(0+1)
{- 1) ecuacin de lrs (parte izquierda)
0 log2(0+1)
{- aritmtica de log (parte derecha) -}
0 0
True
-}
55
Paso
induc7vo:
Sean
p
=
weight lh
y
q
=
weight rh
si
lrs lh
entonces
-- longitud de la espina derecha
lrs :: Heap a -> Int
lrs Empty
= 0
lrs (Node x _ _ rh) = 1 + lrs rh
Hiptesis de
induccin
log2(p+1) && lrs rh log2(q+1)
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
Dos
monYculos
zurdos
construidos
con
50
elementos
aleatorios:
la
espina
derecha
es
muy
corta!
57
Pretendemos
obtener
un
nuevo
WBLH
mezclando
dos
WBLHs
merge
=>
Y
pretendemos
obtenerlo
ecientemente:
Mezclndolos
a
travs
de
sus
espinas
derechas
(O(log
n))
58
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]
merge :: (Ord a) => [a] -> [a] -> [a]
merge []
ys
= ys
0 : 1 : merge [7,9] [2,4]
merge xs
[]
= xs
merge ls@(x:xs) rs@(y:ys)
= x : merge xs rs
0 : 1 : 2 : merge [7,9] [4] | x <= y
| otherwise
= y : merge ls ys
0 : 1 : 2 : 4 : merge [7,9] []
0 : 1 : 2 : 4 : [7,9]
El algoritmo anterior puede generalizarse para montculos
59
Necesitamos
una
funcin
auxiliar
para
construir
un
rbol
zurdo
a
par7r
de
otros
dos
y
de
un
valor:
node :: a -> Heap a -> Heap a -> Heap a
node x h h'
El de ms peso a la
| w >= w'
= Node x s h h'
izquierda
| otherwise = Node x s h' h
where
Manteniendo
el
w = weight h
invariante:
los
w' = weight h'
El resultado es zurdo,
pero no necesariamente
s = w + w' + 1
argumentos
son
zurdos
ordenado, salvo que 0
no supere a las raices
node 0
=>
60
merge :: (Ord a) => Heap a -> Heap a -> Heap a
merge Empty h'
= h'
merge h
Empty = h
merge h@(Node x w lh rh) h'@(Node x' w' lh' rh')
| x <= x'
= node x lh (merge rh h')
| otherwise
= node x' lh' (merge h rh')
Conservando
el
invariante:
los
argumentos
son
monYculos
zurdos
extraemos el menor nodo junto a su hijo izquierdo,
y mezclamos el resto
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 a
merge Empty h'
= h'
merge h
Empty = h
merge h@(Node x w lh rh) h'@(Node x' w' lh' rh')
| x <= x'
= node
x lh (merge rh h')
| otherwise
= node x' lh' (merge h rh')
Conservando
el
invariante:
los
argumentos
son
monYculos
zurdos
x
merge
x'
=>
62
merge :: (Ord a) => Heap a -> Heap a -> Heap a
merge Empty h'
= h'
merge h
Empty = h
merge h@(Node x w lh rh) h'@(Node x' w' lh' rh')
| x <= x'
= node
x lh (merge rh h')
| otherwise
= node x' lh' (merge h rh')
Conservando
el
invariante:
los
argumentos
son
monYculos
zurdos
La funcin node coloca lh
a la derecha de
x
merge
x'
rh
h'
lh
merge
=>
63
merge :: (Ord a) => Heap a -> Heap a -> Heap a
merge Empty h'
= h'
merge h
Empty = h
merge h@(Node x w lh rh) h'@(Node x' w' lh' rh')
| x <= x'
= node x lh (merge rh h')
| otherwise
= node
x' lh' (merge h rh')
x
merge
merge
=>
x'
Conservando
el
invariante:
los
argumentos
son
monYculos
zurdos
1
lh'
=>
rh'
merge
64
merge :: (Ord a) => Heap a -> Heap a -> Heap a
merge Empty h'
= h'
merge h
Empty = h
merge h@(Node x w lh rh) h'@(Node x' w' lh' rh')
| x <= x'
= node x lh (merge rh h')
| otherwise
= node
x' lh' (merge h rh')
Conservando
el
invariante:
los
argumentos
son
monYculos
zurdos
1
merge
merge
=>
=>
x'
merge
65
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
) where
import qualified DataStructures.Heap.WeightBiasedLeftistHeap as H
data PQueue a = PQ (H.Heap a)
empty :: PQueue a
empty = PQ H.empty
isEmpty :: PQueue a -> Bool
isEmpty (PQ h) = H.isEmpty h
enqueue :: (Ord a) => a -> PQueue a -> PQueue a
enqueue x (PQ h) = PQ (H.insert x h)
first :: PQueue a -> a
first (PQ h) = H.minElem h
dequeue :: (Ord a) => PQueue a -> PQueue a
dequeue (PQ h) = PQ (H.delMin h)
66
Eciencia
de
las
operaciones:
Operacin
empty
isEmpty
minElem
merge
insert
delMin
Coste
O(1)
O(1)
O(1)
O(log
n)
O(log
n)
O(log
n)
El
resultado
es
similar
al
obtenido
con
monYculos
binarios
en
Java
va
arrays
67
-- construccin en forma ascendente (bottom-up): O(n)
mkHeap :: (Ord a) => [a] -> Heap a
Construimos una lista de
mkHeap [] = empty
montculos simples
mkHeap xs = mergeLoop (map singleton xs)
where
Mezclamos
dos
a
dos
mergeLoop [h] = h
hasta
obtener
un
solo
elemento
mergeLoop hs = mergeLoop (mergePairs hs)
mergePairs []
= []
mezcla dos a dos
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))
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
La
solucin
T(n)
es
O(n)
J
68
mergeLoop (map singleton [8, 3, 1, 6, 2, 4, 5, 7]) =>
mergeLoop (mergePairs[
mergeLoop (mergePairs [
mergeLoop (mergePairs [
mergeLoop [
]) =>
]) =>
]) =>
] =>
69
heapSort :: (Ord a) => [a] -> [a]
heapSort
est
en
heapSort = heapToList . mkHeap
O(n
log
n)
n eliminaciones donde cada una
heapToList :: (Ord a) => Heap a -> [a] realiza O(log
n)
pasos +
O(n)
heapToList h
para la operacin mkHeap
| isEmpty h = []
| otherwise = minElem h : heapToList (delMin h)
[1,3,4,6,7,8,9]
heapToList
mkHeap
[6,3,8,1,4,7,9]
70
package dataStructures.heap;
public class WeigthBiasedLeftistHeap<T extends Comparable<? super T>>
implements Heap<T>{
root
protected static class Tree<E> {
E elem;
// elemento raz del MZ
int weight;
// peso o nmero de elementos
Tree<E> left; // hijo izdo
a 5
Tree<E> right; // hijo dcho
}
// referencia a la raz del montculo
d 3
b 1
protected Tree<T> root;
public WeigthBiasedLeftistHeap() {
root = null;
}
e 1
f 1
public boolean isEmpty() {
return root == null;
significa null
}
private static<T> int weight(Tree<T> t) {
return t==null ? 0 : t.weight;
}
public int size() {
return isEmpty() ? 0 : root.weight;
}
71
private static <T> Tree<T> node(T x, Tree<T>
"int w = weight(h);!
"int wp = weight(hp);!
"Tree<T> tree = new Tree<T>();!
"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;!
node :: a -> Heap a ->
}!
node x h h'
"!
| w >= w'
= Node x
| otherwise = Node x
where
w = weight h
w' = weight h'
s = w + w' + 1
h, Tree<T> hp) {!
Heap a -> Heap a
s h h'
s h' h
72
// Merges two heap trees along their right spines.!
// Returns merged heap.!
private static <T extends Comparable<? super T>> !
"
"
"
"
"Tree<T> merge(Tree<T> h, Tree<T> hp) {!
"if (h == null)!
"
"return hp;!
"if (hp == null)!
"
"return h;!
!
"T x = h.elem;!
"T xp = hp.elem;!
"if (x.compareTo(xp) <= 0) {
// x <= xp!
"
"return node(x, h.left, merge(h.right, hp));!
"} else {!
"
"return node(xp, hp.left, merge(h, hp.right));
"
"
"!
"}!
merge :: (Ord a) => Heap a -> Heap a -> Heap a
merge Empty h'
= h'
merge h
Empty = h
merge h@(Node x w lh rh) h'@(Node x' w' lh' rh')
| x <= x'
= node x lh (merge rh h')
| otherwise
= node x' lh' (merge h rh')
73
// mezcla dos MZs a lo largo de sus espinas derechas, devolviendo un MZ
private static <T extends Comparable<? super T>> Tree<T> merge(Tree<T> h1, Tree<T> h2) {
if (h1 == null)
return h2;
if (h2 == null)
return h1;
if (h2.elem.compareTo(h1.elem) < 0) {// forzamos que h1 sea el de clave menor
// intercambiamos h1 and h2
Tree<T> aux = h1;
h1 = h2;
h2 = aux;
} // la mezcla quedar referenciada por h1
h1.right = merge(h1.right, h2); // mezcla sobre la espina derecha
int wL = weight(h1.left);
int wR = weight(h1.right);
h1.weight = wL + wR + 1; // reajustamos el nuevo peso
// intercambiamos los hijos de h1 si fuera necesario para que h1 quede zurdo
if (wL < wR) {
Tree<T> aux = h1.left;
h1.left = h1.right;
h1.right = aux;
}
return h1;
}
74
public T minElem() {
if(isEmpty())
throw new EmptyHeapException("minElem on empty heap");
else
return root.elem;
El mnimo en la raz
}
public void delMin() {
if(isEmpty())
throw new EmptyHeapException("delMin on empty heap");
else
Mezclamos los hijos
sin la raz
root = merge(root.left,root.right);
}
public void insert(T x) {
Tree<T> tree = new Tree<T>();
tree.elem = x;
tree.weight = 1;
root = merge(root, tree);
}
Creamos un nuevo MZ
con un solo elemento
La insercin se produce
al mezclar la raz con el
nuevo MZ
75
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
v
Invariante de un BST
data BST a = Empty | Node a (BST a) (BST a) deriving Show
isBST :: (Ord a) => BST a -> Bool
isBST Empty
= True
isBST (Node x lt rt) = forAll (<x) lt && 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
Problema:
insertar
un
nuevo
elemento
en
un
BST
de
forma
que
el
resultado
sea
otro
BST
(se
conserve
el
invariante)
insert
7
77
Problema:
insertar
un
nuevo
elemento
en
un
BST
de
forma
que
el
resultado
sea
otro
BST
(se
conserve
el
invariante)
7
7 debe quedar a la
derecha de 4
78
Problema:
insertar
un
nuevo
elemento
en
un
BST
de
forma
que
el
resultado
sea
otro
BST
(se
conserve
el
invariante)
7
7 a la izquierda de 8
79
Problema:
insertar
un
nuevo
elemento
en
un
BST
de
forma
que
el
resultado
sea
otro
BST
(se
conserve
el
invariante)
7 a la derecha de 6
80
Problema:
insertar
un
nuevo
elemento
en
un
BST
de
forma
que
el
resultado
sea
otro
BST
(se
conserve
el
invariante)
7 debe quedar
aqu
81
Problema:
insertar
un
nuevo
elemento
en
un
BST
de
forma
que
el
resultado
sea
otro
BST
(se
conserve
el
invariante)
82
insert :: (Ord a) => a -> BST a -> BST a
insert x' Empty = Node x' Empty Empty
insert x' (Node x lt rt)
| x'==x
= Node x' lt rt
| x'<x
= Node x (insert x' lt) rt
| otherwise = Node x lt (insert x' rt)
Si x'==x, entonces
x es sustituido por x'
El
nmero
de
pasos
es
proporcional
a
la
altura
del
rbol:
Para
un
rbol
con
n
claves,
insert
O(n),
pero
podra
conseguirse,
para
cierto
7po
de
rboles,
insert
O(log
n)
Altura en O(log n) J
Altura en O(n) L
83
Dos
BSTs
generados
con
elementos
aleatorios:
Los rboles quedan muy
desequilibrados L
84
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
[1,3,4,6,7,8,9]
inOrderB
mkBST
[9,7,4,1,8,3,6]
86
search :: (Ord a) => a -> BST a -> Maybe a
search x' Empty = Nothing
search x' (Node x lt rt)
| x'==x
= Just x
| x'<x
= search x' lt
| otherwise
= search x' rt
isElem :: (Ord a) => a -> BST a -> Bool
isElem x t = isJust (search x t)
Maybe
search
4
search
10
data Maybe a = Nothing | Just a
isJust :: Maybe a -> Bool
isJust (Just _) = True
isJust Nothing
= False
87
El
mnimo
elemento
se
encuentra
en
la
posicin
ms
a
la
izquierda
(al
nal
de
la
espina
izquierda):
minim
minim
minim
minim
:: BST a -> a
Empty
(Node x Empty rt)
(Node x lt rt)
= error "minim on empty tree"
= x
= minim lt
Mnimo
elemento
88
El
mximo
elemento
se
encuentra
al
nal
de
la
espina
derecha:
maxim
maxim
maxim
maxim
:: BST a -> a
Empty
(Node x lt Empty)
(Node x lt rt)
= error "maxim on empty tree"
= x
= maxim rt
Mximo
elemento
89
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
Man7ene
invariante
el
orden
=>
delete 'c'
hoja
90
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.
Man7ene
invariante
el
orden
Solo 1 hijo
delete b'
=>
91
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
Man7ene
Invariante
el
orden
2 hijos
=>
delete d'
Hijo derecho
Mnimo del
hijo derecho
92
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
Man7ene
invariante
el
orden
2 hijos
=>
delete d'
Hijo izquierdo
Mximo del
hijo izquierdo
93
Quitar
y
devolver
el
mnimo
elemento
de
un
rbol:
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
split
=>
94
delete :: (Ord a) => a -> BST a -> BST a
delete x' Empty = Empty
delete x' (Node x lt rt)
| x'==x
= join lt rt
| x'<x
= Node x (delete x' lt) rt
| otherwise
= Node x lt (delete x' rt)
join :: BST a -> BST a -> BST a
join Empty rt
= rt
Uno de los hijos es vaco
join lt
Empty = lt
join lt
rt
= Node m lt rt'
where (m,rt') = split rt
rbol derecho sin
Mnimo
elemento del
rbol derecho
el elemento
mnimo
Todas las claves de lt son
menores que las de rt,
luego x es mayor que las
claves de lt
95
Operacin
empty
isEmpty
insert
isElem
delete
minim
maxim
Coste
O(1)
O(1)
O(n)
O(n)
O(n)
O(n)
O(n)
(*)
Podemos
obtener
complejidades
en
O(log
n)
si
imponemos
a
los
BST
condiciones
de
balanceo;
por
ejemplo,
AVL
96
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<K extends Comparable<? super K>, V> {
public boolean isEmpty();
public int size();
Implementaremos
una
variante
en
la
public int height();
que
cada
nodo
del
rbol
guarda,
adems
public void insert(K k, V v);
de
las
referencias
a
los
hijos,
otros
dos
public V search(K k);
datos:
una
clave
y
un
valor.
public boolean isElem(K k);
public void delete(K k);
Los
nodos
en
el
rbol
estarn
ordenados
public Iterable<K> inOrder();
public Iterable<K> postOrder();
segn
sus
claves.
public Iterable<K> preOrder();
public Iterable<V> values();
public Iterable<Tuple2<K,V>> keysValues();
97
package dataStructures.binarySearchTree;
public class BST<K extends Comparable<? super K>, V> implements SearchTree<K,V> {
private static class Tree<K,V> {
private K key;
private D value;
private Tree<K,V> left, right;
public Tree(C k, V v) {
key = k;
value = v;
left = null;
right = null;
}
}
private Tree<K,V> root;
private int size;
public BST() {
root = null;
size = 0;
}
public boolean isEmpty() {
return root == null;
}
public int size () {
return size;
}
98
public V search(K key) {
return BST.searchRec(root, key);
}
Devuelve el valor del rbol
asociado a la clave key, o null
si la clave no est en el rbol
private static <K extends Comparable<? super K>, V>
V searchRec(Tree<K,V> tree, K key) {
if (tree == null)
return null;
else if (key.compareTo(tree.key) == 0)
Recordemos que los
return tree.value;
rboles estn ordenados
else if (key.compareTo(tree.key) < 0)
segn clave
return searchRec(tree.left, key);
else
return searchRec(tree.right, key);
}
public boolean isElem(K key) {
return search(key) != null;
}
Devuelve true si el rbol
contiene la clave key
99
public void insert(K key, V value) {
root = insertRec(root, key, value);
}
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
// returns modified tree
private Tree<K,V> insertRec(Tree<K,V> node, K key, V value) {
if (node == null) {
node = new Tree<K,V>(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
// 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 <K, V> Tree<K,V>
split(Tree<K,V> node, Tree<K,V> 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
public void delete(K key) {
root = deleteRec(root, key);
}
Borra el nodo con
clave key
// Devuelve el rbol modificado
private Tree<K,V> deleteRec(Tree<K,V> node, K key) {
if (node == null)
; // key no encontrada; no hacemos nada
2 hijos
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
Hijo
node.right = split(node.right, node);
derecho
Mnimo del hijo
size--;
derecho
} else if (key.compareTo(node.key) < 0)
node.left = deleteRec(node.left, key);
else
Quitamos el mnimo de
node.right = deleteRec(node.right, key);
node.right, pero
return node;
copiando antes su
}
contenido en node
102
public interface SearchTree<K extends Comparable<? super K>, V> {
public boolean isEmpty();
public int size();
public int height();
public void insert(K k, V v);
...
public Iterable<K> preOrder();
public Iterable<K> postOrder();
public Iterable<K> inOrder();
public Iterable<V> values(); //itera valores inOrder
public Iterable<Tuple2<K,V>> keysValues(); // //itera pares inOr.
Recordemos
las
interfaces:
interface Iterable<T> {
public
Iterator<T> iterator();
}
public interface Iterator<T> {
boolean hasNext();
T next();
void remove();
}
}
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:
PostOrden:
InOrden:
Iterable<K> preOrder();
Iterable<K> postOrder();
Iterable<K> inOrder();
-
Por
valores:
Iterable<V> values();
-
Por
pares
(clave,
valor):
Iterable<Tuple2<K,V>> keysValues();
103
BST<Integer,String> bst = new BST<Integer,String>();
bst.insert(5, "five");
bst.insert(2, "two");
de tipo
bst.insert(7, "seven");
Iterable<Integer>
bst.insert(1, "one");
bst.insert(3, "three");
Ambos Imprimen:
1
System.out.println("InOrder traversal:");
for(int i : bst.inOrder()) {
2
3
System.out.printf("%d ",i);
}
5
System.out.println();
7
System.out.println("InOrder traversal:");
Iterator<Integer> it = bst.inOrder().iterator();
Devuelve un iterador que
while(it.hasNext())
recorre las claves del rbol
System.out.printf("%d ",it.next());
en orden
System.out.println();
System.out.println(KeysValues inOrder traversal:");
for(Tuple<Integer.String> par : bst.keysValues()) {
1 one
System.out.printf("%d %s", par._1(), par._2() );
2 two
3 three
}
5 five
System.out.println();
7 seven
104
Usa
un
stack
para
organizar
los
nodos
pendientes
root
Para recorrer los
void save(Tree<K,V> node) {
elementos, se guardan en
// en orden inverso, el stack es LIFO
un stack
if (node.right != null)
Visitaremo la subrama
push red right subtree in stack
derecha en tercer lugar
push blue node in stack
Visitaremos la clave y valor
if (node.left != null)
en segundo lugar
push red left subtree in stack
}
Visitaremos la subrama
izquierda en primer lugar
Visitaremos la subrama
izquierda en primer lugar
(red)
Visitaremos el nodo en
segundo lugar (blue)
stack
Visitaremos la subrama
derecha en tercer lugar
(red)
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)
105
void save(Tree<K,V> 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
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
106
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
107
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
108
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
109
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
110
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
111
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
112
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
113
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
114
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
115
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
116
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
117
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
118
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
119
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
120
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
121
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
122
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
123
void save(Tree<K,V> 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
}
public Tree<K,V> nextTree() {
t = stack.top();
stack.pop();
t
nextTree =>
}
stack
while (t is a red tree) {
save(t);
t = stack.top();
stack.pop();
}
return t; //blue tree
124
El
stack
debe
ser
capaz
de
diferenciar
los
rboles
almacenados
(red
o
blue)
El
7po
base
del
stack
ser
Either< Tree<K,V>, Tree<K,V> >
Un
objeto
del
7po
Either<A,B>
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<Integer,String> either = new Left(5);
true si either
guarda un Integer
if(either.isLeft())
Integer n = either.left();
Either guarda el Integer
5
Devuelve el Integer de
either
either = new Right("five");
Either guarda el String
"five"
true si either
guarda un String
if(either.isRight())
String s = either.right();
Devuelve el String de
either
125
package dataStructures.either;
public interface Either<A,B> {
boolean isLeft();
boolean isRight();
A left();
B right();
}
public class Left<A,B> implements Either<A,B> {
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<A,B> implements Either<A,B> {
private B right;
public Right(B x) { right = x; } ...
126
}
private abstract class Traversal {
Stack<Either<Tree<K,V>, Tree<K,V>>> stack = new LinkedStack<Either<Tree<K,V>, Tree<K,V>>>();
abstract void save(Tree<K,V> node);
public Traversal() {
if (root != null)
save(root);
}
public boolean hasNext() {
return !stack.isEmpty();
}
No hay ms
elementos ya que el
stack est vacio
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)
public Tree<K,V> nextTree() {
if (!hasNext())
throw new NoSuchElementException();
Either<Tree<K,V>, Tree<K,V>> either = stack.top();
stack.pop();
Mientras sea un rbol de la derecha
hay que visitarlo
Inicializa el stack
Ser definido para cada
recorrido: inOrder,
preOrder y postOrder
while (either.isRight()) {
Tree<K,V> node = either.right();
save(node);
either = stack.top();
stack.pop();
Es un rbol de la izquierda. Nos
}
interesa solo la clave y el valor
return either.left();
public void remove() {
throw new UnsupportedOperationException();
}
127
public class InOrderTravesal extends Travesal {
Visitamos el
void
save(Tree<K,V>
node)
{
subrbol derecho en
// in reverse order, cause stack is LIFO
tercer lugar (right)
if (node.right != null)
stack.push(new Right<Tree<K,V>, Tree<K,V>>(node.right)); Visitamos rbol con
stack.push(new Left<Tree<K,V>, Tree<K,V>>(node));
if (node.left != null)
stack.push(new Right<Tree<K,V>, Tree<K,V>>(node.left));
clave y valor en
segundo lugar (left)
Visitamos el subrbol
izquierdo en primer
lugar (right)
private class InOrderIt extends InOrderTraversal implements Iterator<K> {
"public K next() {
"
"return super.nextTree().key;
Solo se necesita la
"}
clave del nodo raz
}
public class BST<K extends Comparable<? super K>, V>
implements SearchTree<K,V> {
"public Iterable<K> inOrder() {
return new Iterable<K>() {
"
"
"public Iterator<K> iterator() {
return new InOrderIt();
}
"
"};
}...
}
128
public class PreOrderTraversal extends Traversal {
Visitamos el
void
save(Tree<K,V>
node)
{
subrbol derecho en
// in reverse order, cause stack is LIFO
tercer lugar (right)
if (node.right != null)
stack.push(new Right<Tree<K,V>, Tree<K,V>>(node.right));
Visitamos el subrbol
if (node.left != null)
stack.push(new Right<Tree<K,V>, Tree<K,V>>(node.left)); izquierdo en segundo
lugar (right)
stack.push(new Left<Tree<K,V>, Tree<K,V>>(node));
Visitamos rbol con clave y
}
valor en primer lugar (left)
}
private class PreOrderIt extends PreOrderTraversal implements Iterator<K> {
"public K next() {
"
"return super.nextTree().key;
Solo se necesita la
"}
clave del nodo raz
}
public class BST<K extends Comparable<? super K>, V>
implements SearchTree<K,V> {
"public Iterable<K> PreOrder() {
return new Iterable<K>() {
"
"
"public Iterator<K> iterator() {
return new PreOrderIt();
}
"
"};
}...
}
129
public class PostOrderTravesal extends Travesal {
void save(Tree<K,V> node) {
// in reverse order, cause stack is LIFO
stack.push(new Left<Tree<K,V>, Tree<K,V>>(node));
Visitamos el
subrbol derecho en
if (node.right != null)
stack.push(new Right<Tree<K,V>, Tree<K,V>>(node.right)); segundo lugar (right)
Visitamos rbol con
clave y valor en tercer
lugar (left)
if (node.left != null)
stack.push(new Right<Tree<K,V>, Tree<K,V>>(node.left));
Visitamos el subrbol
izquierdo en primer
lugar (right)
private class PostOrderIt extends PostOrderTraversal implements Iterator<K> {
"public K next() {
"
"return super.nextTree().key;
Solo se necesita la
"}
clave del nodo raz
}
public class BST<K extends Comparable<? super K>, V>
implements SearchTree<K,V> {
"public Iterable<K> postOrder() {
return new Iterable<K>() {
"
"
"public Iterator<K> iterator() {
return new PostOrderIt();
}
"
"};
}...
}
130
Solo
denimos
la
iteracin
por
valores
para
el
recorrido
InOrder
private class ValuesIt extends InOrderTraversal implements Iterator<V> {
"public V next() {
"
"return super.nextTree().value;
Solo se necesita el
"}
valor del nodo raz
}
public class BST<K extends Comparable<? super K>, V>
implements SearchTree<K,V> {
"public Iterable<V> values() {
return new Iterable<V>() {
"
"
"public Iterator<V> iterator() {
return new ValuesIt();
}
"
"};
}...
}
131
Solo
denimos
la
iteracin
por
pares
para
el
recorrido
InOrder
private class KeyValuesIt extends InOrderTraversal !
!
!
!
!
!implements Iterator<Tuple2<K,V>> {
"public Tuple2<K,V> next() {
"
"Tree<K,V> node = super.nextTree();
"
"return new Tuple2<K,V>(node.key, node.value);
"}
Se necesita clave y valor del nodo raz.
}
Se devuelve una Tuple2 con los dos datos
public class BST<K extends Comparable<? super K>, V>
implements SearchTree<K,V> {
"public Iterable<Tuple2<K,V>> keysValues() {
return new Iterable<Tuple2<K,V>>() {
"
"
"public Iterator<Tuple2<K,V>> iterator() {
return new KeyValuesIt();
}
"
"};
}...
}
132
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)
h|p://en.wikipedia.org/wiki/Self-balancing_binary_search_tree
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/
AVL_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
Todos
estos
son
rboles
AVL
134
data AVL a = Empty | Node a Int (AVL a) (AVL a)
4
En cada nodo
mantenemos su altura
Altura
2
3
height :: AVL a -> Int
height Empty
= 0
1
1
2
2
height (Node k h lt rt) = h
0 0 0 0
1
1 0
1
isAVL :: (Ord a) => AVL a -> Bool
0 0 0 0
0 0
isAVL Empty
= True
isAVL (Node k h lt rt) = forAll (<k) lt && forAll (>k) rt
&& abs (height lt - height rt) <= 1
&& isAVL lt && isAVL rt
where
forAll :: (a -> Bool) -> AVL a -> Bool
forAll p Empty
= True
forAll p (Node x h lt rt) =
p x && forAll p lt && forAll p rt
135
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
rboles
AVL
trees
con
alturas
1,2
y
3
N(2)
=
2
N(h)
=
1
+
N(h
-
1)
+
N(h
-
2)
,
h
>
2
Nodo de la raz
de un rbol de
atura h
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
Probaremos:
h
1
N(h),
luego
h
log
(n+1)
= 1+5/2
137
El
nmero
de
oro
ecuacin
es
la
raz
posi7va
de
la
x2
=
1
+
x,
es
decir
1+ 5
=
= 1.618033988749895 ...
2
Por
tanto,
2
=
1
+
, y de aqu:
n+2
=
n
+
n+1
138
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:
fn =
1
(n ()n )
5
= lim
f n +1
fn
n = f n + f n 1
140
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,
a + b = a
o
tambin
x = 1
a
b
1
x 1
Construccin
de
un
Rectngulo
ureo
Fernando
Corbaln,
La
proporcin
urea,
RBA
(2010)
Entrevista
a
Fernando
Corbaln
(You
Tube)
141
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)
node 4
=>
143
rotR :: AVL a -> AVL a
rotR (Node k h (Node lk lh llt lrt) rt) = node lk llt (node k lrt rt)
lk
llt
lk
lrt
rt
llt
lrt
rt
144
rotR :: AVL a -> AVL a
rotR (Node k h (Node lk lh llt lrt) rt) = node lk llt (node k lrt rt)
Man7ene
invariante
el
orden
7
lk
lk
rt
mayores
que 7
llt
menores
que 3
lrt
mayores
que 3 y
menores que 7
llt
menores
que 3
lrt
mayores
que 3 y
menores que 7
rt
mayores
que 7
145
rotL :: AVL a -> AVL a
rotL (Node k h lt (Node rk rh rlt rrt)) = node rk (node k lt rlt) rrt
lt
rlt
rk
rrt
lt
rk
rrt
lrt
146
rotL :: AVL a -> AVL a
rotL (Node k h lt (Node rk rh rlt rrt)) = node rk (node k lt rlt) rrt
Man7ene
invariante
el
orden
k
lt
rk
menores
que 3
rlt
mayores
que 3 y
menores que 7
rk
rrt
mayores
que 7
rrt
mayores
que 7
lt
menores
que 3
rlt
mayores
que 3 y
menores que 7
147
La
insercin
en
un
AVL
7ene
dos
fases:
-
insercin
como
en
un
BST
-
rebalanceo
de
los
nodos
modicados:
insert 0
No necesita
rebalanceo
148
La
insercin
en
un
AVL
7ene
dos
fases:
-
insercin
como
en
un
BST
-
rebalanceo
de
los
nodos
modicados:
No necesita
rebalanceo
insert 0
2
149
La
insercin
en
un
AVL
7ene
dos
fases:
-
insercin
como
en
un
BST
-
rebalanceo
de
los
nodos
modicados:
3
insert 0
Necesita rotacin
simple rotR ya que
la altura del hijo es
dos unidades mayor
que la del hijo
derecho
150
La
insercin
en
un
AVL
7ene
dos
fases:
-
insercin
como
en
un
BST
-
rebalanceo
de
los
nodos
modicados:
Este es un rbol AVL
insert 0
rotR
151
Una rotacin simple a la derecha
no produce el balanceo
insert 7
No necesita
rebalanceo
152
insert
7
No necesita
rebalanceo
153
Necesita doble
rotacin
Inclinado a la
derecha
insert 7
154
insert 7
rotL
hijo
izquierdo
155
rotL
hijo
izquierdo
insert 7
Este es un rbol AVL
156
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 a
insert k' Empty = node k' Empty Empty
insert 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)
Solo
deben
ser
rebalanceados
los
nodos
modicados
en
el
camino
desde
la
raz
hasta
el
punto
de
insercin
157
Este es un rbol AVL
h+1
h+2
insert
h
h+1
Tras la insercin la
rama izquierda se
descompensa
Ahora no es
un rbol AVL
L
h+2
Puede
volver
a
balancearse
con
una
simple
rotacin
h
h+1
h+2
158
Este es un rbol AVL
h+1
h+2
insert
h
h+1
Tras la insercin, la
rama izquierda se
descompensa
Ahora no es
un rbol AVL
L
h+2
Puede
rebalancearse
con
una
doble
rotacin
h
h+1
h+2
159
Este es un rbol AVL
h+1
h+2
insert
h
h+1
Ahora no es
un rbol AVL
L
Tras la insercin, la
rama derecha se
descompensa
h+2
Puede
rebalancearse
con
una
simple
rotacin
h
h+1
h+2
160
Este es un rbol AVL
h+1
h+2
insert
h
h+1
Ahora no es
un rbol AVL
L
Tras la insercin, la
rama derecha se
descompensa
h+2
Puede
rebalancearse
con
una
doble
rotacin
h
h+1
h+2
161
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
balance :: a -> AVL a -> AVL a -> AVL a
balance k lt rt
| (lh-rh > 1) && leftLeaning lt = rotR
| (lh-rh > 1)
= rotR
| (rh-lh > 1) && rightLeaning rt = rotL
| (rh-lh > 1)
= rotL
| otherwise
= node
where lh = height lt
rh = height rt
(node k
(node k
(node k
(node k
k lt rt
lt rt)
(rotL lt) rt)
lt rt)
lt (rotR rt))
k
lt
rt
rotR (node k lt rt)
Rotacin a la
derecha
h+1
h+1
h+2
h+2
163
balance :: a -> AVL a -> AVL a -> AVL a
balance k lt rt
| (lh-rh > 1) && leftLeaning lt = rotR
| (lh-rh > 1)
= rotR
| (rh-lh > 1) && rightLeaning rt = rotL
| (rh-lh > 1)
= rotL
| otherwise
= node
where lh = height lt
rh = height rt
(node k
(node k
(node k
(node k
k lt rt
lt rt)
(rotL lt) rt)
lt rt)
lt (rotR rt))
k
lt
rt
rotL (node k lt rt)
Rotacin a la
izquierda
h+1
h+1
h+2
h+2
164
k
lt
balance :: a -> AVL a -> AVL a -> AVL a
balance k lt rt
| (lh-rh > 1) && leftLeaning lt = rotR
| (lh-rh > 1)
= rotR
| (rh-lh > 1) && rightLeaning rt = rotL
| (rh-lh > 1)
= rotL
| otherwise
= node
where lh = height lt
rh = height rt
(node k
(node k
(node k
(node k
k lt rt
lt rt)
(rotL lt) rt)
lt rt)
lt (rotR rt))
rt
rotR (node k (rotL lt) rt)
h
h
h+1
h+1
h+2
h+2
Solo una de estas
ramas tiene h+2
Rotacin a la izquierda en
el subrbol izquierdo (lt)
h
h+1
h+2
Rotacin a la
derecha en la raz
165
balance :: a -> AVL a -> AVL a -> AVL a
balance k lt rt
| (lh-rh > 1) && leftLeaning lt = rotR
| (lh-rh > 1)
= rotR
| (rh-lh > 1) && rightLeaning rt = rotL
| (rh-lh > 1)
= rotL
| otherwise
= node
where lh = height lt
rh = height rt
lt rt)
(rotL lt) rt)
lt rt)
lt (rotR rt))
rt
lt
(node k
(node k
(node k
(node k
k lt rt
rotL (node k lt (rotR rt))
h
h
h+1
h+1
h+2
h+2
Solo una de estas
ramas tiene h+2
h
Rotacin a la derecha en el
subrbol derecho (rt)
h+1
h+2
Rotacin a la
izquierda en la raz
166
search
4
Igual
que
en
rboles
Binarios
de
Bsqueda:
search
10
isElem :: (Ord a) => a -> AVL a -> Bool
isElem k t = isJust (search k t)
Maybe
search :: (Ord a) => a -> AVL a -> Maybe a
search k' Empty = Nothing
search k' (Node k h lt rt)
| k'==k
= Just k
| k'<k
= search k' lt
| otherwise
= search k' rt
data Maybe a = Nothing | Just a
isJust :: Maybe a -> Bool
isJust (Just _) = True
isJust Nothing
= False
167
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'<k
= balance k (delete k' lt) rt
| otherwise
= balance k lt (delete k' rt)
join :: AVL a -> 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
Operacin
empty
isEmpty
insert
isElem
delete
minim
maxim
Coste
O(1)
O(1)
O(log
n)
O(log
n)
O(log
n)
O(log
n)
O(log
n)
(*)
Comprense
con
los
costes
para
un
BST
estndar
169
package dataStructures.SearchTree;
public class AVL<K extends Comparable<? super K>, V> implements SearchTree<K,V>{
private static class Tree<C,D> {
private C key;
private D value;
private int height;
private Tree<C,D> left, right;
public Tree(C k, D v) {
key = k;
value = v;
height = 1;
left = null;
right = null;
}
}
Implementaremos
una
variante
en
la
que
en
cada
nodo
almacenamos:
una
clave
y
un
valor.
Los
nodos
en
el
rbol
estarn
ordenados
segn
las
claves.
private Tree<K,V> root;
public AVL() {
root = null;
}
public boolean isEmpty() {
return root == null;
}
170
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<K,V> rotR() {
Tree<K,V> lt = this.left;
Tree<K,V> lrt = lt.right;
this.left = lrt;
this.setHeight();
lt.right = this;
lt.setHeight();
7 this
return lt;
}
lt
lrt
lt
lrt
this
9
172
// Rota a la izquierda el receptor. Devuelve la nueva raz
public Tree<K,V> rotL() {
Tree<K,V> rt = this.right;
Tree<K,V> rlt = rt.left;
this.right = rlt;
this.setHeight();
rt.left = this;
rt.setHeight();
return rt;
this
3
7 rt
}
0
rlt
rt
this
lrt
173
// Balancea el receptor. Devuelve el nodo despues de balancearlo
public Tree<K,V> balance() {
int lh = height(left);
int rh = height(right);
Tree<K,V> 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 <C extends Comparable<? super C>, D>
D searchRec(Tree<C,D> tree, C key) {
if (tree == null)
return null;
else if (key.compareTo(tree.key) == 0)
return tree.value;
else if (key.compareTo(tree.key) < 0)
return searchRec(tree.left, key);
else
return searchRec(tree.right, key);
}
public boolean isElem(K key) {
return search(key) != null;
}
175
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 <C extends Comparable<? super C>, D>
Tree<C,D> insertRec(Tree<C,D> node, C key, D value) {
if (node == null)
node = new Tree<C,D>(key, value);
else if (key.compareTo(node.key) == 0)
node.value = value;
else if (key.compareTo(node.key) < 0) {
node.left = insertRec(node.left, key, value);
node = node.balance();
} else {
node.right = insertRec(node.right, key, value);
node = node.balance();
}
return node;
}
176
Un
diccionario
permite
manejar
echas
(asociaciones)
entre
un
conjunto
de
claves
a y
un
conjunto
de
valores
b:
data Dict a b
-- un diccionario vaco
empty :: Dict a b
isEmpty :: Dict a b -> Bool
-- inserta/aade una asociacin en un diccionario
insert :: (Eq a) => a -> b -> Dict a b -> Dict a b
-- recupera el valor en el diccionario
valueOf :: (Eq a) => a -> Dict a b -> Maybe b
177
True ==> isEmpty empty
True ==> not (isEmpty (insert k v d))
True ==> valueOf k empty == Nothing
k==k' ==> valueOf k (insert k' v' d) == Just v'
k/=k' ==> valueOf k (insert k' v' d) == valueOf k d
True ==> insert k v' (insert k v d) = insert k v' d
k/=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
Valor
Clave
5 "five"
2 "two"
1 "one"
9 "nine"
3 "three"
179
module DataStructures.Dictionary.AVLDictionary
( Dict
, empty
, isEmpty
, insert
, get
) where
import qualified DataStructures.BinarySearchTree.AVL as T
data Rel a b = a :-> b
Dos asociaciones son iguales
instance (Eq a) => Eq (Rel a b) where
sii tienen la misma clave
(k :-> _) == (k' :-> _) = (k == k')
instance (Ord a) => Ord (Rel a b) where
(k :-> _) <= (k' :-> _) = (k <= k')
180
data Dict a b = D (T.AVL (Rel a b))
-- las operaciones son delegadas a operaciones con AVL
empty :: Dict a b
empty = D T.empty
Un diccionario es vaco si lo
es como rbol AVL
isEmpty :: Dict a b -> Bool
isEmpty (D avl) = T.isEmpty avl
insert :: (Ord a) => a -> b -> Dict a b -> Dict a b
insert k v (D avl) = D (T.insert (k :-> v) avl)
valueOf :: (Ord a) => a -> Dict a b -> Maybe b
valueOf k (D avl) =
case T.search (k :-> undefined) avl of
Nothing
-> Nothing
Just (_ :-> v) -> Just v
181
La
complejidad
de
las
operaciones
son
las
correspondientes
a
un
rbol
AVL:
Operacin
empty
isEmpty
insert
valueOf
Coste
O(1)
O(1)
O(log
n)
O(log
n)
182