Você está na página 1de 42

Árboles binarios y generales

Clara Segura y Alberto Verdejo

Dpto. de Sistemas Informáticos y Programación


Universidad Complutense de Madrid
Marzo 2005
Árboles binarios: Especificación

especificación ÁRBOLES-BINARIOS[ELEM]
usa BOOLEANOS
tipos árbol-bin
operaciones
árbol-vacı́o : −→ árbol-bin { constructora }
plantar : árbol-bin elemento árbol-bin −→ árbol-bin { constructora }
raı́z : árbol-bin −→p elemento
hijo-iz : árbol-bin −→p árbol-bin
hijo-dr : árbol-bin −→p árbol-bin
es-árbol-vacı́o? : árbol-bin −→ bool

2
variables
e : elemento
iz , dr : árbol-bin
ecuaciones
hijo-iz(árbol-vacı́o) = error
hijo-iz(plantar(iz , e, dr )) = iz
hijo-dr(árbol-vacı́o) = error
hijo-dr(plantar(iz , e, dr )) = dr
raı́z(árbol-vacı́o) = error
raı́z(plantar(iz , e, dr )) = e
es-árbol-vacı́o?(árbol-vacı́o) = cierto
es-árbol-vacı́o?(plantar(iz , e, dr )) = falso
fespecificación

3
Árboles binarios: Implementación
tipos
enlace-árbol = puntero a nodo-árbol
nodo-árbol = reg
valor : elemento
iz , dr : enlace-árbol
freg
árbol-bin = enlace-árbol
ftipos

fun árbol-vacı́o() dev a : árbol-bin { Θ(1) }


a := nil
ffun

fun plantar(iz : árbol-bin, e : elemento, dr : árbol-bin) dev a : árbol-bin { Θ(1) }


reservar(a)
a ↑ .valor := e
a ↑ .iz := iz
a ↑ .dr := dr
ffun
4
fun hijo-iz(a : árbol-bin) dev b : árbol-bin { Θ(1) }
si a = nil entonces error(Árbol vacı́o)
si no b := a ↑ .iz
fsi
ffun
fun hijo-dr(a : árbol-bin) dev b : árbol-bin { Θ(1) }
si a = nil entonces error(Árbol vacı́o)
si no b := a ↑ .dr
fsi
ffun
fun raı́z(a : árbol-bin) dev e : elemento { Θ(1) }
si a = nil entonces error(Árbol vacı́o)
si no e := a ↑ .valor
fsi
ffun
fun es-árbol-vacı́o?(a : árbol-bin) dev b : bool { Θ(1) }
b := (a = nil)
ffun

5
Recorridos en profundidad
especificación RECORRIDOS-PROF-ÁRBOLES-BINARIOS[ELEM]
usa ÁRBOLES-BINARIOS[ELEM], LISTAS[ELEM]
operaciones
preorden : árbol-bin −→ lista
inorden : árbol-bin −→ lista
postorden : árbol-bin −→ lista
variables
e : elemento
iz , dr : árbol-bin
ecuaciones
preorden(árbol-vacı́o) = []
preorden(plantar(iz , e, dr )) = [e] ++ (preorden(iz ) ++ preorden(dr ))
inorden(árbol-vacı́o) = []
inorden(plantar(iz , e, dr )) = inorden(iz ) ++ ([e] ++ inorden(dr ))
postorden(árbol-vacı́o) = []
postorden(plantar(iz , e, dr )) = postorden(iz ) ++ (postorden(dr ) ++ [e])
fespecificación

6
Implementación
fun preorden(a : árbol-bin) dev l : lista
var r : lista
si es-árbol-vacı́o?(a) entonces l := lista-vacı́a()
si no
r := preorden(hijo-iz(a))
añadir-izq(raı́z(a), r)
l := concatenar(r, preorden(hijo-dr(a)))
fsi
ffun
fun inorden(a : árbol-bin) dev l : lista
var r : lista
si es-árbol-vacı́o?(a) entonces l := lista-vacı́a()
si no
r := inorden(hijo-iz(a))
añadir-der(r, raı́z(a))
l := concatenar(r, inorden(hijo-dr(a)))
fsi
ffun
7
Versión iterativa del recorrido en preorden

