Está en la página 1de 22

Laboratorio de Estructuras Discretas Página 1

UNIVERSIDAD CATÓLICA DE SANTA MARÍA


ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMAS

Laboratorio 6.2:

Implementación de Árboles en Python

I
OBJETIVOS

• Utilizar y valorar los Árboles


• Implementarlos en Python
• Razonar recursivamente con Árboles binarios
• Implementarlos en Python como si fueran listas
• Aprender algoritmos especiales de árboles: Código Huffman, Búsqueda a lo ancho,
en profundidad y el problema de las 4 reinas

II
TEMAS A TRATAR

! Implementaciones de Árboles en Python


! Aplicaciones de Árboles binarios en Python
! Algoritmos especiales de árboles

III
MARCO TEORICO

1. Código Huffman

El codificador Huffman crea una estructura arbórea ordenada con todos los
símbolos y la frecuencia con que aparecen. Las ramas se construyen en forma
recursiva comenzando con los símbolos menos frecuentes.

La construcción del árbol se realiza ordenando en primer lugar los símbolos según
la frecuencia de aparición. Los dos símbolos con menor frecuencia de aparición
se eliminan sucesivamente de la lista y se conectan a un nodo cuyo peso es igual

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 2

a la suma de la frecuencia de los dos símbolos. El símbolo con menor peso es


asignado a la rama 1, el otro a la rama 0 y así sucesivamente, considerando cada
nodo formado como un símbolo nuevo, hasta que se obtiene un nodo principal
llamado raíz.
El código de cada símbolo corresponde a la sucesión de códigos en el camino,
comenzando desde este carácter hasta la raíz. De esta manera, cuanto más
dentro del árbol esté el símbolo, más largo será el código.

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 3

2. Algoritmos para encontrar árboles de expansión

2.1. Algoritmo de Búsqueda a lo ancho

La idea de la búsqueda a lo ancho es procesar todos los vértices en un


nivel dado antes de moverse al nivel más alto que sigue.
Consideremos el ejemplo del Grafo G:

Como lo vimos en el ejemplo, Primero se selecciona un orden, por ejemplo


abcdefgh, de los vértices de G. Se elige el primer vértice a y se etiqueta
como raíz. T consiste en un sólo vértice a y ninguna arista. Se agregan a
T todas las aristas (a, x) y vértices en los cuales inciden, para x = b hasta
h, que no produzcan ciclos cuando se agregan a T. Entonces se agregan
a T las aristas (a, b), (a, c) y (a, g). (Se puede usar cualquiera de las aristas
paralelas que inciden en a y g). Se repite este proceso con los vértices del
nivel 1 examinando cada uno en orden:
! b: incluir (b, d).
! c: incluir (c, e).
! g: ninguna
Se repite el proceso con los vértices en el nivel 2:
! d: incluir (d, f).
! e: ninguna
Se repite el proceso con los vértices del nivel 3:
! f : incluir (f, h).
Como no se pueden agregar más aristas al vértice h en el nivel 4, el
proceso termina. Se ha encontrado el árbol de expansión de la figura
anterior.

El algoritmo es el siguiente:
! Entrada: Gráfica conexa G con vértices ordenados v1,v2,…vn
! Salida: Árbol de expansión T.
bla(V, E) {
//V = vértices ordenados v1, . . . , vn; E = aristas

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 4

//V ′ = vértices del árbol de expansión T; E′ = aristas del árbol de expansión T


//v1 es la raíz del árbol de expansión
//S es una lista ordenada
S = (v1)
V ′ = {v1}
E′=∅
while(verdadero) {
for x ∈ S, en orden
for y ∈ V − V ′, en orden
if((x, y) es una arista)
agregar arista(x,y) a E′ y y a V′
if (no se agregaron aristas) return T
S = hijos de S ordenados siguiendo el orden original
}}

La búsqueda a lo ancho se puede usar para probar si una gráfica arbitraria