Hay que obtener una generalización adecuada de la función preorden, la operación


pre-lista-pila que, dadas una lista y una pila de árboles binarios, devuelve la concatena-
ción de la lista con la concatenación de los recorridos en preorden de todos los árboles
en la pila.
pre-pila(pila-vacı́a) = [ ]
pre-pila(apilar(a, p)) = preorden(a) ++ pre-pila(p)
pre-lista-pila(l, p) = l ++ pre-pila(p)
Para calcular el recorrido en preorden de un árbol binario basta considerar la siguiente
ecuación:
preorden(a) = pre-lista-pila([ ], apilar(a, pila-vacı́a))

8
Para obtener la definición recursiva de pre-lista-pila, vamos a operar ecuacionalmente
con las ecuaciones anteriores y las que definen el preorden, distinguiendo los tres casos
siguientes:

La pila es vacı́a.
pre-lista-pila(l, pila-vacı́a)
= l ++ pre-pila(pila-vacı́a)
= l ++ [ ]
= l
La pila no es vacı́a, pero el árbol en su cima es el árbol vacı́o.
pre-lista-pila(l, apilar(árbol-vacı́o, p))
= l ++ pre-pila(apilar(árbol-vacı́o, p))
= l ++ (preorden(árbol-vacı́o) ++ pre-pila(p))
= l ++ ([ ] ++ pre-pila(p))
= l ++ pre-pila(p)
= pre-lista-pila(l, p)

9
La pila no es vacı́a y el árbol en su cima no es el árbol vacı́o.
pre-lista-pila(l, apilar(plantar(iz , e, dr ), p))
= l ++ pre-pila(apilar(plantar(iz , e, dr ), p))
= l ++ (preorden(plantar(iz , e, dr )) ++ pre-pila(p))
= l ++ (([e] ++ (preorden(iz ) ++ preorden(dr ))) ++ pre-pila(p))
= (l ++ [e]) ++ (preorden(iz ) ++ (preorden(dr ) ++ pre-pila(p)))
= (l ++ [e]) ++ (preorden(iz ) ++ pre-pila(apilar(dr , p)))
= (l ++ [e]) ++ pre-pila(apilar(iz , apilar(dr , p)))
= pre-lista-pila(l ++ [e], apilar(iz , apilar(dr , p)))

10
Como la recursión es lineal final en ambos subcasos, la versión iterativa se obtiene
fácilmente, dando lugar al algoritmo siguiente:
fun pre-lista-pila(l : lista, p : pila[árbol-bin] ) dev r : lista
var a : árbol-bin, q : pila[árbol-bin]
r := copiar-lista(l) ; q := copiar-pila(p)
mientras ¬es-pila-vacı́a?(q) hacer
a := cima(q) ; desapilar(q)
si ¬es-árbol-vacı́o?(a) entonces
añadir-der(r, raı́z(a))
apilar(hijo-dr(a), q)
apilar(hijo-iz(a), q)
fsi
fmientras
ffun

11
El recorrido en preorden de un árbol binario se obtiene aplicando la operación pre-lista-
pila a una lista vacı́a y una pila que únicamente contiene el árbol a recorrer:
fun preorden-it1(b : árbol-bin) dev r : lista
var a : árbol-bin, q : pila[árbol-bin]
r := lista-vacı́a()
q := pila-vacı́a() ; apilar(b, q)
mientras ¬es-pila-vacı́a?(q) hacer
a := cima(q) ; desapilar(q)
si ¬es-árbol-vacı́o?(a) entonces
añadir-der(r, raı́z(a))
apilar(hijo-dr(a), q)
apilar(hijo-iz(a), q)
fsi
fmientras
ffun

12
fun preorden-it2(b : árbol-bin) dev r : lista
var a, h : árbol-bin, q : pila[árbol-bin]
r := lista-vacı́a()
si ¬es-árbol-vacı́o?(b) entonces
q := pila-vacı́a() ; apilar(b, q)
mientras ¬es-pila-vacı́a?(q) hacer
a := cima(q) ; desapilar(q)
añadir-der(r, raı́z(a))
h := hijo-dr(a)
si ¬es-árbol-vacı́o?(h) entonces apilar(h, q) fsi
h := hijo-iz(a)
si ¬es-árbol-vacı́o?(h) entonces apilar(h, q) fsi
fmientras
fsi
ffun

13
Recorrido por niveles
especificación RECORRIDO-NIVELES-ÁRBOLES-BINARIOS1[ELEM]
usa NATURALES, ÁRBOLES-BINARIOS+[ELEM], LISTAS[ELEM]
operaciones
niveles : árbol-bin −→ lista
operaciones privadas
nivel-i-ésimo : árbol-bin nat −→ lista
niveles-hasta-i-ésimo : árbol-bin nat −→ lista
variables
a : árbol-bin
i : nat
ecuaciones
niveles(a) = niveles-hasta-i-ésimo(a, altura(a))
nivel-i-ésimo(árbol-vacı́o, i) = []
nivel-i-ésimo(plantar(iz , e, dr ), 0) = []
nivel-i-ésimo(plantar(iz , e, dr ), 1) = [e]
nivel-i-ésimo(plantar(iz , e, dr ), i) = nivel-i-ésimo(iz , i − 1) ++ nivel-i-ésimo(dr , i − 1) ⇐ i > 1
niveles-hasta-i-ésimo(a, 0) = [ ]
niveles-hasta-i-ésimo(a, i) = niveles-hasta-i-ésimo(a, i − 1) ++ nivel-i-ésimo(a, i) ⇐ i > 0
fespecificación
14
especificación RECORRIDO-NIVELES-ÁRBOLES-BINARIOS2[ELEM]
usa ÁRBOLES-BINARIOS[ELEM], COLAS[ÁRBOLES-BINARIOS[ELEM]], LISTAS[ELEM]
operaciones
niveles : árbol-bin −→ lista
operaciones privadas
niveles-cola : cola[árbol-bin] −→ lista
variables
a : árbol-bin
c : cola[árbol-bin]
ecuaciones
niveles(a) = niveles-cola(pedir-vez(cola-vacı́a, a))
niveles-cola(c) = [ ] ⇐ es-cola-vacı́a?(c)
niveles-cola(c) = niveles-cola(avanzar(c))
⇐ ¬es-cola-vacı́a?(c) ∧ es-árbol-vacı́o?(primero(c))
niveles-cola(c) = raı́z(primero(c)) : niveles-cola(pedir-vez(pedir-vez(avanzar(c),
hijo-iz(primero(c))), hijo-dr(primero(c))))
⇐ ¬es-cola-vacı́a?(c) ∧ ¬es-árbol-vacı́o?(primero(c))
fespecificación

15
Implementación iterativa

fun niveles(a : árbol-bin) dev l : lista


var sig, hijo : árbol-bin, c : cola[árbol-bin]
l := lista-vacı́a()
si ¬es-árbol-vacı́o?(a) entonces
c := cola-vacı́a() ; pedir-vez(c, a)
mientras ¬es-cola-vacı́a?(c) hacer
sig := primero(c) ; avanzar(c)
añadir-der(l, raı́z(sig))
hijo := hijo-iz(sig)
si ¬es-árbol-vacı́o?(hijo) entonces pedir-vez(c, hijo) fsi
hijo := hijo-dr(sig)
si ¬es-árbol-vacı́o?(hijo) entonces pedir-vez(c, hijo) fsi
fmientras
fsi
ffun

16
Árboles generales: especificación

especificación ÁRBOLES-GENERALES[ELEM]
usa BOOLEANOS, NATURALES
tipos árbol, bosque
operaciones
plantar : elemento bosque −→ árbol { constructora }
bosque-vacı́o : −→ bosque { constructora }
añ-árbol : árbol bosque −→ bosque { constructora }
raı́z : árbol −→ elemento
hijos : árbol −→ bosque
núm-hijos : árbol −→ nat
longitud : bosque −→ nat
subárbol : árbol nat −→p árbol
[] : bosque nat −→p árbol
es-hoja? : árbol −→ bool