G con n vértices es conexa. Se usa el método de este algoritmo para
producir un árbol T. Después G es conexa si y sólo si T tiene n vértices.
La búsqueda a lo ancho también resulta útil para encontrar trayectorias de
longitud mínima en una gráfica ponderada desde un vértice fijo v a todos
los demás vértices. Se emplea este método para generar un árbol de
expansión con raíz en v. Se observa que la longitud de una ruta más corta
de v al vértice en el nivel i del árbol de expansión es i. El algoritmo de la
ruta más corta de Dijkstra para gráficas ponderadas se puede considerar
como una generalización de la búsqueda a lo ancho.

2.2. Algoritmo de Búsqueda en profundidad


Una alternativa para la búsqueda a lo ancho es la búsqueda de altura o
en profundidad, que procede a los niveles sucesivos en un árbol en la
oportunidad más cercana posible.

! Entrada: Gráfica conexa G con vértices ordenados v1, v2, …, vn


! Salida: Árbol de expansion T
bll(V, E) {
//V ′ = vértices del árbol de expansión T; E ′ = aristas del árbol de expansión T
//v1 es la raíz del árbol de expansión
V ′ = {v1}
E′=∅
w = v1
while(verdadero) {
while(hay arista (w, v) que al agregarla a T no crea un ciclo en T) {
elegir la arista (w, vk) con k mínima, que si se
agrega a T no crea un ciclo en T
agregar(w, vk) a E′
agregar vk a V′
w = vk
}
if (w == v1)
return T
w = padre de w en T //hacia atrás
} }

Veamos cómo funcionaría en nuestro Ejemplo. Use la búsqueda a


profundidad (anterior algoritmo) para encontrar un árbol de expansión para
la gráfica de la figura anterior con el orden de vértices abcdefgh.
Se selecciona el primer vértice a y se le llama raíz. Después se agrega al
árbol la arista (a, x), con x mínima. En este caso se agrega la arista (a, b).
Se repite este proceso. Se agregan las aristas (b, d), (d, c), (c, e), (e, f) y
(f, h). En este punto, no se puede agregar una arista de la forma (h, x), de
manera que regresamos a f, el padre de h, y tratamos de agregar una arista

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 5

de la forma (f, x). Una vez más, no es posible agregar una arista de la forma
(f, x), así́ que regresamos a e, el padre de f. Esta vez se puede agregar la
arista (e, g). En este punto, no hay más aristas que agregar, de manera
que regresamos a la raíz y el procedimiento termina.

3. El problema de las 4 reinas

El problema de las cuatro reinas trata de colocar cuatro fichas en una


cuadricula de 4 × 4 de manera que no haya dos fichas en la misma fila,
columna o diagonal. Construya un algoritmo de regreso para resolver el
problema de las cuatro reinas. (Para usar la terminología del ajedrez, éste
es el problema de colocar cuatro reinas en un tablero de 4 × 4 de manera
que ninguna reina pueda atacar a otra).
La idea del algoritmo es colocar fichas sucesivamente en las columnas.
Cuando es imposible colocar una ficha en una columna, se regresa y ajusta
la ficha de la columna anterior.

El algoritmo es el siguiente:

! Entrada: Un arreglo fila de tamaño 4


! Salida: verdadero, si hay solución. Falso, si no hay solución
[Si hay solución, la reina k está en la columna k y el renglón fila(k)].
cuatro_reinas(fila) {
k = 1 //inicia en la columna 1
//inicia en el renglón 1
//como fila(k) se incrementa antes de usarla, se hace fila(1) igual a 0
fila(1) = 0
while(k>0) {
fila(k) = fila(k) + 1
//se busca un movimiento legal en la columna k
while (fila(k) ≤ 4 ∧ columna k, fila(k) conflicto)
//se intenta el siguiente renglón
fila(k) = fila(k) + 1
if (fila(k) ≤ 4)
if(k == 4)
return verdadero
else{//siguiente columna
k=k+1
fila(k) = 0
}
else //regresar a columna anterior
k=k−1
}
return falso //no hay solución
}

El árbol que genera el anterior algoritmo se ilustra en la siguiente figura. La


numeración indica el orden en que se generaron los vértices. La solution
se encuentra en el vertices 8.
El problema de las n reinas es colocar las n fichas en una cuadrícula de n
× n de manera que no haya dos fichas en la misma fila, columna o diagonal.
Es directo verificar que no hay solución a los problemas de dos o tres
reinas. Se acaba de ver que el algoritmo anterior genera una solución para
el problema de las cuatro reinas. Se han dado muchos desarrollos para
generar una solución al problema de las n reinas para toda n ≥ 4.

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 6

La búsqueda a lo largo o de regreso es atractiva, en especial en un


problema como el de este ejemplo, donde todo lo que se quiere es una
solución. Como una solución, si acaso existe, se encuentra en un vértice
terminal, moviéndose a los vértices terminales tan pronto como sea
posible, en general no se puede evitar generar algunos vértices
innecesarios.

4. Sugerencias para resolver problemas

La búsqueda a profundidad y la búsqueda a lo ancho son la base de


muchos algoritmos de gráficas. Por ejemplo, cualquiera de los dos resulta
útil para determinar si una gráfica es conexa: Si se puede visitar cada
vértice en una gráfica a partir de un vértice inicial, la gráfica es conexa; de
otra manera no es conexa. La búsqueda a profundidad se puede emplear
como algoritmo de búsqueda, en cuyo caso se llama de regreso. Este
algoritmo, el regreso se usa para buscar una solución al problema de las 4
reinas; también se puede utilizar para buscar ciclos de Hamilton en una
gráfica, para generar permutaciones y para determinar si dos gráficas son
isomorfas.

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 7

5. Implementación de árboles binarios como listas en Python

Vamos a implementar los arboles binarios como si fueran listas, de la


maneras más sencilla posible para concentrarnos en los problemas
recursivos a resolver.
Representaremos el siguiente árbol:

De la siguiente manera:
myTree = ['a', ['b', ['d', [], []], ['e', [], []] ], ['c', ['f',
[], []],[] ]]

Donde un árbol binario de un solo nodo r es representado como [r, [],


[]]
Las operaciones básicas para obtener la raíz, el hijo izquierdo, el hijo
derecho y saber si es un árbol vacío respectivamente son:
def raizArbin(a):
return a[0]

def izqArbin(a):
return a[1]

def derArbin(a):
return a[2]

def vacioArbin(a):
return a == []

Además los recorridos son:

def preOrden(arbin):
if not vacioArbin(arbin):
print raizArbin(arbin)
preOrden(izqArbin(arbin))
preOrden(derArbin(arbin))

def inOrden(arbin):
if not vacioArbin(arbin):
inOrden(izqArbin(arbin))
print raizArbin(arbin)
inOrden(derArbin(arbin))

def postOrden(arbin):
if not vacioArbin(arbin):
postOrden(izqArbin(arbin))
postOrden(derArbin(arbin))
print raizArbin(arbin)

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 8

Probamos el programa con el árbol anterior para que nos muestre sus
recorridos:

>>> preOrden(myTree)
a
b
d
e
c
f
>>> inOrden(myTree)
d
b
e
a
f
c
>>> postOrden(myTree)
d
e
b
f
c
a

6. Las Operaciones básicas para obtener la raíz, el hijo izquierdo, el hijo


derecho y saber si es un árbol vacío respectivamente son:
def inicArbinOr():
#Crea un arbol busqueda binaria
return []

def insArbinOr(arbinOr,elem):
if arbinOr==[]:
return [elem,[],[]]
else:
if elem > arbinOr[0]:
arbinOr[2] = insArbinOr(arbinOr[2],elem)
else:
arbinOr[1] = insArbinOr(arbinOr[1],elem)
return arbinOr

def mayorElem(arbinOr):
if arbinOr[2]==[] :
return arbinOr[0]
else:
return mayorElem(arbinOr[2])

def elimArbinOr(arbinOr, elem):


p = inicArbinOr()
if arbinOr[0]==elem:
if arbinOr[1]==[] and arbinOr[2]==[]:
return []
elif arbinOr[1]==[]:
p = arbinOr[2]
return p
else:
mayor = mayorElem(arbinOr[1])
arbinOr[0] = mayor
arbinOr[1] = elimArbinOr(arbinOr[1], mayor)

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 9