17
variables
e : elemento
a : árbol
b : bosque
i : nat
ecuaciones
raı́z(plantar(e, b)) = e
hijos(plantar(e, b)) = b
núm-hijos(plantar(e, b)) = longitud(b)
longitud(bosque-vacı́o) = 0
longitud(añ-árbol(a, b)) = 1 + longitud(b)
subárbol(plantar(e, b), i) = b[i]
b[i] = error ⇐ i == 0 ∨ i > longitud(b)
añ-árbol(a, b)[1] = a
añ-árbol(a, b)[i] = b[i − 1] ⇐ 1 < i ∧ i ≤ longitud(b) + 1
es-hoja?(a) = (núm-hijos(a) == 0)
fespecificación

18
Árboles generales: implementación

tipos
enlace-árbol = puntero a nodo-árbol
nodo-árbol = reg
valor : elemento
primog, sig-herm : enlace-árbol
freg
árbol = enlace-árbol
bosque = enlace-árbol
ftipos

fun plantar(e : elemento, b : bosque) dev a : árbol { Θ(1) }


reservar(a)
a ↑ .valor := e
a ↑ .primog := b
a ↑ .sig-herm := nil
ffun

19
fun bosque-vacı́o() dev b : bosque { Θ(1) }
b := nil
ffun
proc añ-árbol(a : árbol, b : bosque) { Θ(1) }
a ↑ .sig-herm := b
b := a
fproc
fun raı́z(a : árbol ) dev e : elemento { Θ(1) }
e := a ↑ .valor
ffun
fun hijos(a : árbol ) dev b : bosque { Θ(1) }
b := a ↑ .primog
ffun
fun núm-hijos(a : árbol ) dev n : nat
n := longitud(a ↑ .primog)
ffun

20
fun longitud(b : bosque) dev n : nat
var c : enlace-árbol
c := b ; n := 0
mientras c 6= nil hacer
n := n + 1
c := c ↑ .sig-herm
fmientras
ffun
fun es-hoja?(a : árbol ) dev r : bool { Θ(1) }
r := (a ↑ .primog = nil)
ffun

21
fun subárbol(a : árbol, i : nat ) dev h : árbol { Θ(i) }
h := consultar(a ↑ .primog, i)
ffun
fun consultar(b : bosque, i : nat ) dev h : árbol { Θ(i) }
si i = 0 entonces error(Índice no válido)
si no
h := b ; j := 1
mientras h 6= nil ∧ j 6= i hacer
j := j + 1
h := h ↑ .sig-herm
fmientras
si h = nil entonces error(Índice no válido) fsi
fsi
ffun

22
Árboles binarios de búsqueda

parámetro ELEM=<
usa BOOLEANOS, ELEM=
operaciones
< : elemento elemento −→ bool
> : elemento elemento −→ bool
variables
x, y, z : elemento
ecuaciones
x<x = falso { antirreflexividad }
x<z = cierto ⇐ x < y ∧ y < z { transitividad }
x < y ∨ y < x = cierto ⇐ x 6= y { totalidad }
x>y = y<x
fparámetro

23
especificación ÁRBOLES-BINARIOS-DE-BÚSQUEDA[ELEM=<]
usa BOOLEANOS
tipos árbol-bb
operaciones
abb-vacı́o : −→ árbol-bb { constructora }
plantar : árbol-bb elemento árbol-bb −→p árbol-bb { constructora }
insertar : elemento árbol-bb −→ árbol-bb
está? : elemento árbol-bb −→ bool
mı́nimo : árbol-bb −→p elemento
máximo : árbol-bb −→p elemento
eliminar : elemento árbol-bb −→ árbol-bb
es-abb-vacı́o? : árbol-bb −→ bool
variables
e, f : elemento
iz , dr : árbol-bb

ecuaciones
plantar(iz , e, dr ) = error ⇐ ¬(es-abb-vacı́o?(iz ) ∨ e > máximo(iz )) ∨
¬(es-abb-vacı́o?(dr ) ∨ e < mı́nimo(dr ))

24
insertar(e, abb-vacı́o) = plantar(abb-vacı́o, e, abb-vacı́o)
insertar(e, plantar(iz , e, dr )) = plantar(iz , e, dr )
insertar(e, plantar(iz , f, dr )) = plantar(insertar(e, iz ), f, dr ) ⇐ e < f
insertar(e, plantar(iz , f, dr )) = plantar(iz , f, insertar(e, dr )) ⇐ e > f

está?(e, abb-vacı́o) = falso


está?(e, plantar(iz , e, dr )) = cierto
está?(e, plantar(iz , f, dr )) = está?(e, iz ) ⇐ e < f
está?(e, plantar(iz , f, dr )) = está?(e, dr ) ⇐ e > f

mı́nimo(abb-vacı́o) = error
mı́nimo(plantar(abb-vacı́o, e, dr )) = e
mı́nimo(plantar(iz , e, dr )) = mı́nimo(iz ) ⇐ ¬es-abb-vacı́o?(iz )
máximo(abb-vacı́o) = error
máximo(plantar(iz , e, abb-vacı́o)) = e
máximo(plantar(iz , e, dr )) = máximo(dr ) ⇐ ¬es-abb-vacı́o?(dr )

25
eliminar(e, abb-vacı́o) = abb-vacı́o
eliminar(e, plantar(iz , e, abb-vacı́o)) = iz
eliminar(e, plantar(abb-vacı́o, e, dr )) = dr
eliminar(e, plantar(iz , e, dr )) = plantar(iz , mı́nimo(dr ), eliminar(mı́nimo(dr ), dr )
⇐ ¬es-abb-vacı́o?(iz ) ∧ ¬es-abb-vacı́o?(dr )
eliminar(e, plantar(iz , f, dr )) = plantar(eliminar(e, iz ), f, dr )) ⇐ e < f
eliminar(e, plantar(iz , f, dr )) = plantar(iz , f, eliminar(e, dr )) ⇐ e > f

es-abb-vacı́o?(abb-vacı́o) = cierto
es-abb-vacı́o?(plantar(iz , e, dr )) = falso
fespecificación

26
Implementación

tipos
enlace-abb = puntero a nodo-abb
nodo-abb = reg
valor : elemento
iz , dr : enlace-abb
freg
árbol-bb = enlace-abb
ftipos

fun abb-vacı́o() dev a : árbol-bb { Θ(1) }


a := nil
ffun

27
proc insertar(e e : elemento, a : árbol-bb) { Θ(altura(a)) }
si a = nil entonces
reservar(a)
a ↑ .valor := e
a ↑ .iz := nil ; a ↑ .dr := nil
si no
casos
e = a ↑ .valor → nada
e < a ↑ .valor → insertar(e, a ↑ .iz )
e > a ↑ .valor → insertar(e, a ↑ .dr )
fcasos
fsi
fproc

{ (es-abb-vacı́o?(iz ) ∨ máximo(iz ) < e) ∧ (es-abb-vacı́o?(dr ) ∨ e < mı́nimo(dr )) }


fun plantar(iz : árbol-bb, e : elemento, dr : árbol-bb) dev a : árbol-bb { Θ(1) }
reservar(a)
a ↑ .valor := e
a ↑ .iz := iz ; a ↑ .dr := dr
ffun
28
fun está?(e : elemento, a : árbol-bb) dev b : bool { Θ(altura(a)) }
si a = nil entonces b := falso
si no
casos
e = a ↑ .valor → b := cierto
e < a ↑ .valor → b := está?(e, a ↑ .iz )
e > a ↑ .valor → b := está?(e, a ↑ .dr )
fcasos
fsi
ffun
fun mı́nimo(a : árbol-bb) dev e : elemento { Θ(altura(a)) }
si a = nil entonces error(Árbol vacı́o)
si no
si a ↑ .iz = nil entonces e := a ↑ .valor
si no e := mı́nimo(a ↑ .iz )
fsi
fsi
ffun

29
fun máximo(a : árbol-bb) dev e : elemento { Θ(altura(a)) }
si a = nil entonces error(Árbol vacı́o)
si no
si a ↑ .dr = nil entonces e := a ↑ .valor
si no e := máximo(a ↑ .dr )
fsi
fsi
ffun

fun es-abb-vacı́o?(a : árbol-bb) dev b : bool { Θ(1) }


b := (a = nil)
ffun