elif arbinOr[0] > elem:


arbinOr[1] = elimArbinOr(arbinOr[1], elem)
else:
arbinOr[2] = elimArbinOr(arbinOr[2], elem)
return arbinOr

def estaArbinOr(arbinOr, elem):


if arbinOr==[]:
return False
else:
if arbinOr[0]==elem:
return True
else:
if arbinOr[0] > elem:
return estaArbinOr(arbinOr[1], elem)
else:
return estaArbinOr(arbinOr[2], elem)

7. Ejemplos de ejecución para árboles de búsqueda binaria como listas en


Python:

Creamos un árbol de búsqueda binaria:

>>> a2 = inicArbinOr()
>>> a2
[]

Insertamos algunos elementos en el árbol de búsqueda binaria:

>>> a2 = insArbinOr(a2, 6)
>>> a2
[6, [], []]
>>> a2 = insArbinOr(a2, 8)
>>> a2
[6, [], [8, [], []]]
>>> a2 = insArbinOr(a2, 3)
>>> a2
[6, [3, [], []], [8, [], []]]
>>> a2 = insArbinOr(a2, 7)
>>> a2
[6, [3, [], []], [8, [7, [], []], []]]
>>> a2 = insArbinOr(a2, 1)
>>> a2
[6, [3, [1, [], []], []], [8, [7, [], []], []]]

Eliminamos algunos elementos del árbol de búsqueda binaria:

>>> a2 = elimArbinOr(a2, 7)
>>> a2
[6, [3, [1, [], []], []], [8, [], []]]
>>> a2 = elimArbinOr(a2, 6)
>>> a2
[3, [1, [], []], [8, [], []]]

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 10

Más ejercicios de inserción y eliminación:

>>> a2 = insArbinOr(a2, 2)
>>> a2
[3, [1, [], [2, [], []]], [8, [], []]]
>>> a2 = elimArbinOr(a2, 3)
>>> a2
[2, [1, [], []], [8, [], []]]

Probamos el método que devuelve si existe o no un elemento en un árbol


de búsqueda binaria:

>>> estaArbinOr(a2, 1)
True
>>> estaArbinOr(a2, 11)
False
>>> a2
[2, [1, [], []], [8, [], []]]

Más ejercicios de inserción y eliminación:

>>> a2 = insArbinOr(a2, 6)
>>> a2 = insArbinOr(a2, 7)
>>> a2 = insArbinOr(a2, 17)
>>> a2
[2, [1, [], []], [8, [6, [], [7, [], []]], [17, [],
[]]]]
>>> a2 = elimArbinOr(a2, 8)
>>> a2
[2, [1, [], []], [7, [6, [], []], [17, [], []]]]

8. Ejemplo para hallar la altura de un árbol binario:

Pensando recursivamente se puede resolver muchos problemas de la


manera simple. Para resolver un problema como hallar la altura de un árbol
binario, obtenemos el siguiente algoritmo:

def alturaArbin(a):
if vacioArbin(a):
return 0
elif vacioArbin(izqArbin(a)) and vacioArbin(derArbin(a)):
return 1
else:
izq = alturaArbin(izqArbin(a))
der = alturaArbin(derArbin(a))
if izq<der:
return der + 1
else:
return izq + 1

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 11

El truco acá es entender que la altura de cualquier árbol binario es la altura


del mayor de sus subárboles izquierdo o derecho + 1 que es la altura de la
raíz con respecto a sus hijos.

9. Otro ejemplo: calcular el número de veces que aparece un elemento en


un árbol.

La idea principal es primero que las veces que un elemento ocurre en


cualquier árbol vacío es cero. Luego si no es vacío, hay que comparar el
elemento en la raíz y luego hacer lo mismo con sus hijos y el total de
apariciones será la suma. Así:

def ocurre(a, elem):


if vacioArbin(a):
return 0
if raizArbin(a) == elem:
return 1 + ocurre(izqArbin(a), elem) +
ocurre(derArbin(a), elem)
else:
return ocurre(izqArbin(a), elem) +
ocurre(derArbin(a), elem)