30
proc eliminar(e e : elemento, a : árbol-bb) { Θ(altura(a)) }
var b : enlace-abb
si a 6= nil entonces
casos
e = a ↑ .valor →
casos
a ↑ .dr = nil → b := a ; a := a ↑ .iz ; liberar(b)
a ↑ .iz = nil → b := a ; a := a ↑ .dr ; liberar(b)
a ↑ .dr 6= nil ∧ a ↑ .iz 6= nil → eliminar-aux(a, a ↑ .dr )
fcasos
e < a ↑ .valor → eliminar(e, a ↑ .iz )
e > a ↑ .valor → eliminar(e, a ↑ .dr )
fcasos
fsi
fproc

31
{ a 6= nil ∧ b 6= nil }
proc eliminar-aux(a, b : árbol-bb) { Θ(altura(b)) }
var c : enlace-abb
si b ↑ .iz 6= nil entonces eliminar-aux(a, b ↑ .iz )
si no
a ↑ .valor := b ↑ .valor
c := b ; b := b ↑ .dr
liberar(c)
fsi
fproc

32
Árboles binarios de búsqueda de pares clave-valor

parámetro CLAVES
usa BOOLEANOS
tipos clave
operaciones
== : clave clave −→ bool
6= : clave clave −→ bool
variables
c, d, e : clave
ecuaciones
(x == y) = cierto ⇐ x = y
x = y ⇐ (x == y) = cierto
x 6= y = ¬(x == y)
fparámetro

33
parámetro CLAVES<
usa CLAVES
operaciones
< : clave clave −→ bool
> : clave clave −→ bool
variables
c, d, e : clave
ecuaciones
c<c = falso { antirreflexividad }
c<e = cierto ⇐ c < d ∧ d < e { transitividad }
c < d ∨ d < c = cierto ⇐ c = 6 d { totalidad }
c>d = d<c
fparámetro

parámetro VALORES-MODIFICABLES
tipos valor
operaciones
combinar : valor valor −→ valor
fparámetro

34
especificación ÁBB-CON-PARES[CLAVES<, VALORES-MODIFICABLES]
usa BOOLEANOS
tipos árbol-bb
operaciones
abb-vacı́o : −→ árbol-bb { constructora }
plantar : árbol-bb clave valor árbol-bb −→p árbol-bb { constructora }
insertar : clave valor árbol-bb −→ árbol-bb
consultar : clave árbol-bb −→p valor
está? : clave árbol-bb −→ bool
mı́nimo : árbol-bb −→p clave
máximo : árbol-bb −→p clave
eliminar : clave árbol-bb −→ árbol-bb
es-abb-vacı́o? : árbol-bb −→ bool
variables
c, d : clave
v, w : valor
iz , dr : árbol-bb

35
ecuaciones
plantar(iz , c, v, dr ) = error
⇐ ¬(es-abb-vacı́o?(iz ) ∨ c > máximo(iz )) ∨
¬(es-abb-vacı́o?(dr ) ∨ c < mı́nimo(dr ))
insertar(c, v, abb-vacı́o) = plantar(abb-vacı́o, c, v, abb-vacı́o)
insertar(c, v, plantar(iz , c, w, dr )) = plantar(iz , c, combinar(w, v), dr )
insertar(c, v, plantar(iz , d, w, dr )) = plantar(insertar(c, v, iz ), d, w, dr ) ⇐ c < d
insertar(c, v, plantar(iz , d, w, dr )) = plantar(iz , d, w, insertar(c, v, dr )) ⇐ c > d
consultar(c, abb-vacı́o) = error
consultar(c, plantar(iz , c, v, dr )) = v
consultar(c, plantar(iz , d, w, dr )) = consultar(c, iz ) ⇐ c < d
consultar(c, plantar(iz , d, w, dr )) = consultar(c, dr ) ⇐ c > d
está?(c, abb-vacı́o) = falso
está?(c, plantar(iz , c, v, dr )) = cierto
está?(c, plantar(iz , d, w, dr )) = está?(c, iz ) ⇐ c < d
está?(c, plantar(iz , d, w, dr )) = está?(c, dr ) ⇐ c > d

36
mı́nimo(abb-vacı́o) = error
mı́nimo(plantar(abb-vacı́o, c, v, dr )) = c
mı́nimo(plantar(iz , c, v, dr )) = mı́nimo(iz ) ⇐ ¬es-abb-vacı́o?(iz )
máximo(abb-vacı́o) = error
máximo(plantar(iz , c, v, abb-vacı́o)) = c
máximo(plantar(iz , c, v, dr )) = máximo(dr ) ⇐ ¬es-abb-vacı́o?(dr )
eliminar(c, abb-vacı́o) = abb-vacı́o
eliminar(c, plantar(iz , c, v, abb-vacı́o)) = iz
eliminar(c, plantar(abb-vacı́o, c, v, dr )) = dr
eliminar(c, plantar(iz , c, v, dr )) = plantar(iz , mı́nimo(dr ), consultar(mı́nimo(dr ))
eliminar(mı́nimo(dr ), dr ))
⇐ ¬es-abb-vacı́o?(iz ) ∧ ¬es-abb-vacı́o?(dr )
eliminar(c, plantar(iz , d, w, dr )) = plantar(eliminar(c, iz ), d, w, dr ) ⇐ c < d
eliminar(c, plantar(iz , d, w, dr )) = plantar(iz , d, w, eliminar(c, dr )) ⇐ c > d
es-abb-vacı́o?(abb-vacı́o) = cierto
es-abb-vacı́o?(plantar(iz , c, v, dr )) = falso
fespecificación

37
Implementación
tipos
enlace-abb = puntero a nodo-abb
nodo-abb = reg
clave : clave
valor : valor
iz , dr : enlace-abb
freg
árbol-bb = enlace-abb
ftipos

fun consultar(c : clave, a : árbol-bb) dev v : valor { Θ(altura(a)) }


si a = nil entonces error(Clave no definida)
si no
casos
c = a ↑ .clave → v := a ↑ .valor
c < a ↑ .clave → v := consultar(c, a ↑ .iz )
c > a ↑ .clave → v := consultar(c, a ↑ .dr )
fcasos
fsi
ffun
38
proc insertar(e c : clave, e v : valor, a : árbol-bb) { Θ(altura(a)) }
si a = nil entonces
reservar(a)
a ↑ .clave := c ; a ↑ .valor := v ; a ↑ .iz := nil ; a ↑ .dr := nil
si no
casos
c = a ↑ .clave → combinar(a ↑ .valor , v)
c < a ↑ .clave → insertar(c, v, a ↑ .iz )
c > a ↑ .clave → insertar(c, v, a ↑ .dr )
fcasos
fsi
fproc

39
Árboles equilibrados

fun altura(a : árbol-bin) dev alt : nat


si es-árbol-vacı́o?(a) entonces alt := 0
si no alt := 1 + máx(altura(hijo-iz(a)), altura(hijo-dr(a)))
fsi
ffun


 c0 n=0
Talt(n) = 

Talt(p) + Talt(q) + c1 n > 0

fun diferencia(n, m : nat ) dev d : nat


si n ≥ m entonces d := n − m
si no d := m − n
fsi
ffun

40
fun equilibrado(a : árbol-bin) dev eq : bool
si es-árbol-vacı́o?(a) entonces eq := cierto
si no eq := equilibrado(hijo-iz(a)) ∧ equilibrado(hijo-dr(a)) ∧
(diferencia(altura(hijo-iz(a)), altura(hijo-dr(a))) ≤ 1)
fsi
ffun

c00


 n=0
Teq (n) = 

Teq (p) + Teq (q) + c01n n > 0

41
fun equilibrado2(a : árbol-bin) dev h eq : bool, alt : nat i
si es-árbol-vacı́o?(a) entonces h eq, alt i := h cierto, 0 i
si no
h eq-iz , alt-iz i := equilibrado2(hijo-iz(a))
h eq-dr , alt-dr i := equilibrado2(hijo-dr(a))
eq := eq-iz ∧ eq-dr ∧ (diferencia(alt-iz , alt-dr ) ≤ 1)
alt := 1 + máx(alt-iz , alt-dr )
fsi
ffun

c000


 n=0
Teq2(n) = 

Teq2(p) + Teq2(q) + c001 n > 0

42

Você também pode gostar