10. Otro ejemplo mas: Informar si 2 árboles binarios son iguales

Aquí tenemos que comparar los datos y la estructura del árbol. Por tanto
empezamos por comparar arboles vacíos y luego sus subárboles. Así:

def igualesArbin( arbin1, arbin2):


if (vacioArbin(arbin1) and not vacioArbin(arbin2)) or
(vacioArbin(arbin2) and not vacioArbin(arbin1)):
return False
elif vacioArbin(arbin1) and vacioArbin(arbin2):
return True
elif raizArbin(arbin1) != raizArbin(arbin2):
return False
else:
return igualesArbin(izqArbin(arbin1),izqArbin(arbin2))
and igualesArbin(derArbin(arbin1),derArbin(arbin2))

11. Algunas definiciones en Arboles binarios:

11.1. Definiciones principales


El camino entre 2 elementos e1 y e2 de un árbol binario es una
secuencia <x1,x2,…,xn> que cumple que el primer elemento es e1
y el ultimo es e2 y cada elemento es padre de su sucesor. No
siempre existe un camino, pero si existe es único. La raíz se
caracteriza por que tiene un camino a cualquier nodo. La longitud
del camino <x1,x2,…,xn> es n-1 o es el número de veces que se
tiene que aplicar la relación padre -> hijo durante el recorrido.
Utilizando como ejemplo el árbol binario anteriormente mencionado,
el camino <a,b,e> es 2, la longitud del camino <a> es 0. No existe
camino entre d y c. El único camino que lleva de b a d es <b,d>. El
camino <a,b,d> es una rama.

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 12

11.2. Ancestro, descendiente y otros:


Un elemento e1 es ancestro de un elemento e2, si existe un camino
entre e1 y e2. También se dice que e2 es descendiente de e1. El
nivel de un elemento se define como la longitud del camino que
parte de la raíz y llega a el. Entonces el nivel de la raiz es 0, y el de
cualquier elemento es 1 + que el de su padre. El nivel determina
que tan lejos está de la raíz. El ancestro común más próximo de 2
elementos e1 y e2 es el elemento e3 que cumple que es ancestro
de ambos y se encuentra a mayor nivel que cualquier otro ancestro
que compartan.

11.3. Altura y peso de un árbol


La altura de un árbol es la longitud del camino más largo que parte
de su raíz + 1. La altura de un árbol vacío es 0. El peso de un árbol
es el número de elementos que contiene. Recursivamente se define
como la suma de los pesos de sus subárboles + 1. El peso de un
árbol vacío es 0.
Según nuestro ejemplo, la altura del árbol es 3 y el peso es 6.
El nodo a es el ancestro de todos los elementos del árbol, e es
descendiente de b, el ancestro común más próximo de d y c es a. y
el ancestro común más próximo de f y c es c.

11.4. Árbol binario completo


Un árbol es completo si todo elemento no terminal tiene asociados
exactamente 2 subárboles no vacíos. O sea todo elemento de un
árbol completo tiene los 2 subárboles o no tiene ninguno.
Una gráfica de árboles completos y no completos:

Árbol binario no completo Árbol binario completo

11.5. Árbol lleno y casi lleno


Un árbol binario está lleno si es completo y además todas las hojas
están en el mismo nivel. Un árbol binario está casi lleno si está lleno
hasta el penúltimo nivel y todas las hojas del último nivel están tan
a la izquierda como sea posible.

Árbol lleno Árbol casi lleno

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 13

11.6. Arboles iguales, isomorfos y semejantes


Dos árboles son iguales si ambos son vacíos o si sus raíces son
iguales y sus respectivos subárboles izquierdo y derecho. Dos
árboles son isomorfos si tienen la misma estructura pero no
necesariamente los mismos elementos. Dos árboles son
semejantes si contienen los mismos elementos aunque no sean
isomorfos, o sea tienen el mismo contenido pero no la misma
estructura.

Árboles isomorfos

Árboles semejantes

11.7. Ocurrencia de árboles


Un árbol a1 ocurre en otro árbol binario a2, si a1 y a2 son iguales, o
si a1 ocurre en alguno de los subárboles de a2.

Árbol binario Árbol binario que ocurre en el anterior

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 14

IV
(La práctica tiene una duración de 4 horas) ACTIVIDADES

1. Pruebe el siguiente código Huffman:


from heapq import heappush, heappop, heapify
from collections import defaultdict

def encode(symb2freq):
"""Huffman encode the given dict mapping symbols to weights"""
heap = [[wt, [sym, ""]] for sym, wt in symb2freq.items()]
heapify(heap)
while len(heap) > 1:
lo = heappop(heap)
hi = heappop(heap)
for pair in lo[1:]:
pair[1] = '0' + pair[1]
for pair in hi[1:]:
pair[1] = '1' + pair[1]
heappush(heap, [lo[0] + hi[0]] + lo[1:] + hi[1:])
return sorted(heappop(heap)[1:], key=lambda p: (len(p[-1]), p))

txt = "this is an example for huffman encoding"


symb2freq = defaultdict(int)
for ch in txt:
symb2freq[ch] += 1
huff = encode(symb2freq)
print "Symbol\tWeight\tHuffman Code"
for p in huff:
print "%s\t%s\t%s" % (p[0], symb2freq[p[0]], p[1])

2. Compruebe su salida que sea igual a:


Symbol Weight Huffman Code
6 101
n 4 010
a 3 1001
e 3 1100
f 3 1101
h 2 0001
i 3 1110
m 2 0010
o 2 0011
s 2 0111
g 1 00000
l 1 00001
p 1 01100
r 1 01101
t 1 10000
u 1 10001
x 1 11110
c 1 111110
d 1 111111

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 15

3. Pruebe la siguiente implementación en Python del Algoritmo de búsqueda a lo


ancho para generar árboles de expansión
def breadth_first(G, r):
"Arbol de Expansion - Busqueda a lo Ancho"
T = {r: []}
L = [r]
while L:
v = L.pop(0)
for w in G[v]:
if w not in T and w not in L:
L.append(w)
T[w] = [v]
T[v].append(w)
return T

G2 = {
'a': list('bd'),
'b': list('ace'),
'c': list('bf'),
'd': list('aeh'),
'e': list('bdfi'),
'f': list('cegj'),
'g': list('fjl'),
'h': list('dik'),
'i': list('ehjk'),
'j': list('fgi'),
'k': list('him'),
'l': list('g'),
'm': list('k'),
}

print('-'*70)
print("breadth_first de G2 = \\")
pprint(G2)
T2 = breadth_first(G2, 'e')
print("es T2 = \\")
pprint(T2)
#
print('-'*70)

4. Comprueba que su salida sea la siguiente:


C:\Python27>python "c:\Users\Carlo\Documents\Python\spanningtree.py"
----------------------------------------------------------------------

breadth_first de G2 = \
{'a': ['b', 'd'],
'b': ['a', 'c', 'e'],
'c': ['b', 'f'],
'd': ['a', 'e', 'h'],
'e': ['b', 'd', 'f', 'i'],
'f': ['c', 'e', 'g', 'j'],
'g': ['f', 'j', 'l'],
'h': ['d', 'i', 'k'],
'i': ['e', 'h', 'j', 'k'],
'j': ['f', 'g', 'i'],
'k': ['h', 'i', 'm'],
'l': ['g'],
'm': ['k']}
es T2 = \
{'a': ['b'],
'b': ['e', 'a', 'c'],
'c': ['b'],
'd': ['e', 'h'],
'e': ['b', 'd', 'f', 'i'],
'f': ['e', 'g', 'j'],
'g': ['f', 'l'],
'h': ['d'],
'i': ['e', 'k'],
'j': ['f'],
'k': ['i', 'm'],
'l': ['g'],
'm': ['k']}

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 16

----------------------------------------------------------------------

C:\Python27>

5. Pruebe la siguiente implementación en Python del Algoritmo de búsqueda en


profundidad para generar árboles de expansión
def depth_first(G, r):
"Arbol de Expansion - Busqueda en Profundidad"
def visit(G, V, E):
padre = dict([])
Vp = {V}
w = V
while True:
if G[w]!=None:
V = G[w][0]
n=0
while V in Vp and n<len(G[w]):
V = G[w][n]
n=n+1
if n==len(G[w]) and V in Vp:
V = padre[w]
else:
padre[V] = w
Vp = Vp | {V}
T[V] = [w]
T[w] = T[w] + [V]
if len(Vp)==len(G):
return
w = V

T = {r: []}
visit(G, r, T)
return T

G2 = {
'a': list('bd'),
'b': list('ace'),
'c': list('bf'),
'd': list('aeh'),
'e': list('bdfi'),
'f': list('cegj'),
'g': list('fjl'),
'h': list('dik'),
'i': list('ehjk'),
'j': list('fgi'),
'k': list('him'),
'l': list('g'),
'm': list('k'),
}

T2 = depth_first(G2, 'e')
print("depth_first de G2 es T2 = \\")
print(T2)
#
print(‘-'*70)

6. Comprueba que su salida sea la siguiente:


C:\Python27>python "c:\Users\Carlo\Documents\Python\spanningtree.py"
----------------------------------------------------------------------

depth_first de G2 es T2 = \
{'a': ['b', 'd'],
'b': ['e', 'a'],
'c': ['f'],
'd': ['a', 'h'],
'e': ['b'],
'f': ['j', 'c', 'g'],
'g': ['f', 'l'],
'h': ['d', 'i'],
'i': ['h', 'j', 'k'],
'j': ['i', 'f'],
'k': ['i', 'm'],
'l': ['g'],
'm': ['k']}

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 17

----------------------------------------------------------------------

C:\Python27>

7. Pruebe la siguiente implementación en Python del Algoritmo de resolución al


problema de las 4 reinas
def isConsistent(q,n):
for i in range(n):
if q[i]==q[n]:
return False
if q[i] - q[n] == n-i:
return False
if q[n] - q[i] == n-i:
return False
return True

def printQueens(q):
N = len(q)
for i in range(N):
for j in range(N):
if q[i] == j:
print "Q",
else:
print "*",
print " "
print " "

def CuatroReinas(q,n):
N = len(q)
if n==N:
printQueens(q)
Fin = True
else:
for i in range(N):
q[n] = i
if (isConsistent(q,n)):
CuatroReinas(q,n+1)

print('-'*70)
n = 4
CuatroReinas([0 for x in range(n)],0)
print('-'*70)

8. Compruebe que su salida sea la siguiente:

C:\Python27>python "c:\Users\Carlo\Documents\Python\CuatroReinas.py"
----------------------------------------------------------------------
* Q * *
* * * Q
Q * * *
* * Q *

* * Q *
Q * * *
* * * Q
* Q * *

----------------------------------------------------------------------

C:\Python27>

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 18

V
EJERCICIOS

1. Ingrese los siguientes arboles binarios y muestre sus recorridos preorden,


inorden y postorden:

a.

b.

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 19

c.

2. Reconstrucción de un árbol a partir de sus recorridos:


Suponga que se quiere reconstruir el árbol binario sin elementos repetidos
cuyos recorridos en inorden y preorden son los siguientes:
Preorden: h – a – b – f – g – c – m – n – d
Inorden: f – b – g – a – c – h – n – m – d

a. Encontrar la raíz y subdividir los recorridos.


Preorden: h – a – b – f – g – c – m – n – d
Inorden: h
f–b–g–a–c– –n–m–d

b. Sabiendo el peso de cada uno de los subárboles (5 el izquierdo y 3 el


derecho) es posible calcular el recorrido en preorden de cada uno de
ellos
Preorden: h – a–b–f–g–c– m–n–d
Inorden: h
f–b–g–a–c– –n–m–d

c. Repetir el paso a. con cada uno de los subárboles encontrados


Preorden: h – a–b–f–g–c– m–n–d
Inorden: h
a m
f–b–g– –c n– –d

d. Repetir el paso b. con cada uno de los subárboles encontrados


Preorden: h – a–b–f–g c m–n d

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 20

Inorden: h
a m
f–b–g– –c n– –d

e. Repetir el mismo proceso descrito en los pasos a. y b. con el único


subárbol que falta.
Preorden: h – a–b–f–g c m–n d
Inorden: h
a m
b c n d
f– –g

3. Reconstruya los árboles binarios con los siguientes recorridos:


a. Preorden: 10 – 20 – 30 – 50 – 60 – 40 – 70 – 80 – 90
Inorden: 50 – 30 – 60 – 20 – 80 – 70 – 90 – 40 – 10
b. Postorden: 60 – 30 – 80 – 70 – 40 – 20 – 50 – 90 – 10
Inorden: 30 – 60 – 20 – 80 – 70 – 40 – 10 – 90 – 50

4. Une al árbol de búsqueda binaria a1, el árbol de búsqueda binaria a2


def unirArbinOr(a1, a2):
5. Elimina del árbol de búsqueda binaria a1 los elementos que no se encuentran
en el árbol de búsqueda binaria a2
def interArbinOr(a1, a2):
6. Indica si todos los elementos de a2 están en a1
def subArbinOr(a1, a2):
7. Pruebe el código Huffman con 3 diferentes cadenas de strings que ud. escoja.
Escriba los resultados y el seguimiento a la respuesta final en cada caso.
8. Prueba el código para generar árboles de expansión según la búsqueda a lo
ancho. Defina 3 diferentes Grafos y pruebe su ejecución. Escriba los resultados
y el seguimiento a la respuesta final en cada caso.
9. Prueba el código para generar árboles de expansión según la búsqueda en
profundidad. Defina 3 diferentes Grafos y pruebe su ejecución. Escriba los
resultados y el seguimiento a la respuesta final en cada caso.
10. Prueba el código para responder al problema de las 4 reinas, utilizando 5, 6,..,
12 reinas. ¿Qué puedes deducir de los resultados?
11. Implementar los siguientes algoritmos utilizando la implementación de árboles
binarios como listas:
12. Calcular el peso de un árbol binario
def pesoArbin(arbin):

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 21

13. Informar si un elemento se encuentra presente en un árbol binario


def estaArbin(arbin, elem):
14. Calcular el número de hojas de un árbol.
def numHojas(arbin):
15. Decidir si existe un camino entre 2 elementos e1 y e2
def camino(arbin, e1, e2):
16. Calcular el número de elementos que tiene un árbol binario en un nivel dado.
def contNivel(arbin, num):
17. Informar si 2 árboles binarios sin elementos repetidos son semejantes
def semejantes(arbin1, arbin2):
18. Informa si 2 árboles binarios son isomorfos
def isomorfosArbin(arbin1, arbin2):
19. Informa si 2 árboles binarios son semejantes aunque existan elementos
repetidos. O sea si existen repetidos n veces en arbin1, también deberá existir
n veces en arbin2.
def semejantesArbin(arbin1, arbin2):
20. Informa si un árbol binario es completo
def completoArbin(arbin):
21. Informa si un árbol binario está lleno
def llenoArbin(arbin):
22. Informa si un árbol binario está casi lleno
def casillenoArbin(arbin):

VI
CUESTIONARIO

1. ¿Cuáles son las principales implementaciones de Árboles en Python?


2. ¿Cuál es tu opinión sobre la importancia de los Árboles para la resolución de
problemas?
3. ¿Cómo son los algoritmos de las aplicaciones de Árboles en Python?
4. ¿Cuál es tu opinión sobre la importancia de las aplicaciones de Árboles?

VII
BIBLIOGRAFIA Y REFERENCIAS

! JOHNSONBAUGH, R. Matemáticas Discretas. México. Pearson. 6ta Ed. 2005

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2


Laboratorio de Estructuras Discretas Página 22

! LEE KENT D. Python programming fundamentals. New York. Springer Verlag. 2011.
! GORVATOV V.A. Fundamentos de la Matemática Discreta. Rusia. Edit. Mir Moscu. 1988.
! Documentación Python 2.7.9 Tutorial de Python. www.python.org

Carlo Corrales Delgado, Karim Guevara P. Lab 6.2

También podría gustarte