You are on page 1of 142

1

CONTENIDO ANALITICO DEL CURSO



I.- OBJETIVOS

Generales

- Estudiar las estructuras de datos como elementos esenciales en la ciencia
computacional
- Organizar y manejar las estructuras de datos bsicas en conjunto con los Algoritmos
asociados.
- Implementar los algoritmos de estructuras de datos de acuerdo a una metodologa de
programacin para dar soluciones a los problemas computacionales

Especficos

- Entender el conocimiento acerca de las diferentes estructuras de datos usadas para la
organizacin de la informacin que requiere un algoritmo.
- Aprender a determinar cul de las estructuras de datos es la ms adecuada para la
solucin de un problema en particular y el uso eficiente de la memoria tanto para el
acceso rpido a los datos como para el ahorro de espacio.
- Adquirir habilidades para el anlisis de algoritmos en trminos de tiempo y espacio, con
el propsito de saber optar por el algoritmo que resuelva el problema de la forma ms
ptima.
- Aplicar mtodos de cuantificacin de la eficiencia de un algoritmo en trmino de
tiempo.
- Aplicar tcnicas de verificacin de programas con el fin de desarrollar algoritmos
correctos y eficientes.

CONTENIDO

UNIDAD TEMA C CP LAB PRC TOTAL
I Diseo y Anlisis de Algoritmos 2 2 2 0 6
II Algoritmos recursivos 2 2 4 0 8
III Estructuras de datos
fundamentales
6 2 8 0 16
IV Teora de grafos 3 2 5 0 10
V Arboles 6 2 8 0 16
VI Ordenamiento y Bsqueda 4 4 8 0 16
2

Proyecto 0 0 0 12 12
TOTALES 23 14 35 12 84


CONTENIDOS POR TEMAS

UNIDAD I: DISEO Y ANALISIS DE ALGORITMOS
I.1 Estructura de Datos y Algoritmos

I.1.1 Necesidad de las estructuras de datos
I.1.2 Tipos de datos abstractos.
I.1.3 Problemas, Algoritmos y Programas
I.1.4 Eficiencia de Algoritmos
I.1.5 Anlisis de Algoritmos
I.1.6 TDA
I.1.7 Estructura de Datos

UNIDAD II: ALGORITMOS RECURSIVOS
II.1 Recursin
II.1.1 Principios de Recursin.
Pautas para emplear la recursin.
Como funciona la recursin.
Recursin de extremo final.
Cuando no usar la recursin.

II.2 Como utilizar la recursin.
II.3 Algoritmo de rastreo inverso.
II.4 Divide y vencers.

Laboratorio
Funcin de Ackermann
Torre de Hanoi
Las ocho reinas

UNIDAD III: ESTRUCTURAS DE DATOS FUNDAMENTALES
III Listas, Pilas y Colas.
III.1 Listas.
Definiciones
3

Listas Enlazadas
Listas circulares
Listas Doblemente Enlazadas
Laboratorio : Aplicaciones de Listas

III.2 Pilas
Definiciones y Ejemplos
Pilas basadas en arreglos
Operaciones en Pilas
Aplicaciones de Pilas
Laboratorio : Aplicaciones de Pilas

III.3 Colas
Definiciones y Ejemplos
Colas basadas en arreglos
Operaciones en Colas
Aplicaciones de colas
Laboratorio : Aplicaciones de Colas

UNIDAD IV: TEORIA DE GRAFOS

IV.1Grafos Dirigidos
IV.1.1 Definiciones fundamentales.
IV.1.2 Representacin de grafos dirigidos.
IV.1.3 Problema de los caminos ms cortos con un solo origen.
IV.1.4 Problema de los caminos ms cortos entre todos los pares.
IV.1.5 Recorrido de grafos dirigidos.
IV.1.6 Grafos dirigidos acclicos.
IV.2 Grafos no dirigidos.
IV.2.1 Definiciones.
IV.2.2 rboles abarcadores de costo mnimo.
IV.2.3 Recorridos
Laboratorio
Algoritmo de Dijkstra
Algoritmo de Prim

UNIDAD V: RBOLES

V.1 rboles Binarios
V.1.1 Definicin y Propiedades
4

V.1.2 Operaciones en rboles Binarios
V.1.3 Recorridos en rboles Binarios
V.1.4 Implementacin en rboles Binarios
V.1.5 Bsqueda en rboles Binarios
V.1.6 Montculos y colas de prioridad
Laboratorio : Aplicaciones en rboles Binarios
V.2 Arboles Generales
V.3 Arboles AVL
V.4 Arboles B, B+
Laboratorio : Aplicaciones en rboles Generales

UNIDAD VI: ORDENAMIENTO Y BUSQUEDA

VI.1 Ordenamiento interno
Terminologa y Notacin
VI.2 Metodologas de clasificacin
Rpida, Quicksort
Por montculos
Shell
Binaria
Clasificacin por seleccin
Por intercambio directo
Laboratorio : Implementacin de Algoritmos de Ordenamiento
VI.3 Mtodos de Ordenamiento Externos
Laboratorio : Ordenamiento en Archivos
VI.4 Bsquedas.
Lineal
Binaria
Hashing
Laboratorio : Bsqueda en Arreglos ordenados, desordenados y Archivos.
5

I Unidad: Algoritmos computacionales
1. Introduccin

En la siguiente unidad pretendemos presentar una serie de concepto y definiciones propios del
estudio de los Algoritmos, su anlisis y diseo. En el mismo podremos encontrar los conceptos
de algoritmo y algunos de sus componentes, anlisis y diseo. Estudiaremos los diferentes tipos
de formas y tamaos o medidas en que se pueden almacenar y representar los datos y
estructuras en un algoritmo o programa. As como las diferentes tcnicas para disearlos como
son el mtodo de la fuerza bruta, el voraz, divide y vencers, programacin dinmica, de vuelta
atrs, entre otros.

De igual forma analizaremos las definiciones y algunas caractersticas, reglas, normas, tipos de
algoritmos de bsqueda y ordenacin as como sus aplicaciones.

Al final de la unidad veremos los que es la verificacin y derivacin de programas, donde
daremos los conceptos bsicos de semntica y sus tipos haciendo mayor nfasis en la semntica
axiomtica, la recursividad e iteracin, los diseos de estos ltimos, as como los tpicos ciclos
utilizados en algoritmos y programas y los paso a tener en cuenta al momento de desarrollar un
algoritmo iterativo o recursivo.

2. Marco Histrico
Un algoritmo es un conjunto de operaciones y procedimientos que deben seguirse para resolver
un problema. La palabra algoritmo se deriva del nombre latinizado del gran Matemtico rabe
Mohamed Ibn Al Kow Rizmi, el cual escribi sobre los aos 800 y 825 su obra Quitad Al
Mugabala, donde se recoga el sistema de numeracin hind y el concepto del cero. Fue
Fibonacci, el que tradujo la obra al latn y el inicio con la palabra: Algoritmi Dicit.

El lenguaje algortmico es aquel por medio al cual se realiza un anlisis previo del problema a
resolver y encontrar un mtodo que permita resolverlo. El conjunto de todas las operaciones a
realizar y e orden en que se deben efectuarse, se le denomina algoritmo.
Es un mtodo para resolver un problema mediante una serie de datos precisos, definidos y
finitos.

3. Generalidades
El programador de computadoras es antes que nada una persona que resuelve problemas, por
lo que para llegar a ser un programador eficaz se necesita aprender a resolver problemas de un
modo riguroso y sistemtico. A la metodologa necesaria para resolver problemas mediante
programas se denomina Metodologa de la Programacin. El eje central de esta metodologa es
el concepto de algoritmo.
6

Un algoritmo es un mtodo para resolver un problema. Aunque la popularizacin del trmino
ha llegado con el advenimiento de la era informtica, algoritmo proviene de Mohammed al-
Khowarizmi, matemtico persa que vivi durante el siglo IX y alcanzo gran reputacin por el
enunciado de las reglas para sumar, restar, multiplicar y dividir nmeros decimales; la traduccin
al latn del apellido de la palabra algorismus derivo posteriormente en algoritmo. Euclides, el
gran matemtico griego (del siglo IV antes de Cristo) que invento un mtodo para encontrar el
mximo comn divisor de dos nmeros, se considera con Al-Khowarizmi el otro gran padre de la
algoritmia (ciencia que trata de los algoritmos).

El profesor Niklaus Wirth, inventor de Pascal, Modula - 2 y Oberon, titulo uno de sus ms famosos
libros, Algoritmos + Estructuras de Datos = Programas, significndonos que solo se puede llegar
a realizar un buen programa con el diseo de un algoritmo y una correcta estructura de datos.
Esta ecuacin ser de una de las hiptesis fundamentales consideradas en esta obra. La
resolucin de un problema exige el diseo de un algoritmo que resuelva el problema propuesto.





Los pasos para la resolucin de un problema son:
1. Diseo de algoritmo, que describe la secuencia ordenada de pasos que conducen a la
solucin de un problema dado. (Anlisis del problema y desarrollo del algoritmo).
2. Expresar el algoritmo como un programa de lenguaje de programacin adecuado. (Fase
de codificacin.)
3. Ejecucin y validacin del programa por la computadora.

Para llegar a la realizacin de un programa es necesario el diseo previo de algoritmo, de modo
que sin algoritmo no puede existir un programa.

Los algoritmos son independientes tanto del lenguaje de programacin en que se expresan
como de la computadora que lo ejecuta. En cada problema el algoritmo se puede expresar en
un lenguaje diferente de programacin y ejecutarse en una computadora distinta; sin embargo,
el algoritmo ser siempre el mismo. As, por ejemplo, en una analoga con la vida diaria, una
receta de un plato de cocina se puede expresar en espaol, ingls o francs, pero cualquiera que
sea el lenguaje, los pasos para la elaboracin del plato se realizaran sin importar el idioma del
cocinero.

En la ciencia de la computacin y en la programacin, los algoritmos son ms importantes que
los lenguajes de programacin o las computadoras. Un lenguaje de programacin es tan solo
un medio para expresar un algoritmo y una computadora es solo un procesador para ejecutarlo.

Problema
Diseo del
algoritmo
Programa de
computadora
7

Tanto el lenguaje de programacin como la computadora son los medios para obtener un fin:
conseguir que el algoritmo se ejecute y se efecte el proceso correspondiente.

Dada la importancia del algoritmo en la ciencia de la computacin, un aspecto muy importante
ser el diseo de algoritmos. El diseo de la mayora de los algoritmos requiere creatividad y
conocimientos profundos de la tcnica de la programacin. En esencia, la solucin de un
problema se puede expresar mediante un algoritmo.












La definicin de un algoritmo debe definir tres partes: Entrada, Proceso y Salida. En el algoritmo
de receta de cocina citado anteriormente se tendr:

Entrada: ingrediente y utensilios empleados.
Proceso: elaboracin de la receta en la cocina.
Salida: terminacin del plato (por ejemplo, cordero).

Ejemplo de Algoritmo:
Un cliente ejecuta un pedido a una fbrica. Esta examina en su banco de datos la ficha del
cliente; si el cliente es solvente entonces la empresa acepta el pedido; en caso contrario
rechazara el pedido. Redactar el algoritmo correspondiente.









Diseo del Algoritmo:
Los pasos del algoritmo son:
1. inicio
2. leer el pedido
3. examinar la ficha del cliente
4. si el cliente es solvente aceptar pedido; en caso contrario, rechazar
Pedido
5. fin

Caractersticas de los Algoritmos:

Las caractersticas fundamentales que debe cumplir todo algoritmo son:

1.- Un algoritmo debe ser preciso e indicar el orden de realizacin de cada paso.
2.- Un algoritmo debe estar definido. Si se sigue un algoritmo dos veces, se debe obtener
el mismo resultado cada vez.
3.- Un algoritmo debe ser finito. Si se sigue un algoritmo se debe terminar en algn
momento; o sea, debe tener un numero finito de pasos.

8

En la etapa de anlisis del proceso de programacin se determina que hace el programa. En la
etapa de diseo se determina como hace el programa la tarea solicitada.

Los mtodos ms eficaces para el proceso de diseo se basan en el conocido por Divide y
Vencers, es decir, la resolucin de un problema complejo se realiza dividiendo el problema en
sub problemas y a continuacin dividir estos sub problemas en otros de nivel ms bajo, hasta
que pueda ser implementada una solucin en la computadora. Este mtodo se conoce
tcnicamente como diseo descendente (Top Down) o modular. El proceso de romper el
problema en cada etapa y expresar cada paso en forma ms detallada se denomina refinamiento
sucesivo.

Cada sub programa es resuelto mediante un modulo (sub programa) que tiene un solo punto de
entrada y un solo punto de salida.

Cualquier programa bien diseado consta de un programa principal (el modulo de nivel mas alto)
que llama a sub programas (mdulos de nivel mas bajo) que a su vez pueden llamar a otros sub
programas. Los programas estructurados de esta forma se dice que tienen un diseo modular y
el mtodo de romper el programa en mdulos ms pequeo se llama Programacin Modular.
Los mdulos pueden ser planeados, codificados, comprobados y depurados
independientemente (incluso por diferentes programadores) y a continuacin combinarlos
entre si.










El proceso que convierte los resultados del anlisis del problema en un diseo modular con
refinamiento sucesivo que permitan una posterior traduccin al lenguaje se denomina diseo
de algoritmo.

El diseo del algoritmo es independiente del lenguaje de programacin en el que se vaya a
codificar posteriormente.

Consideraciones y Criterios para Disear Algoritmos

El proceso implica la ejecucin de los siguientes pasos hasta que el programa se
termina:

1.- Programar modulo.
2.- Comprobar el modulo.
3.- Si es necesario, depurar el modulo.
4.- Combinar el modulo con los mdulos anteriores
9

Algunas consideraciones estilsticas pueden contribuir a mejor la calidad de los algoritmos (y
programas) mediante la reduccin del nmero de errores que aparecen al desarrollar los.
Tambin influyen haciendo que nuestros algoritmos resulten ms fciles de leer y entender para
otras personas.

Los criterios de estilo pueden reflejarse en un conjunto de normas de estilo de codificacin. Ello
asegura que tanto algoritmos como programa resulten legibles y puedan modificarse fcilmente
en caso de necesidad. Generalmente, estas normas de estilo se dirigen hacia aspectos como la
forma de construir los nombres de variables o tipo de datos que aparezcan., la tipografa seguida
a la hora de escribir nombres de variables, subprogramas, palabras claves, etc. El modo de en
columnar las distintas partes de un algoritmo para facilitar su lectura y comprensin, y la normas
sobre cmo y dnde deben de introducirse los comentarios.

Estilo y calidad de los programas van fuertemente unidos. Ante la pregunta Cules son las
caracterstica de un buen algoritmo?, las siguientes respuestas reflejan, cierta medida, los
factores que identifican la calidad en ellos.

1. Correccin, el algoritmo debe funcionar.
2. Nunca se debe olvidar que la caracterstica ms simple e importante de un algoritmo es
que funcione. Pude aparecer obvio, pero resulta difcil de asegurar en algoritmos complejos.
3. Eficiencia, el algoritmo no debe desaprovechar recursos. La eficiencia de un algoritmo se
mide por los recursos que este consume. En particular, se habla de la memoria y del tiempo de
ejecucin. A pesar de que con la reduccin de los costes del hardware es posible disear
computadores ms rpidos y con ms memoria, no hay que desperdiciar estos recursos y tratar
de desarrollar algoritmos ms eficientes.

4. Claridad, el algoritmo debe estar bien documentacin. La documentacin ayuda a
comprender el funcionamiento de los algoritmos. Ciertos detalles o algunas partes especiales de
los mismos pueden olvidarse fcilmente o quedar oscura si no estn adecuadamente
comentadas.

En realidad, y de acuerdo con los puntos de vista anteriores, la calidad de un algoritmo tiene
muchas facetas y todas ellas importantes. Resumiendo, lo ideal es que nuestro algoritmo
resulte correcto, eficiente, claro, fiable y fcil de mantener.

Otras Caractersticas de diseo de Algoritmos computacionales

1.- Recursos De Computadores Y Complejidad
Algoritmo: Su ejecucin requiere unos recursos.
10


Un algoritmo es mejor cuantos menos recursos consuma, su facilidad de programarlo, corto,
fcil de entender, robusto, etc.

2.-Criterio empresarial: Maximizar la eficiencia.

3.- Eficiencia: Relacin entre los recursos consumidos y los productos conseguidos.

4.- Recursos consumidos: Tiempo de ejecucin.

Memoria principal: Entradas/salidas de datos.

Comunicaciones, procesadores, etc.
Lo que se consigue: Resolver un problema de forma exacta, forma aproximada o algunos casos.

Recursos consumidos:
Ejemplo. Cuntos recursos de tiempo y memoria consume el siguiente algoritmo sencillo?
i:= 0
a[n+1]:= x
repetir
i:= i + 1
hasta a[i] = x

Respuesta: Depende.

De qu depende? De lo que valga n y x, de lo que exista en a, de los tipos de datos, de la
mquina...

En general los recursos dependen delos siguientes Factores externos:

1.- El ordenador donde lo ejecutemos: Dual Core, Core due, i3, i5, i7 etc.


ALGORITMO
0 ms
entradas
1 ms
salidas
Memoria E/S
Comunicacin
11

2.- El lenguaje de programacin y el compilador usado.

La implementacin que haga el programador del algoritmo. En particular, de las estructuras de
datos utilizadas.

3.- Tamao de los datos de entrada.

Ejemplo. Calcular la media de una matriz de NxM.
Contenido de los datos de entrada. Mejor caso. El contenido favorece una rpida ejecucin.

Peor caso. La ejecucin ms lenta posible.
Caso promedio. Media de todos los posibles contenidos.

Los factores externos no aportan informacin sobre el algoritmo.

Conclusin: Estudiar la variacin del tiempo y la memoria necesitada por un algoritmo respecto
al tamao de la entrada y a los posibles casos, de forma aproximada (y parametrizada).

Externos: no aportan informacin sobre el algoritmo.

Normalmente usaremos la notacin T(N)=..., pero qu significa T(N)?
Tiempo de ejecucin en segundos. T(N) = bN + c. Suponiendo que b y c son constantes, con los
segundos que tardan las operaciones bsicas correspondientes.

Instrucciones ejecutadas por el algoritmo: T(N) = 2N + 4.

Tardarn todas lo mismo?
Ejecuciones del bucle principal. T(N) = N+1.
Cunto tiempo, cuntas instrucciones,...?
Sabemos que cada ejecucin lleva un tiempo constante, luego se diferencia en una constante
con los anteriores.

Asignacin de tiempos, para el conteo de instrucciones. Algunas reglas bsicas.

Operaciones bsicas (+, -, *, :=,...): Una unidad de tiempo, o alguna constante.
Operaciones de entrada salida: Otra unidad de tiempo, o una constante diferente.
Bucles FOR: Se pueden expresar como una sumatoria, con los lmites del FOR.
IF y CASE: Estudiar lo que puede ocurrir. Mejor caso y peor caso segn la condicin. Se puede
predecir cundo se cumplirn las condiciones?

12

Llamadas a procedimientos: Calcular primero los procedimientos que no llaman a otros.
Bucles WHILE y REPEAT: Estudiar lo que puede ocurrir. Existe una cota inferior y superior del
nmero de ejecuciones? Se puede convertir en un FOR?

El anlisis de algoritmos tambin puede ser a posteriori: implementar el algoritmo y contar lo
que tarda para distintas entradas.

Ejemplo. Programa cifras.exe:

N= 4, T(4)= 0.1 ms
N= 5, T(5)= 5 ms
N= 6, T(6)= 0.2 s
N= 7, T(7)= 10 s
N= 8, T(8)= 3.5 min

Qu conclusiones podemos extraer?

Anlisis a priori: Evitamos la implementacin, si el algoritmo es poco eficiente. Podemos hacer
previsiones. Podemos comparar con otros algoritmos

4. Tcnica de diseo de algoritmos

Diseo de Algoritmos:
Hasta ahora se han realizado algunos comentarios respecto a la necesidad de disear algoritmos
correctos y eficientes utilizando los elementos de un lenguaje de programacin .Es necesario en
este momento mencionar algo sobre como hacerlo. El acto de disear un algoritmo puede
considerarse como una tarea que difcilmente podr ser del todo automatizada.

Todo problema algortmico es un reto para su diseador, algunos resultan inmediatos de
resolver, otros son bastante complejos. La investigacin en esta rea ha permitido descubrir un
conjunto de mtodos o esquemas de diseo hacia los cuales puede orientarse la realizacin de
muchos algoritmos.

No obstante, y a pesar de que resulta mas adecuado en bastantes casos utilizar alguno de estos
esquemas que realizar un diseo desde cero, idear un algoritmo continua siendo una labor
bastante creativa donde los conocimientos y la experiencia del propio diseador tiene un papel
fundamental.

El diseo de un algoritmo que resuelva un problema es, en general, una tarea difcil. Una forma
de facilitar esta labor consiste en recurrir a tcnicas conocidas de diseo de algoritmos, es decir,
13

a esquemas muy generales que pueden adaptarse a un problema particular al detallar las partes
generales del esquema.

Muchos problemas pueden resolverse buscando una solucin fcil y directa pero, a la vez
bastante ineficiente. Este mtodo, llamado de fuerza bruta, puede ser muy directo, pero con un
poco de anlisis puede encontrarse algoritmos ms eficientes. El esquema ms sencillo quizs
sea el llamado divide y vencers, basado en la descomposicin de un problema en sub
problemas.

Otros esquemas requieren un anlisis minucioso del problema de forma que la solucin se vaya
construyendo en etapas. Si puede preverse que decisin conviene en cada etapa para producir
cierto tipo de mejor resultado, tenemos una solucin voraz, si la decisin en una etapa, solo
puede tomarse tras considerar varias soluciones de otras etapas ms simples, la solucin es
dinmica. Aun as, hay problemas cuya solucin no puede hallarse sino mediante un proceso de
bsqueda, a pesar de lo complejas que son las operaciones de bsqueda, su uso adecuado
mediante el esquema de bsqueda con retroceso (o backtracking) permite ganar gran eficiencia
respecto a soluciones de fuerza bruta. Por ltimo, conviene conocer otros mtodos de diseo de
algoritmos que tambin resultan de utilidad prctica.

Nos estamos refiriendo a mtodos basados en la mejora de la eficiencia (por ejemplo, el uso de
parmetros de acumulacin al resolver problemas utilizando divide y vencers, y el empleo de
tablas como estructura auxiliar para la resolucin eficiente de problemas donde se aplica
programacin dinmica), y a mtodos basados en transformaciones del dominio para encontrar
una solucin mas fcilmente a un problema en un dominio transformado, siendo dicha solucin
finalmente adaptada al dominio original.

Consideraciones generales

Si el hbil programador dispone de un recetario de algoritmos de donde poder seleccionar el
ms adecuado para cada problema, su tarea se simplifica.

Supongamos que disponemos de una especificacin precisa, completa y consistente del
problema a resolver y queremos obtener un algoritmo en el que, dados uno datos de entrada
valido, se produzca cierto resultado. Si no nos importa la eficiencia del algoritmo, podramos
utilizar un algoritmo general llamado algoritmo del museo britnico. Se programa un
computador de manera que parta de un conjunto de axioma matemticos y los que use para
reducir aleatoriamente teoremas vlidos.

Aprender los principios bsicos del diseo de algoritmos podemos preguntarnos por un mtodo
aceptable. El ms entendido, y quizs el mejor, es organizar el diseo sobre un esquema de
14

algoritmo o una tcnica de diseo que haya demostrado su utilidad para otros problemas. Este
mtodo de trabajo es practicable, puesto que existe un nmero reducido de esquema y tcnicas
de diseo.

El conocimiento de tcnicas de diseo es solo un primer paso para el diseador, que debe
completarse con otros conocimientos y, sobre todo, con la experiencia.














4.1.- Algoritmo de fuerza bruta

Comenzamos el estudio de esquemas algortmicos con un mtodo sencillo, pero que debe
evitarse siempre que se pueda, dada su ineficacia; la fuerza bruta. En realidad, no es un esquema
algortmico, sino ms bien calificativo

Para una forma de disear algoritmos: tomar una solucin directa, poco reflexionada. En
principio, esto no es malo, pero dado que no se ha analizado apenas el problema, es muy
probable que no se hayan aprovechado propiedades deducibles del problema y que la solucin
sea terriblemente ineficiente.

Una solucin por fuerza bruta tambin puede resultar adecuada como primera aproximacin a
la solucin final, porque su desarrollo puede permitir profundizar ms sobre el problema y
conocer propiedades que sean utilizadas para obtener otra versin ms eficiente.

Por ejemplo:

Algunos algoritmos de bsqueda de un elemento en un vector. Uno de ellos realizaba una
bsqueda secuencial con complejidad lineal sobre el tamao del vector y poda usarse con
Tipos de algoritmos:
1.- Fuerza Bruta
2.- Recursivo
3.- Divide y vencers
4.- Mtodo voraz
5.- Vuelta atrs
6.- Heurstico
7.- Aproximacin
8.- Iterativos



15

cualquier vector. Otro algoritmo realizaba un bsqueda dicotomica o binaria, con complejidad
logartmica, y solo se poda usar cuando el vector estuviese ordenado. El algoritmo primero
responde a un razonamiento ms sencillo, por lo que uno puede sentirse tentado a usar siempre.
Esta es la solucin de fuerza bruta: una solucin directa, pero poco reflexionada. Lo ms
razonable es comprobar si el vector esta ordenado y, en caso positivo, aprovechar esta
circunstancia para usar el algoritmo ms eficiente: el de bsqueda binaria.

4.2.- Algoritmos Recursivos:

La recursin es un mecanismo que permite obtener, en combinacin con otras construcciones,
una solucin funcional a muchos problemas. Muchos algoritmos recursivos resultan eficientes,
pero no todos: hay algunos fcilmente formulables, pero muy ineficientes. En estos casos, dichos
algoritmos pueden servir como una primera aproximacin al algoritmo definitivo, pero debe
mejorar su rendimiento para que sea prctico.

Estudiaremos en la siguiente unidad mas a fondo este tipo de algoritmo

4.3.- Algoritmo Divide y vencers.

La tcnica de divide y vencers es quizs una de las utilizadas debido a su sencillez: si un
problema es demasiado grande para resolverlo de una vez, se descompone en varias partes ms
fciles de resolver. Mas formalmente, dado un problema al resolver planteando en trminos de
una entrada de tamao n, la tcnica de divide y vencers parte la entrada en k sub problemas,
1<k<=n. Estos sub problemas se resuelven independientemente y despus se combinan sus
soluciones parciales para obtener la solucin del problema original. Este esquema de particin
de problemas se denomina esquema de divide y vencers solo en el caso en que los problemas
sean de la misma clase del problema original. Esta restriccin permite una formulacin y
resolucin recursiva de los sub problemas. Por supuesto, deben existir algunos pasos sencillos
cuya solucin pueda calcularse fcil y directamente; en caso contrario, el proceso recursivo
nunca terminara.

Ejemplo: Bsqueda de una palabra en un diccionario

Como ejemplo sencillo de aplicacin de esta estrategia puede considerarse la bsqueda de una
palabra en un diccionario de acuerdo con el siguiente criterio.

Se abre el diccionario por la pagina centrar(quedando dividido en dos mitades) y se comprueba
si la palabra aparece all o si es lxico grficamente anterior o posterior. Si no ha encontrado y
es anterior se procede a buscarla en la primera mitad., si es posterior, se buscara en la segunda
16

mitad. El procedimiento se repite sucesivamente hasta encontrar la palabra o decidir que no
aparece.


4.4.- Algoritmo de mtodo voraz:

Este mtodo trata de producir tipo de mejor resultado a partir de conjunto de opciones
candidatas .Para ello, se va procedimiento paso a paso realizndose la mejor eleccin (usando
una funcin objetivo que respeta un conjunto de restricciones ) de entre las posibles. Puede
emplearse en problemas de optimizacin, como el conocido de la mochila, en la bsqueda de
caminos mnimos sobre grafos, la planificacin en el orden de la ejecucin de unos programas
en un computador, etc.

Ejemplo: . Dar un cambio utilizando el menor nmero de monedas

Como ejemplo introductorio sencillo al que puede aplicarse la tcnica voraz, se considera el
problema de un cambio o desglose en monedas. Hay que desglosar una cantidad en un conjunto
de monedas tratando de cumplir alguna condicin; en este caso, utilizar el menor nmero de
monedas. Para ello, se parte de un conjunto de tipos de monedas vlidas, de las que se supone
que hay cantidad suficiente para realizar el desglose, y de un importe. Se trata de indicar la
cantidad (menor) de monedas de los tipos considerados, tales que sumados sus valores
equivalgan al importe.

Para simplificar, suponemos que manejamos dinero espaol y, en particular, podemos utilizar
slo monedas de 500, 100, 50, 25, 5 y 1 pesetas para el desglose. Estos valores se definen por
medio de un tipo enumerado MONEDAS. Asimismo, se declaran los tipos VALORES y
CANTIDADES para representar el valor asignado a cada unidad monetaria y la cantidad de cada
tipo de moneda que se devolver en el desglose. Su declaracin es la siguiente:

TYPE
Monedas -> M500 I M100 I M50 I M25 I M5 I M1,
Valores -> Integer M500M1
Cantidades -> Integer M500.M1

Se supone inicialmente asignados los valores a cada uno de los tipos de monedas. Los
elementos de la tcnica voraz estn presentes en este problema de la siguiente forma:
El conjunto de candidatos est constituido por cada una de las monedas de los
diferentes tipos que se pueden usar para realizar el desglose del importe dado.
Una solucin viene dada por un conjunto de monedas devuelto tras el desglose, y cuyo
valor total es igual al importe a desglosar.
17

La condicin de factibilidad de la solucin siendo construida establece en el desglose
debe ser menor o igual que el importe a desglosar.
La funcin de seleccin establece que hay que elegir, mientras sea posible, la moneda
de mayor valor de entre las candidatas.
La funcin objetivo cosiste en minimizar la cantidad total de monedas utilizadas en el
desglose.

Con esta informacin se puede comprobar que en este problema estn presentes los distintos
elementos de la tcnica voraz. Adems, cuando un candidato (moneda) se incorpora al
conjunto solucin, ste no ser nunca excluido de l.

4.5.- Algoritmos De Vuelta Atrs

Existen un alto nmero de problemas que pueden formularse como la bsqueda de la mejor
solucin o del conjunto de todas las soluciones que satisfacen ciertas condiciones. Adems, cada
solucin es el resultado de una secuencia de decisiones. Por supuesto, debe existir una funcin
de criterios que debe ser satisfecha por cada secuencia solucin u optimizada por dichas
secuencias solucin si solo queremos la mejor. En algunos problemas de optimizacin se conoce
un criterio ptimo de seleccin que puede usarse de forma voraz. Otros problemas satisfacen el
principio de optimalidad, pudindose aplicar la tcnica de programacin dinmica. Sin embargo,
todava hay otros problemas peores que no queda mas remedio que realizar una bsqueda de
la solucin.

Esquema de Algoritmos de Vuelta Atrs:

Sea (x1,...,xi) el camino desde la raz hasta un nodo de un rbol del espacio de estado. Sea
G(x1...xi) el conjunto de todos los valores posibles de xi+1 tales que (x1,...,xi+1) es un camino
hasta el estado del problema. Supongamos que existe algn predicado acotador A tal que
A(x1,...,xi+1) es falso si el camino (xi,...,xi+1) no puede extenderse para alcanzar un nodo de
respuesta. Por lo tanto, los candidatos para la posicin i+1 del vector de solucin x1..n son
aquellos valores generados por G que satisfacen A. Supongamos que tambin existe algn
predicado R que determina si un camino (x1,...,xi+1) termina en un nodo de respuesta.

El Algoritmo de Vuelta Atrs se especifica de la forma siguiente:

PROCEDURE Retroceso (IN k : INTEGER, INOUT solucion : elemento1...n) ->
VAR: nodo: elemento
FOR noso IN G(solucion, 1, k-1) DO
Solucion k := nodo;
IF R(solucion, 1, k) THEN
18

IF R(solucion, 1,k) THEN
<< guardar solucion >>;
Retroceso (k+1, solucion)

La llamada inicial del algoritmo es Retroceso(1, solucin). El procedimiento no hace ninguna
llamada recursiva cuando k = N+1 o cuando ningn nodo generado por G satisface el elemento
posible que satisfacen A se aade una solucin particular, se comprueba si se ha encontrado
una solucin. Despus simplemente se llama recursivamente al algoritmo para generar los
estados descendientes. Se sale del bucle FOR cuando no quedan mas valores para solucin
terminando la llamada actual al algoritmo.

Ramificacin (Bifurcacin) Y Acotacin

Los mtodos de Ramificacin y Acotacin constituyen una variante de las tcnicas de retroceso
para problemas donde se trata de encontrar el valor mximo o mnimo de cierta funcin objeto
(esto suele suceder en los problemas de programacin lineal entera).
La tcnica de ramificacin y acotacin aplica de la siguiente manera:

Supngase que al recorrer un rbol y alcanza una hoja se tiene una solucion con k colores, y que
al seguir avanzando en el rbol (mediante la aplicacin de varios pasos de retrocesos) se alcanza
un nodo que requiere k+1 colores. En este punto podemos retroceder (y no seguir avanzando
por mas ramas), pues tenemos ya una solucin mayor. As, k sirve de cota inferior al retroceso.
Este mismo proceso se repite en el resto de nodos del rbol, evitando as la exploracin de gran
parte de al estructura.

4.6.- Algoritmos Heursticos

Existen muchos problemas para los cuales no se conocen algoritmos que puedan encontrar la
solucin de forma eficiente: problemas NP-completos.

La solucin exacta puede requerir un orden factorial o exponencial: el problema de la explosin
combinatoria.

Se hace necesario utilizar algoritmos heursticos:

Un algoritmo heurstico (o simplemente heurstica) puede producir una buena solucin (puede
que la ptima) pero tambin puede que no produzca ninguna solucin o dar una solucin no
muy buena. Normalmente, se basa en un conocimiento intuitivo del programador sobre un
determinado problema.

19

La estructura de algoritmo voraz se puede utilizar para construir procedimientos heursticos:
hablamos de heursticas voraces.

Objetivo: obtener buenas soluciones en un tiempo de ejecucin corto.

El problema del agente viajero

Problema: Dado un grafo no dirigido, completo y ponderado G = (V, A), encontrar un ciclo simple
de costo mnimo que pase por todos los nodos.

Es un problema NP, pero necesitamos una solucin eficiente.

Problema de optimizacin, donde la solucin est formada por un grupo de elementos en cierto
orden: podemos aplicar el esquema voraz.

Posibilidades:

1. Los nodos son los candidatos. Empezar en un nodo cualquiera. En cada paso moverse al
nodo no visitado ms prximo al ltimo nodo seleccionado.

2. Las aristas son los candidatos. Hacer igual que en el algoritmo de Kruskal, pero
garantizando que se forme un ciclo.

Heurstica voraz 1 Una solucin ser un cierto orden en el conjunto de nodos (c
1
, c
2
, ..., c
n
), el
orden de visita de los nodos.

Inicializacin: seleccionar un nodo cualquiera.

Funcin de seleccin: de los nodos candidatos seleccionar el ms prximo al ltimo (o al primero)
de la secuencia actual (c
1
, c
2
, ..., c
a
).
15
30
20
25
50
45
10
35
40 55
5
4
3
1
2
20


Acabamos cuando tengamos n nodos.
Ejemplo. Empezando en el nodo 1.
Solucin: (1, 4, 5, 3, 2)
Coste: 30+15+25+10+45=125
Empezando en el nodo 3.
Solucin: (5, 4, 3, 2, 1)
Coste: 15+20+10+45+50=140
Heurstica voraz 2 Una solucin ser un conjunto de aristas (a
1
, a
2
, ..., a
n-1
) que formen un
ciclo hamiltoniano, sin importar el orden.

Empezar con un grafo sin aristas.

Seleccin: seleccionar la arista candidata de menor coste.

Factible: una arista se puede aadir a la solucin actual si no se forma un ciclo (excepto para la
ltima arista aadida) y si los nodos unidos no tienen grado mayor que 2.Ejemplo.
Solucin: ((2, 3), (4, 5), (3, 4), (1, 2), (1, 5))

Coste = 10+15+20+45+50 = 140

Conclusiones:

Ninguno de los dos algoritmos garantiza una solucin ptima. Sin embargo, normalmente ambos
dan soluciones buenas, prximas a la ptima.

Posibles mejoras: buscar heursticas mejores; repetir la heurstica 1 con varios orgenes; bien,
a partir de la solucin del algoritmo intentar hacer modificaciones locales para mejorar esa
solucin.

4.7.- Algoritmos De Aproximacin

Dado un problema NP completo, es probable que no sepamos resolverlo de manera precisa y
completa utilizando un algoritmo polinomico en tiempo. Para este tipo de problemas, los
algoritmos que no conducen a una solucin ptima se llaman algoritmos de aproximacin. Sin
embargo, resulta parcialmente interesante que estos garanticen una cota en el margen de
imprecisin.

A continuacin se ilustra este tipo de tratamiento de problemas al problema de recubrimiento
de un grafico:
21


Dado un grafo G=(V,A), se trata de encontrar un conjunto con el menor numero de vrtices tal
que toda arista sea incidente por lo menos de un vrtice de V.

Este problema se puede resolver a travs de otro aproximado, como es calcular el ajuste
maximizal del grafo G. Se trata de calcular un subconjunto A de aristas tal que dos aristas
cualquiera de A no tengan ningn vrtice comn y toda arista de A-A comparta algn vrtice
comn con una arista de A. Este nuevo problema garantiza conseguir un recubrimiento que
contiene no ms de dos vrtices del recubrimiento mnimo. El procedimiento para construir un
ajuste maximizal de un grafo G consistira en ir tomando aristas de G, de una en una y en
cualquier orden e ir eliminando las incidentes al conjunto que se est construyendo hasta
recubrir todo en grafo.

Para poder aplicar el nuevo problema aproximado, sera necesario demostrar que el conjunto
de todos los vrtices inciden a las aristas de un ajuste maximal M para un grafo G es un
recubrimiento con no ms de dos veces el nmero de veces el recubrimiento de tamao mnimo.
Esto es evidente, ya que por la definicin de ajuste maximal, los vrtices incidentes a las aristas
de M son un recubrimiento de G. tambin por la propia definicin, ningn vrtice perteneciente
a M puede recubrir a mas de una arista en M. En consecuencia, por lo menos la mitad de los
vrtices de M deben pertenecer a un recubrimiento.

4.8.- Algoritmos Iterativos

Cada clase de bucle resulta til en situaciones diferentes. El bucle FOR se utiliza cuando se
conoce el nmero de iteraciones que se quiere realizar. El bucle WHILE es usado en las otras
situaciones en que no se conoce el nmero de iteraciones. El bucle LOOP es til cuando puede
haber varias condiciones de salida del bucle, situadas en diferentes partes del cuerpo, o cuando
la condicin de salida no esta al comienzo del bucle.

Sin embargo, conocer la instruccin iterativa que mas conviene para un algoritmo es solo el
comienzo de la construccin de la instruccin. Es conveniente tener algunas guas para el diseo
de algoritmos iterativos.

El diseo de un algoritmo iterativo se hace sobre una base distinta de la de uno recursivo. En los
algoritmos imperativos se tiene disponible toda la informacin del problema en las variables.
Por esta razn, es til partir los datos del problema en dos:

- La parte que representa el problema aun no resuelto.

- La parte que representa el problema ya resuelto; es decir, el resultado ya calculado.
22

Una vez que se han distinguido estas dos partes, el bucle se construye a partir de tres decisiones
hechas sobre dicha particin:

a) Fijar la situacin inicial. El problema a resolver se encuentra en los parmetros de entrada
o de entrada/salida; si estos datos quieren modificarse durante el algoritmo, deben copiarse en
variables auxiliares. tambin hay que dar un valor inicial a las variables que representan la
solucin vaca.

b) Formar el cuerpo del bucle. Para ello puede usarse un razonamiento parecido al
recursivo. Se supone, por generalidad, que la iteracin se encuentra en un estado intermedio.
Debe entonces determinarse que hacer en una iteracin para avanzar en la resolucin del
problema.

c) Determinar la condicin de terminacin. Corresponde a la situacin en que se ha hallado
la solucin completa. Esta parte est totalmente relacionada con la eleccin de la instruccin
iterativa. Segn la forma de la iteracin, se elige un bucle FOR, WHILE o LOOP, como se describi
antes.

Normalmente, la terminacin del bucle puede especificarse de forma sencilla, incluso en casos
relativamente complicados. Por ejemplo, cuando se tiene un bucle WHILE con una condicin
compuesta es posible que pueda usarse la tcnica del centinela para obtener una especificacin
ms sencilla.

Algo con lo que hay que tener especial cuidado es la terminacin de los bucles. Esta es fcil de
determinar en un algoritmo recursivo porque basta con tomar una medida de los parmetros y
comprobar que disminuye en cada llamada recursiva, de forma que se acerca al tamao de los
casos bsicos. En una solucin iterativa se razona igual, pero la tarea es algo ms complicada
porque el control del proceso repetitivo no tiene parmetros, sino que se hace a partir de la
informacin contenida en las variables.


5.- DEFINICIN, IMPORTANCIA Y UTILIDAD DE LAS ESTRUCTURAS DE DATOS
Concepto: Es una coleccin de datos organizada de un modo particular.
Las estructuras de datos pueden ser de dos tipos:

23

Estructuras de datos estticas
Estructuras de datos dinmicas.

5.1.- Definicin: Estructuras de datos estticas

Son aquellas en las que se asigna una cantidad fija de memoria cuando se declara la variable.
En muchas ocasiones se necesitan colecciones de datos que crezcan y reduzcan su tamao
en memoria a medida que el programa progrese. Esto se logra implementando las estructuras
dinmicas.

5.2.- Estructura de datos dinmicas

Son aquellas cuya ocupacin en memoria puede aumentar o disminuir en tiempo de ejecucin

Importancia y utilidad de las estructuras de datos

La programacin estructurada significa escribir un programa de acuerdo a las siguientes reglas.

1.-El programa tiene un diseo modular
2.-Los mdulos son diseados de un modo descendente
3.-Cada mdulo se codifica utilizando las tres estructuras de control bsicas:

a)Secuencia
b)Seleccin
c)Repeticin

La programacin estructurada se refiere a un conjunto de tcnicas que aumentan
considerablemente la productividad del programa reduciendo en elevado grado el tiempo
requerido para escribir, verificar, depurar y mantener los programas. Utiliza un nmero limitado
de estructuras de control que minimizan la complejidad de los programas y por consiguiente
reducen los errores y hacen los programas en general ms eficientes.

5.3.- Clasificacin de las estructuras de datos
Estructuras de datos estticas

1.- Simples o primitivas
a) Boolean
24

b) Char
c) Integer
d) Real

2.- Compuestas
a) Arreglos
b) Conjuntos
c) Strings
d) Registros
e) Archivos

Estructura de datos dinmicas (TDA)
1.- Lineales
a) Pila
b) Cola
c) Lista

2.- No lineales
a) rboles
b) Grafos

5.4.- Operaciones ms comunes de las estructuras de datos

1.-Creacin de la estructura
2.-Eliminar la estructura
3.-Leer los datos de la estructura
4.-Ordenar los datos de la estructura
5.-Agregar un tem a la estructura
6.-Eliminar un tem de la estructura
7.-Buscar un tem de la estructura
8.-Fusionar dos estructuras homogneas
25

II Unidad: Algoritmos recursivos

1.- Recursividad

1.1. Definicin

Un procedimiento o funcin se dice recursivo si durante su ejecucin se invoca directa o
indirectamente a s mismo. Esta invocacin depende al menos de una condicin que acta como
condicin de corte que provoca la finalizacin de la recursin.
Un algoritmo recursivo consta de:

1- Al menos un caso trivial o base, es decir, que no vuelva a invocarse y que se ejecuta
cuando se cumple cierta condicin, y

2- el caso general que es el que vuelve a invocar al algoritmo con un caso ms pequeo
del mismo.

Los lenguajes como Pascal, que soportan recursividad, dan al programador una herramienta
poderosa para resolver ciertos tipos de problemas reduciendo la complejidad u ocultando los
detalles del problema.

La recursin es un medio particularmente poderoso en las definiciones matemticas. Para
apreciar mejor cmo es una llamada recursiva, estudiemos la descripcin matemtica de
factorial de un nmero entero no negativo:

1, si n = 0
n! =
n * ( n - 1 ) * ( n - 2 ) * .. * 1 = n * ( n - 1 )! si n > 0

Esta definicin es recursiva ya que expresamos la funcin factorial en trminos de s misma.
Ejemplo: 4! = 4 * 3!
Por supuesto, no podemos hacer la multiplicacin an, puesto que no sabemos el valor de 3!

3! = 3 * 2!
2! = 2 * 1!
1! = 1 * 0!
0! = 1

Podemos ahora completar los clculos

26

1! = 1 * 1 = 1
2! = 2 * 1 = 2
3! = 3 * 2 = 6
4! = 4 * 6 = 24

1.2.- Diseo de Algoritmos Recursivos

Para que una funcin o procedimiento recursivo funcione se debe cumplir que:
- Existe una salida no recursiva del procedimiento o funcin y funciona correctamente en
ese caso.
- Cada llamada al procedimiento o funcin se refiere a un caso ms pequeo del mismo.
- Funciona correctamente todo el procedimiento o funcin.

Para poder construir cualquier rutina recursiva teniendo en cuenta lo anterior, podemos usar
el siguiente mtodo:

- Primero, obtener una definicin exacta del problema.
- A continuacin, determinar el tamao del problema completo a resolver. As se
determinarn los valores de los parmetros en la llamada inicial al procedimiento o
funcin.
- Tercero, resolver el caso base en el que problema puede expresarse no recursivamente.
Esto asegurar que se cumple el punto 1 del test anterior.
- Por ltimo, resolver correctamente el caso general, en trminos de un caso ms pequeo
del mismo problema (una llamada recursiva). Esto asegurar cumplir con los puntos 2 y 3
del test.

Cuando el problema tiene una definicin formal, posiblemente matemtica, como el ejemplo del
clculo del factorial, el algoritmo deriva directamente y es fcilmente implementable en otros
casos debemos encontrar la solucin ms conveniente.

Ejemplo
Clculo del factorial para enteros no negativos

1, si n = 0

n! =
n * ( n - 1 ) ! si n > 0



27

Cdigo Pascal:
function factorial(n: integer):integer;
begin
if n=0 then factorial = 1 (* caso base *)
else factorial = n * factorial(n-1) (* caso general *)
end;

1.3.- Cmo funcionan los Algoritmos Recursivos

Para entender cmo funciona la recursividad es necesario que tengamos presente las reglas y
los tipos de pasaje de parmetros provistos por Pascal.

Si un procedimiento o funcin p invoca a otro q, durante la ejecucin de q se reservarn
locaciones de memoria para todas las variables locales de q y para los parmetros pasados por
valor. Al terminar la ejecucin de q este espacio es desocupado. Ahora bien, si durante la
ejecucin de q se produce una llamada a s mismo, tendremos una segunda instancia de q en
ejecucin, la primera instancia se suspende hasta que la instancia recursiva termine. Antes de
iniciarse la ejecucin recursiva de q, se ocupan nuevas locaciones de memoria para las variables
locales y parmetros por valor de q. Cualquier referencia a estas variables acceder a estas
locaciones. Las locaciones reservadas durante la ejecucin inicial de q son inaccesibles para la
2da. instancia de q.

Cuando la 2da. instancia de q termine, el control vuelve a la primera instancia de q, exactamente
al lugar siguiente a la llamada recursiva. Cualquier referencia a las variables locales o parmetros
por valor de q acceder a las locaciones reservadas inicialmente, inaccesibles para la segunda
instancia de q.

Como vemos, no se conoce la cantidad de memoria que va a utilizarse al ejecutar un
procedimiento o funcin recursivo sino que se produce una asignacin dinmica de memoria, es
decir, a medida que se producen instancias nuevas, se van apilando las que quedan
pendientes: se ponen al menos tres elementos en la pila:

- una para la direccin de vuelta,
- otra para el/los parmetro/s formal/es y
- otra para el identificador de la funcin que en esencia es un parmetro pasado por
variable.

Cuando la ltima instancia de la recursin - elige el caso base- se cumple, se desapila esa
instancia y el control vuelve a la instancia anterior; as hasta desapilar todas las instancias.

28

Esta pila que se va generando en memoria es importante tenerla en cuenta por lo que
debemos asegurarnos que el algoritmo recursivo no sea divergente.

Vamos a ver cmo funciona la recursin en algunos problemas vistos a travs de una traza dnde
iremos guardando los valores de los parmetros formales.

Hagamos un recorrido del cdigo de la funcin factorial :

function factorial(n: integer):integer;
begin
if n=0 then factorial = 1 (* caso base *)
else factorial = n * factorial(n-1) (* caso general *)
end;

La llamada inicial es: write(factorial(5)).

La primera instancia se coloca en la pila, luego a medida que se va invocando la funcin, vamos
apilando el valor del parmetro formal que se enva:

Como n = 0 el algoritmo va por la
rama del then llegando al caso base
obteniendo factorial(0) = 1
0 Instancia 6
1 Instancia 5
2 Instancia 4
3 Instancia 3
4 Instancia 2
5 Instancia 1
n

Ahora desapilamos y vamos reemplazando el resultado obtenido en la instancia posterior:

1- Desapilo Instancia 6 0 factorial(0) 1
2- Desapilo Instancia 5 1 1 * factorial(0) 1 * 1 = 1
3- Desapilo Instancia 4 2 2 * factorial(1) 2 * 1 = 2
4- Desapilo Instancia 3 3 3 * factorial(2) 3 * 2 = 6
5- Desapilo Instancia 2 4 4 * factorial(3) 4 * 6 = 24
6- Desapilo Instancia 1 5 5 * factorial(4) 5 * 24 =
120
n n* factorial(n-1) factorial

29

Ejemplo
Dado un nmero natural N, encontrar el dgito ms significativo (el dgito ms a la derecha).

function Mas_sig (N: integer):integer;
begin
if N <= 9 then Mas_sig := N
else Mas_sig := Mas_sig (N div 10)
end;

Para N = 25743 es:
Como N <= 9 el algoritmo va por la
rama del then llegando al caso base
obteniendo Mas_sig = 2
2 Instancia 5
25 Instancia 4
257 Instancia 3
2574 Instancia 2
25743 Instancia 1
N


Ahora desapilamos:

1- Desapilo Instancia 5 2 2
2- Desapilo Instancia 4 25 Mas_Sig(2)
3- Desapilo Instancia 3 257 Mas_Sig (25)
4- Desapilo Instancia 2 2574 Mas_Sig(257)
5- Desapilo Instancia 1 25743 Mas_Sig (2574)
N Mas_Sig(N div 10) Mas_Sig

1.4. Cundo usar recursividad y cundo iteracin

La potencia de la recursin reside en la posibilidad de definir un nmero infinito de objetos
mediante un enunciado finito. De igual forma, un nmero infinito de operaciones de clculo
puede describirse mediante un programa recursivo finito, incluso si este programa no contiene
repeticiones explcitas. Los algoritmos recursivos son apropiados principalmente cuando el
problema a resolver, o la funcin a calcular, o la estructura de datos a procesar, estn ya
definidos recursivamente.
Hay varios factores a considerar en la decisin sobre si usar o no una solucin recursiva en un
problema. La solucin recursiva puede necesitar un considerable gasto de memoria para las
mltiples llamadas al procedimiento o funcin, puesto que deben almacenarse las direcciones
30

de vueltas y copias de las variables locales y temporales. Si un programa debe ejecutarse
frecuentemente (como un compilador) y/o debe ser muy eficiente, el uso de programacin
recursiva puede no ser una buena eleccin.
Sin embargo, para algunos problemas una solucin recursiva es ms natural y sencilla de escribir
para el programador. Adems la recursividad es una herramienta que puede ayudar a reducir la
complejidad de un programa ocultando algunos detalles de la implementacin. Conforme el
costo del tiempo y el espacio de memoria de las computadoras disminuye y aumenta el costo
del tiempo del programador, puede ser til usar soluciones recursivas en estos casos.
En general, si la solucin no recursiva no es mucho ms larga que la versin recursiva, usar la no
recursiva. De acuerdo a esta regla, los ejemplos que hemos visto no son buenos ejemplos de
programacin recursiva aunque sirven para ilustrar cmo comprender y escribir procedimientos
y funciones recursivas, sera ms eficiente y sencillo escribirlas iterativamente.
La iteracin y la recursividad cumplen con el mismo objetivo: ejecutar un bloque de sentencias
n veces o que con una condicin de fin adecuada lo termine. Es importante distinguir las
diferentes instancias de la ejecucin, los valores de las variables determinan la instancia
particular que est siendo resuelta en ese momento.

Es necesario que la ejecucin del bloque termine, es decir, el mismo bloque debe contener la
condicin de corte que permita que cualquier instancia menor del problema pueda ser resuelta
directamente. Entonces, cmo decir cul alternativa es ms adecuada?. A veces la definicin del
problema no induce ninguna estructura de control en particular, recin al plantear un mtodo
de resolucin es posible elegir entre iteracin y recursividad. Esta decisin tiene que ver con la
costumbre que tenga el programador al plantear sus algoritmos y, una vez planteado un mtodo
de resolucin, se busca cul herramienta conviene ms.
Hay problemas que aparecen ms naturales para la iteracin y para otros para la recursividad,
por ejemplo, en problemas con contadores, sumatorias y productorias lo natural es la iteracin,
pero en problemas en los que distinguimos un caso base y uno general, como factorial, Fibonacci,
MCD lo natural es la recursin. Pero existe otro factor muy importante a tener en cuenta: la
eficiencia. Veamos el factorial sin recursin:

La cantidad de iteraciones o de llamadas recursivas respectivamente depende del tamao de n,
el tiempo de ejecucin de ambas no vara sustancialmente, pero la versin iterativa reserva tres
lugares en memoria: para aux, prod y Fac, en cambio la recursin guarda memoria para cada
instancia y, si n es grande, el espacio ocupado ser mucho ms grande.

Hay problemas altamente complejos en lo que es casi imposible aplicar iteracin.

31

Ejemplo
La serie de Fibonacci es: 1,1,2,3,5,8,13,21,34,.... donde t0= 1, t1=1, t2=2,..ti = ti-1+ti-2...
Veamos ahora el clculo del n-simo trmino de Fibonacci:

Ejemplo
El Mximo Comn Divisor entre dos enteros A y B se define formalmente as:

MCD(N,M) si M < N
MCD(M,N) N si M es divisible por N: M mod N = 0
MCD(N, M mod N) en cualquier otro caso
Ejemplo

Leer una cadena de caracteres terminada con un punto y contar la cantidad de letras.
No se deben utilizar otras estructuras como string o array.

Podemos expresarlo as: Contar la cantidad de letras que siguen al carcter actual y luego si este
carcter es una letra incrementar el contador. Primero establezcamos una definicin formal del
problema


conta = 0 si caracter = .
cantidad de letras
conta = conta + 1 si el caracter actual es una letra


Notemos que en este procedimiento se pasa conta como parmetro variable. Cmo queda la
pila de recursin?

Ejemplo: Imprimir los elementos de un vector en orden inverso con un procedimiento recursivo.

Recomendamos realizar la traza de este procedimiento y analizar qu sucedera si A fuera un
parmetro valor.

Ejemplo
Dado un arreglo A de enteros, ordenado de forma creciente, vamos a desarrollar el diagrama
de llaves para la funcin de Bsqueda Binaria que realiza la bsqueda de un elemento clave en
A de forma recursiva.

Problemas Tpicamente Recursivos

32

Se utilizan algoritmos recursivos generalmente en:
- Recorrido de rboles
- Anlisis de gramticas y lenguajes
- Exploracin y evaluacin de expresiones aritmticas
- Juegos en los que un movimiento se puede dar en funcin de otro de menor nivel o
complicacin.
- Mtodos de ordenamiento ms eficientes
- Computacin grfica

Ejemplo : Torres de Hanoi

Se dan tres barras verticales y n discos de diferentes tamaos. Los discos pueden apilarse en las
barras formando torres. Los discos aparecen inicialmente en la primer barra en orden
decreciente y la tarea es mover los n discos de la primer barra a la tercera de manera que queden
ordenados de la misma forma inicial. Las reglas a cumplir son:

En cada paso se mueve exactamente un disco desde una barra a otra.

En ningn momento pueden situarse un disco encima de otro ms pequeo.












Vamos a intentar resolverlo probando con 1 2 discos:
1 disco
Mover el disco 1 de A a C

2 discos
Mover el disco 1 de A a B
Mover el disco 2 de A a C
Mover el disco 1 de B a C

A B C
33

Veamos qu pasa con 3 y 4 discos:

3 discos
Mover el disco 1 de A a C
Mover el disco 2 de A a B
Mover el disco 1 de C a B
Mover el disco 3 de A a C
Mover el disco 1 de B a A
Mover el disco 2 de B a C
Mover el disco 1 de A a C
4 discos

Podemos, partir de los movimientos para 3 discos, resolver as: pasamos todos los discos de
A a B menos el disco base usando la barra C como auxiliar. Luego movemos la base a C y volvemos
a repetir los movimientos pasando los discos de la barra B a C usando A como auxiliar

Mover el disco 1 de A a B
Mover el disco 2 de A a C
Mover el disco 1 de B a C
Mover el disco 3 de A a B
Mover el disco 1 de C a A
Mover el disco 2 de C a B
Mover el disco 1 de A a B

Mover el disco a de A a C (Movemos el disco base)

Mover el disco 1 de B a C
Mover el disco 2 de B a A
Mover el disco 1 de C a A
Mover el disco 3 de B a C
Mover el disco 1 de A a B
Mover el disco 2 de A a C
Mover el disco 1 de B a C

Intentemos aplicar el mismo razonamiento para 8 discos. Podramos mover 7 discos de A a B,
pasar el disco 8 a C y luego mover los 7 discos de B a C. Para mover los 7 discos aplicamos lo
mismo: mover 6 discos de B a A, pasar el disco 7 de C a B y luego mover los 6 discos de A a B.
Podemos seguir reduciendo el problema hasta llegar a 1 que es trivial, esto es, el caso base es
n=1 y el procedimiento Pascal recurisvo sera:

34

Procedure Hanoi ( n: tipodiscos; Torre_A, Torre_C, Torre_B: tipotorre);
begin
if n = 1 then MoverDiscoBase(Torre_A, Torre_C)
else begin
Hanoi(n-1, Torre_A, Torre_B, Torre_C);
MoverDiscoBase(n, Torre_A, Torre_C);
Hanoi(n-1, Torre_B, Torre_C, Torre_A)
end
end;

El procedimiento resultante es sencillo y pensar el problema de manera iterativa no hubiese sido
natural de acuerdo al razonamiento efectuado adems de la complejidad de programacin que
originara.

35

III Unidad: Estructura de datos fundamentales
Arreglos, matrices y listas simples
Definicin de arreglo:
Un array (matriz o vector) es un conjunto finito y ordenado de elementos homogneos. La
propiedad ordenado significa que el elemento primero, segundo y tercero,, ensimo de un
array puede ser identificado. Los elementos del array son homogneos, es decir, del mismo tipo
de datos. Los array tambin se conocen como matrices-en matemticas- y tablas- en clculos
financieros.



Arreglos Unidimensionales: Los Vectores
El arreglo (array) unidimensional (matriz de una dimensin) es el tipo ms simple. Un vector de
una dimensin denominado NOTAS que consta de n elementos se puede representar as:
NOTAS(1) NOTAS(2) . . . . . NOTAS(I) . . . . . NOTAS(N)
El subndice o ndice de un elemento (1, 2, . . . , i, n) designa su posicin en la ordenacin del
vector. Como ejemplo de un vector o array unidimensional, se puede considerar el vector
temperatura que contiene las temperaturas horarias registradas en una ciudad durante las
veinticuatro horas del da. Este vector constar de veinticuatro elementos de tipo real, ya que
las temperaturas normales no sern enteras siempre. El valor mnimo permitido de un vector se
denomina lmite inferior del vector (L) y el valor mximo permitido se denomina lmite superior
(U). En ste ejemplo el lmite inferior es 1 y el superior 24.
TEMPERATURA (I) donde 1 <= I <=24
Un ejemplo en pseudo lenguaje podra ser:
Inicio
Suma, const.
Limite= 40
Tipo
En otras palabras un arreglo es una especie de variable que contiene muchos valores
pero cada uno con una posicin diferente. Un arreglo puede ser unidimensional o
vectorial, bidimensional o matricial, o multidimensional.

36

array [1limite] de real : puntuacin
var
puntuacin: puntos
real: suma, media
entero: i
Fin
El pseudo cdigo sera:
inicio
suma 0
escribir (`datos de array')
desde i 1 hasta limite hacer
leer (puntos [i])
suma suma + puntos [i]
fin_desde
media suma/limite
escribir ( ` la media es' , media )
fin
Este programa sirve para procesar un array puntos, realizando las siguientes operaciones; a)
lectura del array, b) clculo de la suma de los vectores del array, c) clculo de la media de los
valores.
1.2. Arreglos Bidimensionales (Tablas/ Matrices)
El array bidimensional se puede considerar como un vector de vectores. Por consiguiente, un
conjunto de elementos, todos del mismo tipo, en el cual el orden de los componentes es
significativo y en el que se necesita especificar los subndices para identificar cada elemento del
array.
Si se visualiza un array unidimensional, se puede considerar como una columna de datos, un
array bidimensional es un grupo de columna.





1.3. Arreglos (Array) Multidimensionales
37

Un array puede ser definido de tres dimensiones, cuatro dimensiones, hasta de n-dimensiones.
En general, un array de n- dimensiones requiere que los valores de n-ndices puedan ser
especificados a fin de identificar un elemento individual del array. Si cada componente de un
array tiene n-ndices, el array se dice que es solo de n-dimensiones.
Ejemplo: Mediciones diarias de temperatura
Punto
Tiempo 1 2 3
1 65.5 68.7 62.0
2 68.8 68.9 64.5
3 70.4 69.4 66.3
4 68.5 69.1 65.8



Operaciones fundamentales de los arreglos:

Ordenacin, bsqueda e intercalacin interna:
1. Introduccin.
2. Ordenacin:
- Mtodo de la burbuja.
- Mtodo de insercin.
- Mtodo de seleccin.
- Mtodo de Quick Short.
3. Bsqueda:
- Bsqueda secuencial.
- Bsqueda binaria.
- Bsqueda por conversin de claves o Hashing.
4. Intercalacin.

1. Introduccin:

A la hora de tratar datos, muchas veces nos conviene que estn ordenados. Estos mtodos nos
pueden resultar eficientes cuando hacemos las bsquedas o deseamos ordenarlos de acuerdo
a diversos criterios.

2. Ordenacin:
38

Consiste en organizar un conjunto de datos en un orden determinado segn un criterio.
La ordenacin puede ser interna o externa:

Internos:
- Insercin directa.
o Insercin directa.
o Insercin binaria.
- Seleccin directa.
o Seleccin directa.
- Intercambio directo.
o Burbuja.
o Shake.
- Insercin disminucin incremental.
o Shell.
- Ordenamiento de rbol.
o Heap.
o Tournament.
- Sort particionado.
o Quick sort.
- Merge sort.
- Radix sort.
- Clculo de direccin.

Externos:
- Straight merging.
- Natural merging.
- Balanced multiway merging.
- Polyphase sort.
- Distribution of initial runs.
- Interna: La hacemos en memoria con arrays. Es muy rpida.
- Externa: La hacemos en dispositivos de almacenamiento externo con ficheros.
-
Para determinar lo bueno que es un algoritmo de ordenacin hay que ver la complejidad del
algoritmo (cantidad de trabajo de ese algoritmo), se mide en el nmero de operaciones bsicas
que realiza un algoritmo. La operacin bsica de un algoritmo es la operacin fundamental, que
es la comparacin.

Mtodo de la burbuja:
39

El bubble sort, tambin conocido como ordenamiento burbuja ,la filosofa de este mtodo es ir
comparando los elementos del array de 2 en 2 y si no estn colocados correctamente
intercambiarlos, as hasta que tengamos el array ordenado.

Hay que comparar la posicin 1 y la 2 y si no estn ordenadas las intercambio. Luego la 2 y la 3 y
as sucesivamente hasta que comparo las ltimas posiciones.

Con esta primera pasada lograremos que quede ordenado el ltimo elemento del array.
Tericamente, en cada pasada iremos colocando un elemento, y tendramos que hacer n 1
pasadas. Si en una pasada no se hacen cambios, el array ya est ordenado.

Procedimiento Bubble Sort
1:[Inicializa i al final de arreglo] For i = N down to 1 do
2:[Inicia desde la segunda pos.] For j = 2 to i do
4:[Si a[j-1] es mayor que el que le sigue] If a[j-1] = a[j] then
5: [Los intercambia] Swap(a, j-1, j).
6: [Fin] End.

Procedimiento burbuja (datos: array [1..N] de <tipo>)
Var
Ordenado: booleano
I, J: entero
Aux : <tipo>
Inicio
Ordenado = falso
I = 1
Mientras (ordenado = falso) y (i <> n 1)
Ordenado = verdadero
J= I
Desde j = 1 hasta n 1
Si datos [j] > datos [j + 1]
Entonces aux = datos [j]
Datos [j] = datos [j + 1]
Datos [j] = aux
Ordenado = falso
Fin si
Fin desde
I = I + 1
Fin mientras
Fin
40


Mtodo de insercin:
Se supone que se tiene un segmento inicial del arreglo ordenado, y hay que ir aumentando la
longitud de segmento hasta que coincide con la longitud del arreglo.

Para ello insertaremos el siguiente elemento en el lugar adecuado dentro del segmento
ordenado. Esto se hace moviendo cada elemento del segmento ordenado a la derecha hasta que
se encuentre uno menor o igual al elemento que queremos colocar en el segmento o hasta que
no tenemos elementos, y lo coloco en esa posicin.

Para arrancar este mtodo se parte de que el segmento ordenado inicial este es la primera
posicin.

Procedimiento insercion (datos: array [1..N] de <tipo>)
Var: I, J: entero
Aux: <tipo>
Inicio
Desde i = 2 hasta N
Aux = datos [i]
J = i 1
Mientras (j > 0) y (aux < datos[j])
Datos[j + 1] = datos[j]
J = j 1
Fin mientras
Datos [j + 1] = aux
Fin desde
Fin

Mtodo de la seleccin:
Se trata de buscar el elemento ms pequeo y colocarlo en la primera posicin, despus el
segundo ms pequeo y colocarlo en la segunda posicin, y as sucesivamente hasta que el
arreglo este ordenado.

Para ello vamos a recorrer el array, y por cada elemento buscamos a la derecha de esa posicin
cual es el ms pequeo, y lo intercambio con el elemento que estoy examinando.

Procedimiento selecccion (datos: array[1..N] de <tipo>)
Var
I,j,pos: entero
Aux: <tipo>
41

Inicio
Desde i = 1 hasta N-1
Aux = datos[i]
Pos = i
Desde j = i+1 hasta N
Si datos[j] < aux
Entonces pos = j
Aux = datos[j]
Fin si
Fin desde
Datos[pos] = datos[i]
Datos[i] = aux
Fin desde
Fin

Mtodo de ordenacin rpida o QuickShort:

Consiste en dividir la lista inicial en otras dos que ordenamos por separado recursivamente. Para
ello, se elige un elemento de la lista al que llamamos pivote, tal que a la derecha del pivote va a
quedar lo ms grande, y a la izquierda lo ms pequeo, es decir, que el pivote quedar colocado
en su posicin.

Procedimiento QuickShort (ini: entero; fin: entero; datos: array[1..N] de <tipo>)
Inicio
Si ini < fin
Entonces sublistas (ini,fin,pivote,datos)
Quickshort (ini,pivote-1,datos)
Quickshort (pivote+1,fin,datos)
Fin si
Fin

Procedimiento sublistas (ini:entero;fin:entero;ent-sal pivote:entero;
datos:array[1..N]de <tipo>)
Inicio
Pivote = ini
Aux = datos[ini]
Desde i = pivote+1 hasta fin
Si datos[i] < aux
Entonces pivote = pivote + 1
Aux2 = datos[i]
42

Datos[i] = datos[pivote]
Datos[pivote] = aux2
Fin si
Fin desde
Datos[ini] = datos[pivote]
Datos[pivote] = aux
Fin

3. Bsquedas:
Hay 2 tipos de bsquedas, internas que se hacen en memoria y externas que se hacen en
ficheros. Cuando buscamos en un fichero, normalmente lo hacemos a travs de una clave. Dado
un determinado valor, se trata de ver si existe un elemento con ese valor en el array de ficheros
donde se busca, tal que se devuelve si est o no.

Existen 3 mtodos de bsqueda:
- Secuencial.
- Binaria o dicotmica.
- Por transformacin de claves o Hashing.
-
Bsqueda secuencial:
Se puede aplicar para bsquedas internas y externas, y hay que ir pasando secuencialmente por
todos los elementos de la estructura hasta encontrar el elemento o acabar la lista.

Procedimiento b_secuencial (datos: array[1..N] de <tipo>; elem: <tipo>)
Var I: entero
Inicio
I = 1
Mientras (i <= N) y (datos[i] <> elem)
I = I + 1
Fin mientras
Si datos[i] = elem
Entonces escribir Elemento encontrado en la posicini
Sino escribir Elemento no encontrado
Fin si
Fin

Bsqueda secuencial con centinela:
Se trata de optimizar en cierto modo la bsqueda secuencial normal, lo que hacemos es aadir
al final del arreglo el elemento que quiero buscar por lo que siempre lo encontrare.

43

Si encuentro el elemento en una posicin distinta de N+1 significa que no est en la estructura.
La ventaja es que en la condicin del mientras no tengo que preguntar si se acaba la estructura,
me ahorro una condicin, el inconveniente es que tiene que sobrar espacio al final del array.

Procedimiento b_sec_centineal (datos: array[1..N+1] de <tipo>; elem: <tipo>)
Var: I: entero
Inicio
Datos[n+1] = elem
I = 1
Mientras datos[i] <> elem
I = i+1
Fin mientras
Si i <> n+1
Entonces escribir Elemento encontrado en la posicini
Sino escribir Elemento no encontrado
Fin si
Fin

Bsqueda binaria o dicotmica:
Nota: Para que se pueda aplicar es que la lista en la que queremos buscar el elemento este
previamente ordenada.

Se trata de dividir el espacio de bsqueda en sucesivas mitades hasta encontrar el elemento
buscado o hasta que ya no pueda hacer ms mitades.

Primero hallamos el ndice de la mitad del array y miramos si el elemento coincide con l, sino
coincide averiguamos donde debera estar el elemento buscado, si en la lista de la derecha o de
la izquierda, y dentro de esa mitad hago lo mismo sucesivamente.

Procedimiento b_binaria (datos:array [1..N] de <tipo>; elem:<tipo>; ini:entero;
fin: entero)
Var: mit: entero
Inicio
mit = (ini+fin) div 2
mientras (ini < fin) y (elem <> datos[mit])
si elem < datos[mit]
entonces fin = mit 1
sino ini = mit + 1
fin si
fin mientras
44

si ini < fin
entonces escribir Elemento encontrado en la posicin mit
sino escribir Elemento no encontrado
fin si
fin

Bsqueda por transformacin de claves o Hashing:

Es necesario que lo que se busque sea por un determinado campo clave. Se trata de convertir
ese campo clave en una direccin real, si estamos en un array, en un posicin del array y si
estamos en un fichero, en un registro del fichero.

Lo que hace que se convierta la clave en una direccin real es la funcin de direccionamiento.
Existen diferentes tipos de funciones de direccionamiento:

La ms usada es la funcin mdulo, que consiste en dividir la clave entre el nmero de elementos
mximos de la estructura y coger el resto como direccin real de almacenamiento (el ndice si es
un array, o una direccin relativa si es un fichero).

Entruncamiento: Es la parte de la clave como ndice.

Plegamiento: Dividir la clave en partes iguales de tamao, que va a ser igual al nmero de
cifras del tamao del array, luego sumarlas y coger las ltimas cifras de la suma.

Mitad del cuadrado: Es el cuadrado de la clave y despus coger las cifras centrales.

El problema de estos casos, es que cuando el rango de claves es mayor que el nmero de
posiciones de la estructura, est el problema de que a diferentes claves les corresponde la misma
posicin, as que cuando se produce el segundo sinnimo hay que ver donde se manda.

Para evitar esto, tratar que la funcin de direccionamiento produzca el menor nmero de
colisiones posibles.

Para solucionar el problema de los sinnimos:

- Dejar tanto espacio como rango de claves. Es ilgico.
- Si se trata de un array, que por cada posicin dejemos una posicin ms.
- La mejor solucin es la tcnica de encadenamiento, que consiste en que de cada posicin
del array salga un puntero a una lista enlazada que enlace a todos los elementos que
deberan ir posicionados en esa posicin o ndice del array.
45


4.- fusin por Intercalacin:
Consiste en juntar varias listas ordenadas en una sola lista que quede ordenada.

Procedimiento fusion (a1: T1; a2: T2; a3: T3)
Var
I,j,k,l: entero
Inicio
I = 1 : J = 1 : K = 1
Mientras (i <= n) y (j <= m)
Si a1[i] < a2[j]
Entonces a3[k] = a1[i]
I = I + 1
Sino a3[k] = a2[j]
J = J + 1
Fin si
K = K + 1
Fin mientras
Si i < n
Entonces desde L=i hasta m
K = k +1
A3[k] = a2[l]
Fin desde
Sino desde L=j hasta n
K = k+1
A3[k] = a1[l]
Fin desde
Fin si
Fin

ORDENACIN, BSQUEDA Y FUSIN EXTERNA DE ARCHIVOS:
1. Archivos ordenados.
2. Fusin o mezcla de archivos ordenados.
3. Particin de archivos.
4. Clasificacin de archivos.

1. Archivos ordenados:

Un archivo se puede ordenar por un campo o un conjunto de campos. La mayor parte de los
sistemas disponen de una funcin SORT para ordenar.
46

2. Fusin o mezcla de archivos ordenados:

Dados 2 archivos A y B que tienen la misma estructura y clasificados por el mismo campo o
campos, se trata de obtener otro archivo C que tenga la misma estructura de los 2 anteriores y
que tambin queda clasificado por el mismo criterio.

Procedimiento fusion (A: t_fich; B: t_fich; C: t_fich)
Var: R1, r2: <tipo>
Inicio
Abrir (C,fich.sal,salida)
Abrir (A,fich1,entrada)
Abrir (B,fich2,entrada)
Leer (A,r1)
Leer (B,r2)
Mientras no eof (A) y no eof (B)
Si r1.info < r2.info
Entonces escribir (C,r1)
Leer (A,r1)
Sino escribir (C,r2)
Leer (B,r2)
Fin si
Fin mientras
Si eof (A)
Entonces leer (B,r2)
mientras no eof (B)
Escribir (C,r2)
Leer (B,r2)
Fin mientras
Sino leer (A,r1)
mientras no eof (A)
Escribir (C,r1)
Leer (A,r1)
Fin mientras
Fin si
Cerrar (A)
Cerrar (B)
Cerrar (C)
Fin


47

3. Particin de archivos:
Se trata de dividir un archivo en varios. Hay diferentes criterios de particin:

Particin por contenido:
Se reparten los registros entre varios registros segn el valor de uno o ms campos.
< V1 se asigna a F1
= V1 se asigna a F2
> V1 se asigna a F3

Procedimiento part_cont (fich: t_fich; ent-sal fich1, fich2, fich3: t_fich)
Var
R: <tipo>
Inicio
Abrir (fich,F,entrada)
Abrir (fich1,F1,salida)
Abrir (fich2,F2,salida)
Abrir (fich3,F3,salida)
Leer (fich,r)
Mientras no eof (fich)
Si r.info < V1
Entonces escribir (f1,r)
Sino si r.info > V1
Entonces escribir (f3,r)
Sino escribir (f2,r)
Fin si
Fin si
Leer (fich,r)
Fin mientras
Cerrar (fich)
Cerrar (f1)
Cerrar (f2)
Cerrar (f3)
Fin

Particin por nmero fijo de registros o por secuencias con clasificacin interna:

Se trata de obtener a partir de un fichero varios, tal que todos tengan un nmero fijo de registros
excepto el ltimo. Si el fichero inicial tiene X registros y quiero obtener como resultado Y
ficheros, cada fichero tendr X/Y registros.

48

Se trata de ir leyendo secuencias de X/Y registros del fichero F y se vuelcan a un array, clasificar
esas secuencias internamente, y cuando estn clasificadas, las vuelco a otro fichero.

El problema es que se usa arrays para la ordenacin interna, y a veces el nmero de ficheros
dependen del tamao mximo del array.

F: 3 9 5 14 2 30 1
F1: 3 5 9
F2: 2 14 30
F3: 1

Particin por secuencias sin clasificacin interna:

Se trata de obtener ficheros a partir de uno dado, todos con el mismo tamao, pero los ficheros
no tienen por qu estar clasificados.

Nosotros marcamos el tamao del bloque donde vaya a clasificar la informacin. Determino
tambin el nmero mximo de ficheros que quiero tener.

Leer secuencias de N registros del fichero inicial y los ir grabando en los ficheros resultantes
de la particin.

4. Clasificacin de archivos:

Es obligatorio que exista una clave. Si el fichero fuese pequeo se llevan todos los registros a un
array y los clasifico, pero esto no es lo ms usual, por lo que se usa la clasificacin externa.

Clasificacin por mezcla directa:

Vamos a usar 2 ficheros auxiliares F1 y F2. El fichero F lo organizamos grabando en F secuencias
de registros ordenados cada vez ms grandes.

Primero leemos las secuencias de un registro de F y las grabo alternativamente en F1 y F2.

Luego leo las secuencias de un registro, una de F1 y otra de F2, y las grabo ordenadas en F.
Vuelvo a leer en F con el doble de secuencia que antes y los grabo en F1 y F2, y repetimos todas
las fases duplicando en cada pasada el tamao de la secuencia hasta que el tamao obtenido
sea igual que el del fichero. A cada tratamiento de F se le llama pasada, y el nmero de pasadas
mximo, ser I, tal que el tratamiento se repetir hasta que 2 elevado a I >= nmero de registros.

49

En cada pasada para clasificar la secuencia que leemos de F1 y F2, utilizamos el mtodo de fusin
externa.

F: 3 9 5 14 2 30 1 12 10
F1: 3 / 5 / 2 / 1 / 10
F2: 9 / 14 / 30 / 12

F: 3 9 5 14 2 30 1 12 10
F1: 3 9 / 2 30 / 10
F2: 5 14 /1 12

F: 3 5 9 14 1 2 12 30 10
F1: 3 5 9 14 / 10
F2: 1 2 12 30
F: 1 2 3 5 9 12 14 30 / 10
F1: 1 2 3 5 9 12 14 30
F2: 10
F: 1 2 3 5 9 10 12 14 30

Clasificacin por mezclas de secuencias equivalentes:

Se parece al mtodo anterior porque tambin se intenta coger secuencias de registros ms
grandes, pero ahora usamos 4 ficheros auxiliares y en vez de empezar leyendo secuencias de un
registro, hacemos secuencias de N registros, que la primera vez clasificamos internamente, por
lo que el valor de N vendr limitado por el tamao del array.

Primero leemos del archivo inicial F secuencias de N registros que clasificamos internamente y
que grabamos alternativamente en F1 y F2.

Despus leo secuencias de N registros de F1 y F2 alternativamente, y por cada par de secuencias
ledas las fusiono y las grabo alternativamente ya ordenadas en F3 y F4.

Las secuencias de 2N registros de F3 y F4 las fusiono y la secuencia 4N obtenida ya ordenada la
grabo alternativamente en F1 y F2.

Repito esto hasta que todos los ficheros estn vacos menos 1, y la informacin de ese fichero la
grabo al fichero inicial.

F: 3 9 5 14 2 30 1 12 10
F1: 3 5 9 / 1 10 12
50

F2: 2 14 30

F1: Vacio
F2: Vacio
F3: 2 3 5 9 14 30
F4: 1 10 12
F1: 1 2 3 5 9 12 14 30 Vuelco F1 al fichero inicial F.
F2: Vacio
F3: Vacio
F4: Vacio
51

ESTRUCTURAS DINMICAS LINEALES DE DATOS:
LISTAS ENLAZADAS

1. Introduccin a las estructuras dinmicas de datos.
2. Listas.
3. Listas enlazadas.
4. Procesamiento de listas enlazadas simples.
5. Listas circulares con cabecera.
6. Listas doblemente enlazadas.

1. Introduccin a las estructuras dinmicas de datos:
Las ventajas de las estructuras dinmicas de datos son:

No hay que definir el tamao antes de usarla, sino que se utiliza segn se necesita

Los elementos que forman esta estructura no estn situados en forma contigua en memoria, y
esos elementos se relacionan entre s mediante campos enlace o puntero, y a cada uno de esos
elementos lo llamamos nodo de la estructura.

Un puntero es un dato cuyo contenido es una direccin de memoria que es en la que est
almacenado el dato al que apunta.










Las estructuras dinmicas pueden ser lineales o no lineales segn que desde un elemento se
pueda acceder solamente a otro o a varios.

Declaracin de los punteros en distintos lenguajes:

En C: <tipo> *<var_p>
Int *p
En Pascal: <var_tipo_puntero>: ^<tipo>
P: ^integer
52

En pseudocdigo: <var_tipo_puntero>: puntero a <tipo>
P: puntero a entero

Acceder a un campo de un registro:

En C: P nombre
En Pascal: p^.nombre
En pseudocdigo: p nombre

2. Listas: TDA Tipos de Datos abstractos

Una lista es una estructura de datos de elementos.

Hay 2 formas de almacenarla. Con arreglos (usando memoria esttica), en donde la relacin de
los elementos de la lista viene dada porque ocupa posiciones contiguas de memoria.

De forma enlazada con memoria dinmica. Se conoce como listas enlazadas, y la relacin entre
los elementos de la lista se mantiene mediante campos de enlace o punteros, estos sealan a la
posicin del siguiente elemento

3. Listas enlazadas:

Es una coleccin lineal de elementos llamados NODOS, donde el orden entre los nodos se
establece mediante punteros, y por ser simple, adems desde un nodo solo puedo acceder al
siguiente directamente.

Una lista enlazada tiene 2 partes:

Los nodos que forman la lista. Cada nodo va a tener dos campos. Uno de informacin que ser
del tipo de los elementos que contiene la lista y un campo de enlace que es de tipo puntero, y
que contendr la direccin de memoria en la que est almacenado el siguiente nodo.

Al primer campo de informacin lo llamamos INFO, y el nodo lo llamamos SIG.

La segunda parte de la lista ser una variable de tipo puntero a los nodos de la lista que contiene
la direccin del primer nodo de la lista. Por esa razn a esa variable la podemos llamar Comienzo.

Tipo nodo: registro
Info: <tipo>
Sig: puntero a nodo
53

Fin registro
Var
Com: puntero a nodo

El ltimo nodo de la lista tendr en su campo de enlace el valor nodo (Null,Nil), que quiere decir
que no apunta a ninguna direccin y grficamente se simboliza con:



Ejemplo:





Tipo nodo: registro
Info: carcter
Sig: puntero a nodo
Fin registro
Los nodos de la lista pueden estar en cualquier zona de memoria, no tienen que estar en
posiciones consecutivas.

Tratamiento de la memoria dinmica:

Siempre que se hace una insercin en una estructura dinmica, tenemos que tomar de memoria
tantos bytes de memoria dinmica como ocupa el nodo de la estructura dinmica, y cuando
borramos un elemento, tendremos que liberar la memoria ocupada por ese elemento. Para
conseguir este manejo, todos los lenguajes de programacin tienen 2 instrucciones que
permiten reservar memoria y liberar memoria dinmica, y asignar en el caso de la reserva la
memoria a un puntero, y en el caso de la liberacin se libera la memoria asignada a un puntero.

La instruccin de reserva de memoria llevara un nico argumento, que ser el tipo de datos para
el que se hace la reserva de memoria, y segn el tamao de ese tipo, esa instruccin sabr el
nmero de bytes que tiene que reservar. Y lo que devuelve es un puntero al comienzo de la zona
que se ha reservado. Este valor devuelto ser el que tenemos que asignar a un puntero al tipo
de datos para el que se hace la reserva.

La funcin liberar memoria lleva un nico argumento que es el tipo puntero, y lo que hace es
liberar la memoria asignada a ese puntero, para lo cual es imprescindible que a ese puntero
previamente se le haya hecho una asignacin de memoria dinmica con la funcin de reserva.
54


Var p: puntero a <tipo>
P = res_mem (<tipo>)
Lib_mem (<var_puntero>)

Representacin de listas enlazadas en memoria con arreglos

Sea LISTA una lista enlazada, salvo que se indique lo contrario, LISTA estar compuesta por dos
arreglos lineales, a los que llamaremos INFO y ENLACE, de tal forma que INFO(K) y ENLACE(K)
contienen la parte de informacin y el campo puntero de cada nodo.

Una variable especial COMIENZO contiene la posicin ocupada por el primer elemento de la lista,
y una marca especial NULO indica el final de la misma, como los ndices de los arreglos INFO y
ENLACE sern por lo general positivos , el valor NULO ser cero, salvo se diga lo contrario.

Overflow y Underflow:

La memoria del ordenador tiene un tamao limitado, por lo que la memoria dinmica
(representada por los arreglos) tambin tendr un tamao limitado, es decir, que puede ser que
se nos agote; Esta situacin, se conoce como OVERFLOW, cuando la lista est llena y ya no hay
espacio disponible

Siempre que se haga una instruccin de reserva de memoria, tendremos que comprobar antes
si nos queda memoria libre. Eso en cualquier lenguaje ocurre cuando la instruccin de reservar
de memoria devuelve el valor NULO, esto lo controlamos por medio de una variable DISP que
indicara si hay espacio o no en la lista.

Si DISP = NULO, Entonces escribir: No hay memoria

Igual se hace para borrar un elemento de una estructura dinmica, para borrarlo, esa estructura
tiene que tener al menos un elemento. Si no lo tiene e intentamos borrarlo, se produce un
UNDERFLOW. Por esto, lo primero que tenemos que probar en una estructura dinmica, es
preguntar si tiene algo.

Si COMIENZO = NULO, Entonces escribir: Lista Vaca

Si slo manejo una estructura dinmica, pregunto por DISP (variable que indica los nodos
disponibles), si trabajo con varias estructuras dinmicas cada una de un tipo, habr tantas DISP
como estructuras dinmicas.

55

4. Procesamiento de listas enlazadas simples:

Para poder procesar una lista, se necesita la estructura de sus nodos y la variable de comienzo.

Operaciones bsicas (que pueden estar en funciones, en una clase):

ListaVacia(L) Inicializa la lista
EsVacia(L) Determina si la lista esta vaca
InsertaInicio(X,L) Inserta un nodo con la informacin X como primer elemento de L.
InsertaNodo(X,P,L) Inserta un nodo con el campo X, delante del nodo de direccin P.
Insertafin(X,L) Inserta un nodo con el campo X, al final de la lista L.
Localiza(X,L) Devuelve la posicin /direccin donde esta el campo X, si no esta
Devuelve nulo
EliminaInicio(X,L) Elimina el primer nodo de la lista
Elimina(X,L) Elimina de la lista el nodo que contiene a X
EliminaFin(X,L) Elimina el ultimo nodo de la lista L.
AnteriorNodo(P,L) Devuelve la posicin/direccin del nodo anterior
SiguienteNodo(P,L) Devuelve la posicin/direccin del nodo siguente.
PrimerNodo(P,L) Devuelve la posicin/direccin del primer nodo
UltimoNodo(P,L) Devuelve la posicin/direccin del ultimo nodo
EliminarLista(L) Devuelve vacia la lista L.
VerList(L) Visualiza el campo de informacin de toda la lista

La forma ms normal de representar listas enlazadas es usar memoria dinmica. Una lista
enlazada tambin se puede simular usando arreglos (memoria esttica), pero es poco eficiente.
Para ello utilizara 2 arreglos del mismo tamao y con la misma numeracin de ndices, tal que
en un arreglo guardara los campos de informacin de la lista, y para cada campo de informacin
en la posicin correspondiente en el otro arreglo guardara el ndice del siguiente elemento a
ese nodo.

Es decir en ese segundo arreglo guardara los campos enlace mediante valores de ndice.



a h . i z

Adems de los 2 arreglos, tengo que tener una variable que contenga el ndice del primer
elemento de la lista. El ltimo elemento, tiene en el campo de enlace el valor 0.

56

Algoritmos de listas enlazadas

Recorrido de una lista enlazada:
Consiste en pasar por todos sus nodos y procesarlos.

Algoritmo 1.- (Recorrido de una lista enlazada) Sea LISTA (INFO y ENLACE) una lista enlazada
que almacenamos en memoria. El algoritmo recorre LISTA realizando la operacin PROCESO
a cada elemento de LISTA La variable PTR apunta a cada momento al nodo que se est
tratando.

RECORRE(INFO,ENLACE,COMIENZO)
1 PTR = COMIENZO Inicializa el puntero
2 Repetir pasos 3 y 4 mientras PTR <> 0
3 Aplicar PROCESO a INFO[PTR]
4 PTR = ENLACE[PTR] PTR apunta ahora al siguiente nodo
Fin de del ciclo mientras
5 Terminar

Bsqueda de un nodo:
Se trata de localizar un nodo que cumpla una determinada condicin (por ejemplo que su campo
de informacin valga un valor determinado).

A la hora de hacer las bsquedas tendremos en cuenta si la lista est ordenada o no, y si est
ordenada por el criterio de bsqueda tendr que aprovecharlo.

Algoritmo 2 (Bsqueda en una lista enlazada) Sea LISTA (INFO y ENLACE) una lista enlazada
que almacenamos en memoria. Sea ELEMENTO el dato a buscar en la lista, LUG la posicin
donde se encuentra el elemento. El algoritmo encuentra la posicin LUG del nodo donde
ELEMENTO aparece por primera vez en lista o devuelve LUG = NULO.

BUSQ(INFO,ENLACE,COMIENZO,ELEMENTO,LUG)
1 PTR = COMIENZO Inicializa el puntero
2 Repetir pasos 3 mientras PTR <> NULO
3 Si ELEMENTO = INFO[PTR], entonces
LUG = PTR y salir
Si no
PTR = ENLACE[PTR] PTR apunta ahora al nodo siguiente
Fin de si
Fin de mientras
57

4 LUG = NULO La bsqueda es fallida
5 Terminar

Insercin de un nodo
En los algoritmos de insercin se presentan algunas situaciones que analizaremos con ms
detalle:

Algoritmo 3 (Insercin en una lista enlazada al comienzo) Sea LISTA (INFO y ENLACE) una lista
enlazada que almacenamos en memoria. Sea ELEMENTO el dato a insertar en la lista. Sea DISP
una lista de elementos disponibles

INSPR(INFO, ENLACE, COMIENZO, DISP, ELEMENTO)
1.- Overflow? Si DISP = NULO , entonces escribir OVERFLOW y salir
2.- Extrae el primer nodo de la lista DISP
NUEVO = DISP
DISP = ENLACE(DISP)
3.- INFO(NUEVO) = ELEMENTO Copia le datos en el nodo
4.- ENLACE(NUEVO) = COMIENZO El nuevo nodo apunta ahora al que ocupaba
antes la primera posicin
5.- COMIENZO = NUEVO COMIEZO apunta ahora al elemento que ocupa la primera
posicin de la listas
6.- Salir

Algoritmo 4 (Insercin a continuacin de un nodo determinado)
INSLUG(INFOR, ENLACE,COMIENZO,DISP, LUG, ELEMENTO) Sea LISTA (INFO y ENLACE) una lista
enlazada que almacenamos en memoria. El algoritmo inserta ELEMENTO a continuacin del
nodo que ocupa la posicin LUG o coloca ELEMENTO como primer nodo si LUG = NULO.

1 Overflow? Si DISP = NULO , entonces escribir OVERFLOW y salir
2 Extrae el primer nodo de la lista DISP
NUEVO = DISP
DISP = ENLACE(DISP)
3.- INFO(NUEVO) = ELEMENTO Copia el datos en el nodo obtenido
4.- Si LUG = NULO entonces, lo inserta como primer nodo
ENLACE[NUEVO] = COMIENZO
COMIENZO = NUEVO
Si no, Inserta detrs de nodo de posicin LUG
ENLACE[NUEVO] = ENLACE[LUG]
ENLACE[LUG] = NUEVO
Fin de si
58

3 Salir
Algoritmo insercin en una lista enlazada ordenada
En este caso debemos de realizar dos procedimientos, el primero que nos permita ubicarnos en
la posicin que cumpla con el orden de la informacin del nodo a insertar, y la segunda con la
insercin propia del

Algoritmo 5. (Encuentra la posicin del nodo donde se insertara el nuevo elemento)
ENCUPOS(INFO, ENLACE, COMIENZO, ELEMENTO, LUG) Sea LISTA (INFO y ENLACE) una lista
enlazada que almacenamos en memoria.El procedimiento encuentra la posicin LUG del
ltimo nodo, que cumple INFO(LUG) < ELEMENTO o hace que LUG = 0

1.- Lista vacia? Si COMIENZO = NULO, entonces LUG = NULO y retornar
2.- Caso especial? Si ELEMENTO < INFO(COMIENZO), entonces
LUG = NULO y retornar
3.- AUX = COMIENZO y PTR = ENLACE(COMIENZO) Inicializamos los punteros
4.- Repetir pasos 5 y 6 mientras PTR<> NULO
5.- Si ELEMENTO < INFO(PTR), entonces
LUG = AUX y retornar
Final de la estrcutura condicional
6.- AUX = PTR y PTR =ENLACE(PTR) Actualiza los punteros
Final del ciclo del paso 4
7.- LUG = AUX
8.- Retornar

Ahora podemos aplicar el procedimiento para agregar el algoritmo que inserte el ELEMENTO en
la lista enlazada

Algoritmo 6 INSERLISTAORDENADA(INFO, ENLACE, COMIENZO, DISP, ELEMENTO) Sea LISTA
(INFO y ENLACE) una lista enlazada que almacenamos en memoria.El algoritmo inserta
ELEMENTO en una lista enlazada ordenada
1.- Utilizamos el procedimiento del algoritmo 5 para encontrar la posicin del nodo que
preceder a ELEMENTO.
Llamar ENCUPOS(INFO, ENLACE, COMIENZO, ELEMENTO, LUG)
2.- Utilizamos el algoritmo 4 para insertar ELEMENTO a continuacin del nodo que ocupa la
posicin LUG
Llamar INSLUG(INFOR, ENLACE,COMIENZO,DISP, LUG, ELEMENTO)
3.- Salir
Eliminacin de un nodo de una lista enlazada:

59

Algoritmo 7 (Eliminacin de un nodo sucesor de uno determinado)
ELIMINANODO(INFO, ENLACE, COMIENZO,DISP,LUG,LUGP) Sea LISTA (INFO y ENLACE) una
lista enlazada que almacenamos en memoria. El algoritmo elimina de la lista el nodo N que
ocupa la posicin LUG, siendo LUGP la posicin del nodo que precede a N o bien LUGP = 0 si N
es el primero de la lista.

1 Si LUGP= NULO entonces,
COMIENZO = ENLACE[COMIENZO], Elimina el primer nodo
Si no
ENLACE[LUGP] = ENLACE[LUG], Elimina el nodo N
Fin de Si
2 ENLACE[LUG] = DISP Devolvemos el nodo a la lista DISP
DISP = LUG
3 Salir

Algoritmo 8 (Eliminacin de un nodo que contiene un determinado elemento de informacin)
ELIMINA_NODO_INFO(INFO, ENLACE, COMIENZO,ELEMENTO,LUG,LUGP) Sea LISTA (INFO y
ENLACE) una lista enlazada que almacenamos en memoria. El procedimiento encuentra la
posicin LUG del primer nodo N que contiene a ELEMENTO y la posicin LUGP del nodo
anterior a N . Si ELEMENTO no se encuentra en la lista, el procedimiento devuelve LUG = NULO
y si ELEMENTO se encuentra en el primer nodo, entonces hace LUG = NULO.

1 Lista vacia? Si COMIENZO = NULO , entonces
LUG = NULO
LUGP = NULO
Salir
Fin de si
2 Se encuentra el elemento en el primer nodo ?
Si INFO[COMIENZO] = ELEMENTO, entonces
LUG = COMIENZO
LUGP = NULO
Salir
Fin de si
3 AUX = COMIENZO
PTR = ENLACE[COMIENZO] Inicializamos los punteros
4 Repetir pasos 5 y 6 mientras PTR <> NULO
5 Si INFO[PTR] = ELEMENTO, entonces
LUG = PTR
LUGP = AUX
Salir
60

Fin de si
6 AUX = PTR
PTR = ENLACE[PTR] Actualizamos los punteros
Fin de ciclo mientras
7 LUG = NULO Bsqueda fallida
8 Salir
Algoritmo 9 (Eliminar la informacin del elemento usando el algoritmo anterior)
ELIMINAR(INFO, ENLACE, COMIENZO,DISP,ELEMENTO) Sea LISTA (INFO y ENLACE) una lista
enlazada que almacenamos en memoria. Llamar al procedimiento anterior (algoritmo 8, para
encontrar la posicin de N)

Llamar ELIMINANODOINFO(INFO, ENLACE, COMIENZO,ELEMENTO,LUG,LUGP)
1 Si LUG = NULO entonces
Escribir ELEMENTO no se encuentra en la lista
Salir
Fin de si
3 Si LUGP = NULO entonces Eliminamos el nodo
COMIENZO = ENLACE[COMIENZO] Eliminamos el primer nodo
Si no
ENLACE[LUGP] = ENLACE[LUG]
Fin de si
4 Devolvemos el nodo eliminado a la lista de nodos disponibles
ENLACE[LUG] = DISP
DISP = LUG
9 Salir


5. Listas con cabecera:

Una lista con cabecera, en general es una lista enlazada simple normal, pero en la que el primer
nodo es un nodo especial que no sirve para guardar informacin vlida, sino solamente para
marcar que es el primer nodo.





61

Cabecera

Hay dos tipos de listas enlazadas con cabecera:

Listas enlazadas con cabecera y tierra: El primer nodo va a ser la cabecera, y el ltimo apunta
a nulo. No se utiliza porque perdemos un nodo y no tienen ventajas.

Listas circulares con cabecera: Se caracterizan porque tienen un nodo cabecera, y adems el
ltimo nodo apunta al nodo cabecera.






En cualquier lista enlazada con cabecera el primer nodo con informacin til es el siguiente a
comienzo (Comsig).

En una lista circular con cabecera, la ventaja que presenta respecto a una normal, es que en las
inserciones y borrados no hay que suponer ningn caso especial, pues todos los nodos, incluido
el primero til, tienen un predecesor.

Al recorrer la lista completa, empezaremos buscando la informacin por el siguiente a comienzo,
y sabemos que hemos llegado al final de la lista cuando el siguiente al puntero que recorre la
lista sea comienzo.

Algoritmo 10 RECORRE_LCIR()
Sea LISTA, una lista circular con cabecera en memoria, el algoritmo recorre LISTA aplicando la
operacin PROCESO a cada nodo de la lista
1.- PTR = ENLACE(COMIENZO) Inicializamos el puntero PTR
2.- Repetir pasos 3 y 4 mientras PTR<> COMIENZO
3.- Aplicar PROCESO a INFO(PTR)
4.- PTR = ENLACE(PTR) `PTR apunta ahora al siguiente nodo
Final de ciclo
5.- Salir

Bsqueda de un nodo en una lista circular con cabecera

62

Algoritmo 11 BuscaListaCircu(INFO, ENLACE, COMIENZO, ELEMENTO, LUG) LISTA es una
lista circular con cabecera. El algoritmo encuentra la posicin LUG que ocupa el primer nodo
de la misma en que el ELEMENTO aparece por primera vez o devuelve LUG = NULO

1.- PTR = ENLACE(COMIENZO)
2.- Repetir mientras INFO(PTR) <> ELEMENTO y PTR <> COMIENZO:
PTR = ENLACE(PTR) PTR apunta ahora al nodo siguiente
Final del ciclo
3.- Si INFO(PTR) = ELEMENTO, entonces:
LUG = PTR
Si no:
LUG = NULO
`Final de la estructura condicional
4.- Salir

El siguiente algoritmo encuentra la posicin LUG del primer nodo que contiene a ELEMENTO y
la posicin LUGP del nodo que los precede en la lista.

Algoritmo 12 BuscaPosAntLC(INFO,ENLACE,COMIENZO ELEMENTO, LUG, LUGP)
1.- AUX= COMIENZO
PTR = ENLACE(COMIENZO) Inicializa el puntero
2.- Repetir mientras INFO(PTR) <> ELEMENTO y PTR<> COMIENZO
AUX = PTR
PTR = ENLACE(PTR) Actualiza los punteros
Final del ciclo
3.- Si INFO (PTR) = ELEMENTO, entonces
LUG = PTR
LUGP = AUX
Si No
LUG = NULO
LUGP = AUX
Final de Si
4.- Salir

Elimina un nodo en una lista circular con cabecera:

Algoritmo 13 EliminarListaCircular(INFO,ENLACE ,COMIENZO, DISP, ELEMENTO)
1.- Utilizamos el procedimiento BusquedaListaCircular() para encontrar la
posicin N y su nodo predecesor
Llama BuscaPosAntLC(INFO,ENLACE,COMIENZO ELEMENTO, LUG, LUGP)
63

2.- Si LUG = NULO entonces escribir ELEMENTO no se encuentra en la lista
Salir
3.- ENLACE(LUGP) = ENLACE(LUG) Borra el nodo
4.- ENLACE(LUG) = DISP Devolvemos el nodo eliminado a la lista Disponible
DISP = LUG
5.- Salir

5.- Listas doblemente enlazadas o bidireccionales:

Las listas enlazadas simples se caracterizan porque desde un nodo solo puedo acceder al
siguiente a ese nodo, por lo que solo puedo acceder al siguiente a ese nodo, por lo que solo
puedo recorrer la lista en un sentido, de principio a fin.

Las listas dobles se caracterizan porque desde un nodo podemos acceder directamente tanto
al siguiente como al anterior a ese. Es decir, por cada nodo tendremos 2 campos enlace, uno
para enlazar un nodo con el siguiente, y otro para enlazar a un nodo con el nodo anterior a l.

De esta manera, la lista la podemos recorrer en los 2 sentidos, de principio a fin, movindonos
con el enlace al nodo siguiente o de fin a principio movindonos con el enlace al nodo anterior.
Segn esto, una lista doblemente enlazada, ser la siguiente:

Una lista doble es una coleccin lineal de elementos, llamados nodos, donde cada nodo est
dividido en tres partes:

1.- Un campo de informacin INFO que contiene el dato N
2.- Un campo puntero SIG que contiene la direccin del siguiente nodo de la lista
3.- Un campo puntero ANT que contiene la posicin del nodo anterior en la lista

Cada lista tendr 2 variables, PRIMERO y ULTIMO, del tipo puntero a nodo doble, que
contendrn respectivamente la direccin al primer y ltimo nodo de la lista.
- La estructura de cada nodo ser:
Tipo nodo_doble: registro
Info: <tipo>
Sig: puntero a nodo_doble
Ant: puntero a nodo_doble
Fin registro




64

INFO

ant sig

El campo siguiente del ltimo nodo tendr valor NIL, y el campo anterior del primer nodo
tambin tendr valor NIL, para indicar que no hay nada antes del primer nodo.














La caracterstica de una lista doblemente enlazada vaca es que el comienzo y el final son
iguales y apuntan a NIL.
Si (com = final) y (com = Nil)




Lista doblemente enlazada con un solo elemento:
Si (com = final) y (com <> Nil)







Para implementar la insercin y el borrado de una lista doblemente enlazada, vamos a suponer
que la lista de espacio disponible tiene la forma de una lista doblemente enlazada.
5.1.- Operaciones de listas enlazadas dobles:

65

Recorrido de una lista doblemente enlazada:

Para pasar por todos los nodos de la lista, podemos hacerlo igual que una lista enlazada simple,
solo que ahora la podemos recorrer la lista hacia delante con el campo SIG, y hacia atrs con el
campo ANT.

Bsqueda en una lista doblemente enlazada:

Es exactamente igual que en una lista enlazada simple, solo que ahora puedo buscar el
elemento buscado desde el comienzo y movindome con SIG o desde el final y movindome
con ANT. Si tengo una idea de por dnde va a estar el elemento, empezare por donde sea
mejor.

Insercin en una lista doblemente enlazada:

Lo primero es ver si me queda espacio disponible en memoria dinmica, si me queda, reservo
memoria para un nuevo elemento y meto la informacin que quiero en su campo de
informacin, y lo siguiente es actualizar sus campos de enlace.

Casos particulares:
- Insercin al comienzo si la lista est vaca.
- Insercin al comienzo si la lista no est vaca.
- Insercin al final.
- Insercin en medio de la lista.

Supngase que conocemos las posiciones LUGA y LUGB de dos nodos adyacentes A y B de la
lista doble y que queremos insertar ELEMENTO entre los dos, el siguiente algoritmo realiza esa
funcin:

Algoritmo INSERTALDOBLE(INFO, SIG, ANT, COMIENZO,DISP,LUGA,LUGB, ELEMENTO)
1.- Overflow? Si DISP =NULO , entonces escribir OVERFLOW
Salir
2.- NUEVO = DISP
DISP = SIG(DISP)
INFO(NUEVO) = ELEMENTO Extrae un nodo de la lista disponible y copia el
datos en el nuevo nodo
3.- Inserta el nodo en la lista
SIG(LUGA) =NUEVO
SIG(NUEVO) = LUGB
ANT(LUGB) = NUEVO
66

ANT(NUEVO) = LUGA
4.- Salir

Eliminar en una lista doblemente enlazada:

Primero hay que ver si la lista tiene algn elemento, y si tiene algn elemento, habr que
buscar si el elemento que queremos buscar existe en la lista, y si existe, busco en qu posicin
se encuentra. Casos particulares:
- Elimino el primer nodo.
- Elimino el ltimo nodo.
- Elimino cualquier nodo.

Despus de todo esto, habr que liberar la memoria del nodo.
Supngase que conocemos la posicin LUG de un nodo N de la lista enlazada doble, y
queremos eliminar el nodo N de la misma, podemos utilizar el siguiente algoritmo

Algoritmo ELIMINARLISTADOBLE(INFO,SIG,ANT,COMIENZO,DISP,LUG)
1.- Elimina el nodo
SIG(ANT(LUG)) = SIG(LUG)
ANT(SUG(LUG)) = ANT(LUG)
2.- Devuelve el nodo a DISP
SIG(lug) = DISP
DISP = LUG
3.- Salir

Aplicaciones de listas: (Escribirlas) pagina 183 Schaum
67

IV Unidad: PILAS y COLAS

Estructura de datos tipo PILAS:

Una pila es una estructura lineal de datos con la caracterstica especial de que ahora, no
podemos hacer las inserciones y las eliminaciones en cualquier lugar, sino que obligatoriamente
las tenemos que hacer por un extremo de la lista. Ese extremo lo llamamos cima de la pila.

Esto supone que se procesen los elementos de la pila en orden inverso a su entrada en la
estructura, es decir, el primer elemento de la pila que usare ser el ltimo que ha entrado (LIFO).
Con una pila podemos hacer dos operaciones bsicas, PUSH (meter) y POP (sacar).

Aparte de estas dos funciones se pueden definir otras como la de pila vaca o top, que me dice
cual es elemento que est en la cima de la pila pero sin sacarlo. Se puede implementar con
memoria esttica (arrays) o con memoria dinmica (listas enlazadas).

Si utilizo un array, tendr que definir cul es el tamao mximo del array, que ser el de la pila,
y aparte tendr definida una variable cima que tendr en cada momento el ndice que
corresponde al elemento del array que est en la cima de la pila.

PILA = arreglo [1..max_pila]
CIMA: posicin del elemento cima de la pila,
CIMA = 0 o CIMA = NULL indicara que la pila esta vaca.
MAXPILA: mximo nmero d elementos de la pila

Para sealar que la cima est vaca, cima es igual a 0 porque no tiene que apuntar a ningn
elemento.

Implementacin de una pila con arreglos:

Funcion pila_vacia (cima: entero): booleano
Inicio
Si cima = 0
Entonces retorno verdadero
Sino retorno falso
Fin si
Fin


68

Procedimiento meter_pila (PILA, CIMA, MAXPILA, ITEM)
Este procedimiento mete un ITEM en la pila (push)
Inicio
si CIMA = MAX_PILA
entonces escribir Pila llena
volver
sino
CIMA = CIMA + 1 incrementar en 1 la cima
PILA[CIMA] = ITEM insertar tem en la nueva posicion
fin si
Fin


Procedimiento sacar_pila (PILA, CIMA, TEM)
Este procedimiento elimina el elemento en la cima de la pila y lo asigna a la variable tem
(pop)
Si TOP = 0 entonces
Imprimir : subdesbordamiento
Volver
Sino
TEM = PILA(CIMA)
CIMA = CIMA -1
Fin si
Fin

Aplicaciones de las pilas:

Un ejemplo tpico de uso de pilas, es en las llamadas entre funciones. En este caso, el sistema
operativo utiliza una pila en donde va guardando la direccin de retorno de cada una de estas
llamadas.

Expresiones aritmticas: notacin polaca

Sea Q una expresin aritmtica que incluye constantes y operaciones, estos algoritmos
presentan el valor de Q utilizando la notacin inversa polaca (postfija), utilizaremos estructuras
de pilas en estos casos

Sabemos por matemticas que en las operaciones aritmticas, el smbolo operador (+, -, /, * ) se
coloca entre sus dos operandos, por ejemplo: A + B , B*C o BC, F/G ,etc., a esta notacin se le
llam notacin infija, por que podemos distinguir entre :
69

(a + b)*c a+(b*c).

La notacin polaca, se refiere a la notacin en la que el smbolo operador se colca delante de sus
dos operandos, ejemplo:

+AB, -DE /FG *EF

Si el operador est a la izquierda de los operandos se llama notacin prefija, si el operador esta
al izquierda se llama notacin postfija.

Ejemplos:

(a + b) * c = + [ab]*c = *+abc

(a + b)/(c - d) = [+ ab]/[ -cd] = /+ab-cd

El siguiente algoritmo transforma la expresin infija Q en su equivalente postfija P, el algoritmo
usa una pila para mantener temporalmente los operadores y los parntesis izquierdos, la
expresin posfija P se construir de izquierda a derecha usando los operadores de Q y de los
operadores que sean sacados de PILA, comenzamos metiendo un parntesis izquierdo en PILA y
aadiendo un parntesis derecho a l fina de Q, el algoritmo termina cuando PILA esta vaca.

Procedimiento POLACO(Q,P)
Suponemos que Q es una expresin aritmtica escrita en notacin infija, este algoritmo
encuentra la expresin postfija P equivalente.

1.- meter ( en PILA y aadir ) al final de Q
2.- Examinar Q de izquierda a derecha y repetir pasos 3 a 6 para cada elemento de Q hasta que
pila este vaca.
3.- Si se encuentra un operando aadirlo a P
4.- si se encuentra un parntesis izquierdo meterlo en pila
5.- Si se encuentra un operador (x), entonces:
(a) Repetidamente sacar de PILA y aadir a P cada operador (de lo alto de PILA)
que tenga la misma precedencia o mayor (x)
(b) aadir (x) a PILA
Fin de condicional
6.- Si se encuentra con un parntesis derecho, entonces
(a) Repetidamente sacar de PILA y aadir a P cada operador (de lo alto
De pila) hasta que se encuentre un parntesis izquierdo.
(b) eliminar el parntesis izquierdo (no aadir el parntesis izquierdo a P)
70

Fin de condicional
Fin de bucle paso 2
7.- Salir

Evaluacin de expresiones postfijas.

Supongamos que P es una expresin a aritmtica escrita en notacin postfija, el siguiente
algoritmo que usa una PILA para mantener los operandos, evala P.

Procedimiento valor_P(P)
Este algoritmo encuentra el VALOR de una expresin aritmtica P escrita en notacin postfija

1.- Aadir un parntesis derecho ) al final de P Actua como centinela
2.- Examinar P de izquierda a derecha y repetir pasos 3 y 4 para cada elementode P
Hasta que se encuentre el centinela )
3.- Si se encuentra un operador ponerlo en PILA
4.- Si se encuentra un operador (x) , entonces
(a) Sacar los dos elementos superiores de PILA, donde A sea elemento Superior y B
el
siguiente.
(b) evaluar B(x)A
(c) poner el resultado de (b) en PILA
Fin de condicional
Fin de condicional de paso 2
5.- Hacer VALOR igual al elemento superior de PILA
6.- Salir

as estructuras de pilas por se de fcil manejo se utilizan mucho en operaciones con los datos
tales como ordenamientos, bsquedas , etc.


Estructura de datos tipo COLAS:

Una cola tambin es una lista lineal de elementos, en la que las inserciones se hacen por un
extremo de la lista, y los borrados por otro. Las inserciones se hacen por el final y los borrados
por el principio. Esto significa que es una estructura del tipo FIFO. Sea cual sea la
implementacin, siempre tendrn que existir 2 variables, frente y final, que apunten al comienzo
y al fin de la cola respectivamente.

71

Podemos implementar una cola con memoria esttica (arrays) y con memoria dinmica (listas
enlazadas). Si implementamos la cola con arrays, tendremos un array llamado cola, que contiene
el tipo de informacin que contiene la cola, y aparte dos valores, frente y final, cuyo valor servir
como el ndice que indica que elemento est al frente y al final de la cola.

La cola estar vaca cuando frente y final no apunten a ningn ndice del array, y esto ser cuando
frente y final valgan 0 si el array se empieza a numerar a partir del 1. Aparte de la funcin que
me dice si la cola est vaca, tendr que implementar funciones de sacar y meter un elemento.

Para insertar un elemento en una cola, habra que incrementar el valor en la variable final, y
despus introducir en la cola del final el elemento. Para eliminar un elemento de una cola,
bastara primero ver que elemento est al frente de la cola, y para eliminarlo aumentar el frente
en una unidad. Si solo consideramos esta posibilidad, es decir, manejar el array solo
incrementando, no lo estaramos utilizando eficientemente, porque podramos llegar al caso en
que habiendo posiciones libres al comienzo del array no pudisemos usarlas cuando el final
alcanzase el mximo ndice del array.

Para evitar esto, el array que implementa la cola, lo vamos a tratar como un array circular
(suponemos que despues de la posicin N del array, viene la posicin 1). Esto quiere decir que si
la cola no est llena, despus de final = Max, viene final = 1, y al sacar el elemento de la cola, si
no est vaca, despus de frente = N, vendr frente = 1, y si despus de sacar el elemento la cola
queda vaca, actualizaremos frente y final a 0.

Si frente es igual a final y son distintos de 0 antes de sacar un elemento, quiere decir que ese
elemento es el ltimo. Antes de insertar un elemento, tendr que ver si la cola est llena
(frente = 1 y final = Max o frente = final + 1).

Implementacin de colas con arreglos:

Funcion cola_vacia (frente: entero; final: entero): boolean
Inicio
Si (frente = 0) y (final = 0)
Entonces retorno verdadero
Sino retorno falso
Fin si
Fin

Funcion INSERCOLA(COLA,N,FRENTE, FINAL,ITEM)
Inicio
Si ((FRENTE = 1) y (FINAL = 1)) o FRENTE = FINAL + 1
72

Entonces escribir Cola llena
Regresar
Fin de si
si FRENTE = NULO entonces
FRENTE = 1
FINAL= 1
Sino
si FINAL = N entonces
FINAL =1
Si no
FINAL = FINAL + 1
Fin Si
Fin si
COLA(FINAL) = ITEM inserta nuevo elemento
fin

Procedimiento elim_cola (COLA,N,FRENTE,FINAL,ITEM)
Este procedimiento elimina un elemento de la cola y lo asigna a ITEM
Si FRENTE = 0 , entonces
Escribir : Subdesbordamiento
Volver
Fin si
ITEM = COLA(FRENTE)
Si FRENTE = FINAL, entonces la cola solo tenia un elemento
FRENTE = 0
FINAL = 0
Si no
Si FRENTE = N , entonces
FRENTE = 1
Si no
FRENTE = FRENTE + 1
Fin si
Fin si
Fin


Aplicaciones de las colas:

73

Las colas se suelen utilizar en los procesos por lotes y en la utilizacin de recursos del sistema.
Cuando un proceso quiere usar un recurso y otro lo est usando, tendr que ponerse en la cola,
y se ir asignando el recurso segn el orden en que se ha pedido.

Colas de prioridades:

A veces, la utilizacin de recursos por parte de los procesos, nos interesa que ciertos procesos
tengan mayor prioridad que otros, incluso aunque lleguen ms tarde, y para ello utilizaramos
las colas de prioridades.

Cada elemento de la cola, tendr otro campo que indique su prioridad, tal que a la hora de sacar
un elemento de la cola, saco el del frente, y a la hora de insertar un elemento en la cola, tendr
en cuenta la prioridad del elemento que quiero insertar, y para ello se inserta en la cola por
orden de prioridad, y si hay ms elementos que tienen la misma prioridad que el que queremos
insertar, los procesamos segn su orden de llegada, es decir, que lo colocamos como el ltimo
de los elementos con esa prioridad.

DOBLES COLAS O BICOLAS:

Una bicola es una lista lineal de elementos en la que las inserciones y borrados es pueden hacer
por cualquiera de sus extremos. Va a haber 2 variables, izquierda y derecha, que apuntan a sus
extremos.

Hay 2 tipos especiales de bicolas:

De entrada restringida: Que permite inserciones solo por un extremo y borrados por los dos.
De salida restringida: Que permite inserciones por cualquier extremo y borrado solo por uno.
Se pueden implementar con memoria esttica o dinmica.

APLICACIONES DE PILAS Y COLAS:
74

Estructura de rboles:
Definicin
Un rbol es una estructura no lineal en la que cada nodo puede apuntar a uno o varios nodos.
Tambin se suele dar una definicin recursiva: un rbol es una estructura en compuesta por un
dato y varios rboles.
Esto son definiciones simples. Pero las caractersticas que implican no lo son tanto.

Definiremos varios conceptos. En relacin con otros nodos:
- Nodo hijo: cualquiera de los nodos apuntados por uno de los nodos del rbol. En el ejemplo,
'L' y 'M' son hijos de 'G'.
- Nodo padre: nodo que contiene un puntero al nodo actual. En el ejemplo, el nodo 'A' es padre
de 'B', 'C' y 'D'.
Los rboles con los que trabajaremos tienen otra caracterstica importante: cada nodo slo puede
ser apuntado por otro nodo, es decir, cada nodo slo tendr un padre. Esto hace que estos rboles
estn fuertemente jerarquizados, y es lo que en realidad les da la apariencia de rboles.
En cuanto a la posicin dentro del rbol:
- Nodo raz: nodo que no tiene padre. Este es el nodo que usaremos para referirnos al rbol. En
el ejemplo, ese nodo es el 'A'.
- Nodo hoja: nodo que no tiene hijos. En el ejemplo hay varios: 'F', 'H', 'I', 'K', 'L', 'M', 'N' y 'O'.
- Nodo rama: aunque esta definicin apenas la usaremos, estos son los nodos que no pertenecen
a ninguna de las dos categoras anteriores. En el ejemplo: 'B', 'C', 'D', 'E', 'G' y 'J'.
Otra caracterstica que normalmente tendrn nuestros rboles es que todos los nodos contengan el
mismo nmero de punteros, es decir, usaremos la misma estructura para todos los nodos del rbol.
Esto hace que la estructura sea ms sencilla, y por lo tanto tambin los programas para trabajar
con ellos.
75

Tampoco es necesario que todos los nodos hijos de un nodo concreto existan. Es decir, que pueden
usarse todos, algunos o ninguno de los punteros de cada nodo.
Un rbol en el que en cada nodo o bien todos o ninguno de los hijos existe, se llama rbol
completo.
En una cosa, los rboles se parecen al resto de las estructuras que hemos visto: dado un nodo
cualquiera de la estructura, podemos considerarlo como una estructura independiente. Es decir,
un nodo cualquiera puede ser considerado como la raz de un rbol completo.
Existen otros conceptos que definen las caractersticas del rbol, en relacin a su tamao:
- Orden: es el nmero potencial de hijos que puede tener cada elemento de rbol. De este modo,
diremos que un rbol en el que cada nodo puede apuntar a otros dos es de orden dos, si puede
apuntar a tres ser de orden tres, etc.
- Grado: el nmero de hijos que tiene el elemento con ms hijos dentro del rbol. En el rbol
del ejemplo, el grado es tres, ya que tanto 'A' como 'D' tienen tres hijos, y no existen elementos
con ms de tres hijos.
- Nivel: se define para cada elemento del rbol como la distancia a la raz, medida en nodos. El
nivel de la raz es cero y el de sus hijos uno. As sucesivamente. En el ejemplo, el nodo 'D'
tiene nivel 1, el nodo 'G' tiene nivel 2, y el nodo 'N', nivel 3.
- Altura: la altura de un rbol se define como el nivel del nodo de mayor nivel. Como cada nodo
de un rbol puede considerarse a su vez como la raz de un rbol, tambin podemos hablar de
altura de ramas. El rbol del ejemplo tiene altura 3, la rama 'B' tiene altura 2, la rama 'G' tiene
altura 1, la 'H' cero, etc.
Los rboles de orden dos son bastante especiales, de hecho les dedicaremos varios captulos. Estos
rboles se conocen tambin como rboles binarios.
Frecuentemente, aunque tampoco es estrictamente necesario, para hacer ms fcil moverse a
travs del rbol, aadiremos un puntero a cada nodo que apunte al nodo padre. De este modo
podremos avanzar en direccin a la raz, y no slo hacia las hojas.
Es importante conservar siempre el nodo raz ya que es el nodo a partir del cual se desarrolla el
rbol, si perdemos este nodo, perderemos el acceso a todo el rbol.
El nodo tpico de un rbol difiere de los nodos que hemos visto hasta ahora para listas, aunque
slo en el nmero de nodos. Veamos un ejemplo de nodo para crear rboles de orden tres:
struct nodo {
int dato;
struct nodo *rama1;
struct nodo *rama2;
struct nodo *rama2;};

76

O generalizando ms:
#define ORDEN 5

struct nodo {
int dato;
struct nodo *rama[ORDEN];
};
Declaraciones de tipos para manejar arboles en C:
Para C, y basndonos en la declaracin de nodo que hemos visto ms arriba, trabajaremos con los
siguientes tipos:

typedef struct _nodo {
int dato;
struct _nodo *rama[ORDEN];
} tipoNodo;

typedef tipoNodo *pNodo;
typedef tipoNodo *Arbol;
Al igual que hicimos con las listas que hemos visto hasta ahora, declaramos un tipo tipoNodo para
declarar nodos, y un tipo pNodo para es el tipo para declarar punteros a un nodo.
Arbol es el tipo para declarar rboles de orden ORDEN.

El movimiento a travs de rboles, salvo que implementemos punteros al nodo padre, ser siempre
partiendo del nodo raz hacia un nodo hoja. Cada vez que lleguemos a un nuevo nodo podremos
optar por cualquiera de los nodos a los que apunta para avanzar al siguiente nodo.
77

En general, intentaremos que exista algn significado asociado a cada uno de los punteros dentro
de cada nodo, los rboles que estamos viendo son abstractos, pero las aplicaciones no tienen por
qu serlo. Un ejemplo de estructura en rbol es el sistema de directorios y ficheros de un sistema
operativo. Aunque en este caso se trata de rboles con nodos de dos tipos, nodos directotio y nodos
fichero, podramos considerar que los nodos hoja son ficheros y los nodos rama son directorios.
Otro ejemplo podra ser la tabla de contenido de un libro, por ejemplo de este mismo curso,
dividido en captulos, y cada uno de ellos en subcaptulos. Aunque el libro sea algo lineal, como
una lista, en el que cada captulo sigue al anterior, tambin es posible acceder a cualquier punto
de l a travs de la tabla de contenido.
Tambin se suelen organizar en forma de rbol los organigramas de mando en empresas o en el
ejrcito, y los rboles genealgicos.
Operaciones bsicas con arboles
Salvo que trabajemos con rboles especiales, como los que veremos ms adelante, las
inserciones sern siempre en punteros de nodos hoja o en punteros libres de nodos rama. Con
estas estructuras no es tan fcil generalizar, ya que existen muchas variedades de rboles.
De nuevo tenemos casi el mismo repertorio de operaciones de las que disponamos con las
listas:
- Aadir o insertar elementos.
- Buscar o localizar elementos.
- Borrar elementos.
- Moverse a travs del rbol.
- Recorrer el rbol completo.
Los algoritmos de insercin y borrado dependen en gran medida del tipo de rbol que estemos
implementando, de modo que por ahora los pasaremos por alto y nos centraremos ms en el
modo de recorrer rboles.
Recorridos por arboles
El modo evidente de moverse a travs de las ramas de un rbol es siguiendo los punteros, del
mismo modo en que nos movamos a travs de las listas.
Esos recorridos dependen en gran medida del tipo y propsito del rbol, pero hay ciertos
recorridos que usaremos frecuentemente. Se trata de aquellos recorridos que incluyen todo el
rbol.
Hay tres formas de recorrer un rbol completo, y las tres se suelen implementar mediante
recursividad. En los tres casos se sigue siempre a partir de cada nodo todas las ramas una por
una.
Supongamos que tenemos un rbol de orden tres, y queremos recorrerlo por completo.
78

Partiremos del nodo raz:
RecorrerArbol(raiz);
La funcin RecorrerArbol, aplicando recursividad, ser tan sencilla como invocar de nuevo a la
funcin RecorrerArbol para cada una de las ramas:
void RecorrerArbol(Arbol a) {
if(a == NULL) return;
RecorrerArbol(a->rama[0]);
RecorrerArbol(a->rama[1]);
RecorrerArbol(a->rama[2]);
}
Lo que diferencia los distintos mtodos de recorrer el rbol no es el sistema de hacerlo, sino el
momento que elegimos para procesar el valor de cada nodo con relacin a los recorridos de
cada una de las ramas.

Los tres tipos son:
Pre-orden:
En este tipo de recorrido, el valor del nodo se procesa antes de recorrer las ramas:



void PreOrden(Arbol a) {
if(a == NULL) return;
Procesar(dato);
RecorrerArbol(a->rama[0]);
RecorrerArbol(a->rama[1]);
RecorrerArbol(a->rama[2]);
79

}
Si seguimos el rbol del ejemplo en pre-orden, y el proceso de los datos es sencillamente
mostrarlos por pantalla, obtendremos algo as:
A B E K F C G L M D H I J N O
In-orden:
En este tipo de recorrido, el valor del nodo se procesa despus de recorrer la primera rama y
antes de recorrer la ltima. Esto tiene ms sentido en el caso de rboles binarios, y tambin
cuando existen ORDEN-1 datos, en cuyo caso procesaremos cada dato entre el recorrido de
cada dos ramas (este es el caso de los rboles-b):
void InOrden(Arbol a) {
if(a == NULL) return;
RecorrerArbol(a->rama[0]);
Procesar(dato);
RecorrerArbol(a->rama[1]);
RecorrerArbol(a->rama[2]);
}
Si seguimos el rbol del ejemplo en in-orden, y el proceso de los datos es sencillamente
mostrarlos por pantalla, obtendremos algo as:
K E B F A L G M C H D I N J O
Post-orden:
En este tipo de recorrido, el valor del nodo se procesa despus de recorrer todas las ramas:
void PostOrden(Arbol a) {
if(a == NULL) return;
RecorrerArbol(a->rama[0]);
RecorrerArbol(a->rama[1]);
RecorrerArbol(a->rama[2]);
Procesar(dato);
}
Si seguimos el rbol del ejemplo en post-orden, y el proceso de los datos es sencillamente
mostrarlos por pantalla, obtendremos algo as:
K E F B L M G C H I N O J D A

Eliminar nodos en un rbol
80

El proceso general es muy sencillo en este caso, pero con una importante limitacin, slo
podemos borrar nodos hoja:
El proceso sera el siguiente:
1. Buscar el nodo padre del que queremos eliminar.
2. Buscar el puntero del nodo padre que apunta al nodo que queremos borrar.
3. Liberar el nodo.
4. padre->nodo[i] = NULL;.
Cuando el nodo a borrar no sea un nodo hoja, diremos que hacemos una "poda", y en ese caso
eliminaremos el rbol cuya raz es el nodo a borrar. Se trata de un procedimiento recursivo,
aplicamos el recorrido PostOrden, y el proceso ser borrar el nodo.
El procedimiento es similar al de borrado de un nodo:
1. Buscar el nodo padre del que queremos eliminar.
2. Buscar el puntero del nodo padre que apunta al nodo que queremos borrar.
3. Podar el rbol cuyo padre es nodo.
4. padre->nodo[i] = NULL;.
En el rbol del ejemplo, para podar la rama 'B', recorreremos el subrbol 'B' en postorden,
eliminando cada nodo cuando se procese, de este modo no perdemos los punteros a las ramas
apuntadas por cada nodo, ya que esas ramas se borrarn antes de eliminar el nodo.
De modo que el orden en que se borrarn los nodos ser:
K E F y B

Arboles ordenados
Ahora slo hablaremos de rboles ordenados, ya que son los que tienen ms inters desde el
punto de vista de TAD, y los que tienen ms aplicaciones genricas.
Un rbol ordenado, en general, es aquel a partir del cual se puede obtener una secuencia
ordenada siguiendo uno de los recorridos posibles del rbol: inorden, preorden o postorden.
En estos rboles es importante que la secuencia se mantenga ordenada aunque se aadan o se
eliminen nodos.
Existen varios tipos de rboles ordenados, que veremos a continuacin:
- rboles binarios de bsqueda (ABB): son rboles de orden 2 que mantienen una
secuencia ordenada si se recorren en inorden.
- rboles AVL: son rboles binarios de bsqueda equilibrados, es decir, los niveles de cada
rama para cualquier nodo no difieren en ms de 1.
81

- rboles perfectamente equilibrados: son rboles binarios de bsqueda en los que el
nmero de nodos de cada rama para cualquier nodo no difieren en ms de 1. Son por lo
tanto rboles AVL tambin.
- rboles 2-3: son rboles de orden 3, que contienen dos claves en cada nodo y que estn
tambin equilibrados. Tambin generan secuencias ordenadas al recorrerlos en inorden.
- rboles-B: caso general de rboles 2-3, que para un orden M, contienen M-1 claves.
-
rboles binarios de bsqueda (ABB):
Definicion
Se trata de rboles de orden 2 en los que se cumple que para cada nodo, el valor de la clave de
la raz del subrbol izquierdo es menor que el valor de la clave del nodo y que el valor de la
clave raz del subrbol derecho es mayor que el valor de la clave del nodo.

Operaciones en ABB
El repertorio de operaciones que se pueden realizar sobre un ABB es parecido al que
realizbamos sobre otras estructuras de datos, ms alguna otra propia de rboles:
- Buscar un elemento.
- Insertar un elemento.
- Borrar un elemento.
- Movimientos a travs del rbol:
o Izquierda.
o Derecha.
o Raiz.
- Informacin:
o Comprobar si un rbol est vaco.
o Calcular el nmero de nodos.
o Comprobar si el nodo es hoja.
o Calcular la altura de un nodo.
o Calcular la altura de un rbol.

82

Buscar un elemento
Partiendo siempre del nodo raz, el modo de buscar un elemento se define de forma recursiva.
- Si el rbol est vaco, terminamos la bsqueda: el elemento no est en el rbol.
- Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la
bsqueda con xito.
- Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la
bsqueda en el rbol izquierdo.
- Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la
bsqueda en el rbol derecho.
El valor de retorno de una funcin de bsqueda en un ABB puede ser un puntero al nodo
encontrado, o NULL, si no se ha encontrado.
Insertar un elemento
Para insertar un elemento nos basamos en el algoritmo de bsqueda. Si el elemento est en el
rbol no lo insertaremos. Si no lo est, lo insertaremos a continuacin del ltimo nodo visitado.
Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raz actual. El
valor inicial para ese puntero es NULL.
- Padre = NULL
- nodo = Raiz
- Bucle: mientras actual no sea un rbol vaco o hasta que se encuentre el elemento.
o Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos
la bsqueda en el rbol izquierdo: Padre=nodo, nodo=nodo->izquierdo.
o Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos
la bsqueda en el rbol derecho: Padre=nodo, nodo=nodo->derecho.
- Si nodo no es NULL, el elemento est en el rbol, por lo tanto salimos.
- Si Padre es NULL, el rbol estaba vaco, por lo tanto, el nuevo rbol slo contendr el
nuevo elemento, que ser la raz del rbol.
- Si el elemento es menor que el Padre, entonces insertamos el nuevo elemento como un
nuevo rbol izquierdo de Padre.
- Si el elemento es mayor que el Padre, entonces insertamos el nuevo elemento como un
nuevo rbol derecho de Padre.
Este modo de actuar asegura que el rbol sigue siendo ABB.
Borrar un elemento
Para borrar un elemento tambin nos basamos en el algoritmo de bsqueda. Si el elemento no
est en el rbol no lo podremos borrar. Si est, hay dos casos posibles:
1. Se trata de un nodo hoja: en ese caso lo borraremos directamente.
83

2. Se trata de un nodo rama: en ese caso no podemos eliminarlo, puesto que perderamos
todos los elementos del rbol de que el nodo actual es padre. En su lugar buscamos el nodo
ms a la izquierda del subrbol derecho, o el ms a la derecha del subrbol izquierdo e
intercambiamos sus valores. A continuacin eliminamos el nodo hoja.
Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raz actual. El
valor inicial para ese puntero es NULL.
- Padre = NULL
- Si el rbol est vaco: el elemento no est en el rbol, por lo tanto salimos sin eliminar
ningn elemento.
- (1) Si el valor del nodo raz es igual que el del elemento que buscamos, estamos ante uno
de los siguientes casos:
o El nodo raz es un nodo hoja:
Si 'Padre' es NULL, el nodo raz es el nico del rbol, por lo tanto el puntero
al rbol debe ser NULL.
Si raz es la rama derecha de 'Padre', hacemos que esa rama apunte a NULL.
Si raz es la rama izquierda de 'Padre', hacemos que esa rama apunte a
NULL.
Eliminamos el nodo, y salimos.
o El nodo no es un nodo hoja:
Buscamos el 'nodo' ms a la izquierda del rbol derecho de raz o el ms a
la derecha del rbol izquierdo. Hay que tener en cuenta que puede que slo
exista uno de esos rboles. Al mismo tiempo, actualizamos 'Padre' para que
apunte al padre de 'nodo'.
Intercambiamos los elementos de los nodos raz y 'nodo'.
Borramos el nodo 'nodo'. Esto significa volver a (1), ya que puede suceder
que 'nodo' no sea un nodo hoja. (Ver ejemplo 3)
- Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la
bsqueda en el rbol izquierdo.
- Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la
bsqueda en el rbol derecho.
Ejemplo 1: Borrar un nodo hoja
En el rbol de ejemplo, borrar el nodo 3.
1. Localizamos el nodo a borrar, al tiempo que mantenemos un puntero a 'Padre'.
2. Hacemos que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL.
3. Borramos el 'nodo'.
84


Ejemplo 2: Borrar un nodo rama con intercambio de un nodo hoja.
En el rbol de ejemplo, borrar el nodo 4.
1. Localizamos el nodo a borrar ('raz').
2. Buscamos el nodo ms a la derecha del rbol izquierdo de 'raz', en este caso el 3, al tiempo
que mantenemos un puntero a 'Padre' a 'nodo'.
3. Intercambiamos los elementos 3 y 4.
4. Hacemos que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL.
5. Borramos el 'nodo'.

Ejemplo 3: Borrar un nodo rama con intercambio de un nodo rama.
Para este ejemplo usaremos otro rbol. En ste borraremos el elemento 6.

1. Localizamos el nodo a borrar ('raz').
85

2. Buscamos el nodo ms a la izquierda del rbol derecho de 'raz', en este caso el 12, ya que
el rbol derecho no tiene nodos a su izquierda, si optamos por la rama izquierda, estaremos
en un caso anlogo. Al mismo tiempo que mantenemos un puntero a 'Padre' a 'nodo'.
3. Intercambiamos los elementos 6 y 12.
4. Ahora tenemos que repetir el bucle para el nodo 6 de nuevo, ya que no podemos eliminarlo.

5. Localizamos de nuevo el nodo a borrar ('raz').
6. Buscamos el nodo ms a la izquierda del rbol derecho de 'raz', en este caso el 16, al
mismo tiempo que mantenemos un puntero a 'Padre' a 'nodo'.
7. Intercambiamos los elementos 6 y 16.
8. Hacemos que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL.
9. Borramos el 'nodo'.

Este modo de actuar asegura que el rbol sigue siendo ABB.
Movimientos a travs de un rbol
No hay mucho que contar. Nuestra estructura se referenciar siempre mediante un puntero al
nodo Raz, este puntero no debe perderse nunca.
Para movernos a travs del rbol usaremos punteros auxiliares, de modo que desde cualquier
puntero los movimientos posibles sern: moverse al nodo raz de la rama izquierda, moverse al
nodo raz de la rama derecha o moverse al nodo Raz del rbol.
Informacin
Hay varios parmetros que podemos calcular o medir dentro de un rbol. Algunos de ellos nos
darn idea de lo eficientemente que est organizado o el modo en que funciona.
86

Comprobar si un rbol est vaco.
Un rbol est vaco si su raz es NULL.
Calcular el nmero de nodos.
Tenemos dos opciones para hacer esto, una es llevar siempre la cuenta de nodos en el rbol al
mismo tiempo que se aaden o eliminan elementos. La otra es, sencillamente, contarlos.
Para contar los nodos podemos recurrir a cualquiera de los tres modos de recorrer el rbol:
inorden, preorden o postorden, como accin sencillamente incrementamos el contador.
Comprobar si el nodo es hoja.
Esto es muy sencillo, basta con comprobar si tanto el rbol izquierdo como el derecho estn
vacos. Si ambos lo estn, se trata de un nodo hoja.
Calcular la altura de un nodo.
No hay un modo directo de hacer esto, ya que no nos es posible recorrer el rbol en la
direccin de la raz. De modo que tendremos que recurrir a otra tcnica para calcular la altura.
Lo que haremos es buscar el elemento del nodo de que queremos averiguar la altura. Cada vez
que avancemos un nodo incrementamos la variable que contendr la altura del nodo.
- Empezamos con el nodo raz apuntando a Raiz, y la 'Altura' igual a cero.
- Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la
bsqueda y el valor de la altura es 'Altura'.
- Incrementamos 'Altura'.
- Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la
bsqueda en el rbol izquierdo.
- Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la
bsqueda en el rbol derecho.
Calcular la altura de un rbol.
La altura del rbol es la altura del nodo de mayor altura. Para buscar este valor tendremos que
recorrer todo el rbol, de nuevo es indiferente el tipo de recorrido que hagamos, cada vez que
cambiemos de nivel incrementamos la variable que contiene la altura del nodo actual, cuando
lleguemos a un nodo hoja compararemos su altura con la variable que contiene la altura del
rbol si es mayor, actualizamos la altura del rbol.
- Iniciamos un recorrido del rbol en postorden, con la variable de altura igual a cero.
- Cada vez que empecemos a recorrer una nueva rama, incrementamos la altura para ese
nodo.
- Despus de procesar las dos ramas, verificamos si la altura del nodo es mayor que la
variable que almacena la altura actual del rbol, si es as, actualizamos esa variable.
Arboles degenerados
87

Los rboles binarios de bsqueda tienen un gran inconveniente. Por ejemplo, supongamos que
creamos un ABB a partir de una lista de valores ordenada:
2, 4, 5, 8, 9, 12
Difcilmente podremos llamar a la estructura resultante un rbol:

Esto es lo que llamamos un rbol binario de bsqueda degenerado, y en el siguiente captulo
veremos una nueva estructura, el rbol AVL, que resuelve este problema, generando rboles
de bsqueda equilibrados.


Ejemplos de ABB en C
Vamos a ver cmo implementar en C algunas de las funciones que hemos explicado para
rboles ABB, al final se incluye un ejemplo completo para rboles de enteros.
Declaracin de tipos:
Como estamos trabajando con un rbol binario, slo necesitamos una estructura para
referirnos tanto a cualquiera de los nodos como al rbol completo. Recuerda que cualquier
nodo puede ser considerado como la raz de un rbol.
typedef struct _nodo {
int dato;
struct _nodo *derecho;
struct _nodo *izquierdo;
} tipoNodo;

typedef tipoNodo *pNodo;
typedef tipoNodo *Arbol;
88

Insertar un elemento en un rbol ABB:
Disearemos una funcin que se ajuste al algoritmo que describimos en el punto 7.4:
1. Padre = NULL
2. nodo = Raiz
3. Bucle: mientras actual no sea un rbol vaco o hasta que se encuentre el elemento.
a. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos
la bsqueda en el rbol izquierdo: Padre=nodo, nodo=nodo->izquierdo.
b. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos
la bsqueda en el rbol derecho: Padre=nodo, nodo=nodo->derecho.
4. Si nodo no es NULL, el elemento est en el rbol, por lo tanto salimos.
5. Si Padre es NULL, el rbol estaba vaco, por lo tanto, el nuevo rbol slo contendr el
nuevo elemento, que ser la raz del rbol.
6. Si el elemento es menor que el Padre, entonces insertamos el nuevo elemento como un
nuevo rbol izquierdo de Padre.
7. Si el elemento es mayor que el Padre, entonces insertamos el nuevo elemento como un
nuevo rbol derecho de Padre.
void Insertar(Arbol *a, int dat) {
pNodo padre = NULL; /* (1) */
pNodo actual = *a; /* (2) */

while(!Vacio(actual) && dat != actual->dato) { /* (3) */
padre = actual;
if(dat < actual->dato) actual = actual->izquierdo; /* (3-a) */
else if(dat > actual->dato) actual = actual->derecho; /* (3-b) */
}

if(!Vacio(actual)) return; /* (4) */
if(Vacio(padre)) { /* (5) */
*a = (Arbol)malloc(sizeof(tipoNodo));
(*a)->dato = dat;
(*a)->izquierdo = (*a)->derecho = NULL;
}
else if(dat < padre->dato) { /* (6) */
actual = (Arbol)malloc(sizeof(tipoNodo));
padre->izquierdo = actual;
actual->dato = dat;
actual->izquierdo = actual->derecho = NULL;
}
else if(dat > padre->dato) { /* (7) */
89

actual = (Arbol)malloc(sizeof(tipoNodo));
padre->derecho = actual;
actual->dato = dat;
actual->izquierdo = actual->derecho = NULL;
}
}


Eliminar un elemento de un rbol ABB:
Disearemos una funcin que se ajuste al algoritmo que describimos en el punto 7.5:
1. Padre = NULL
2. Si el rbol est vaco: el elemento no est en el rbol, por lo tanto salimos sin eliminar
ningn elemento.
3. Si el valor del nodo raz es igual que el del elemento que buscamos, estamos ante uno de
los siguientes casos:
a. El nodo raz es un nodo hoja:
i. Si 'Padre' es NULL, el nodo raz es el nico del rbol, por lo tanto el puntero
al rbol debe ser NULL.
ii. Si raz es la rama derecha de 'Padre', hacemos que esa rama apunte a NULL.
iii. Si raz es la rama izquierda de 'Padre', hacemos que esa rama apunte a
NULL.
iv. Eliminamos el nodo, y salimos.
b. El nodo no es un nodo hoja:
i. Buscamos el 'nodo' ms a la izquierda del rbol derecho de raz o el ms a
la derecha del rbol izquierdo. Hay que tener en cuenta que puede que slo
exista uno de esos rboles. Al mismo tiempo, actualizamos 'Padre' para que
apunte al padre de 'nodo'.
ii. Intercambiamos los elementos de los nodos raz y 'nodo'.
iii. Borramos el nodo 'nodo'. Esto significa volver a (3), ya que puede suceder
que 'nodo' no sea un nodo hoja.
4. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la
bsqueda en el rbol izquierdo.
5. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la
bsqueda en el rbometodologa de programacin para dar soluciones a los problemas
6. computacionalesl derecho.
void Borrar(Arbol *a, int dat) {
pNodo padre = NULL; /* (1) */
pNodo actual;
90

pNodo nodo;
int aux;
actual = *a;
while(!Vacio(actual)) { /* Bsqueda (2) else implcito */
if(dat == actual->dato) { /* (3) */
if(EsHoja(actual)) { /* (3-a) */
if(padre)/* (3-a-i caso else implcito) */
if(padre->derecho == actual) padre->derecho = NULL; /* (3-a-ii) */
else if(padre->izquierdo == actual) padre->izquierdo = NULL; /* (3-a-iii) */
free(actual); /* (3-a-iv) */
actual = NULL;
return;
}
else { /* (3-b) */
/* Buscar nodo */
padre = actual; /* (3-b-i) */
if(actual->derecho) {
nodo = actual->derecho;
while(nodo->izquierdo) {
padre = nodo;
nodo = nodo->izquierdo;
}
}
else {
nodo = actual->izquierdo;
while(nodo->derecho) {
padre = nodo;
nodo = nodo->derecho;
}
}
/* Intercambio */
aux = actual->dato; /* (3-b-ii) */
actual->dato = nodo->dato;
nodo->dato = aux;
actual = nodo;
}
}
else {
padre = actual;
if(dat > actual->dato) actual = actual->derecho; /* (4) */
91

else if(dat < actual->dato) actual = actual->izquierdo; /* (5) */
}
}
}
Buscar un elemento en un rbol ABB:
Disearemos una funcin que se ajuste al algoritmo que describimos en el punto 7.3:
1. Si el rbol est vaco, terminamos la bsqueda: el elemento no est en el rbol.
2. Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la
bsqueda con xito.
3. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la
bsqueda en el rbol izquierdo.
4. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la
bsqueda en el rbol dermetodologa de programacin para dar soluciones a los problemas
5. computacionalesecho.
int Buscar(Arbol a, int dat) {
pNodo actual = a;

while(!Vacio(actual)) {
if(dat == actual->dato) return TRUE; /* dato encontrado (2) */
else if(dat < actual->dato) actual = actual->izquierdo; /* (3) */
else if(dat > actual->dato) actual = actual->derecho; /* (4) */
}
return FALSE; /* No est en rbol (1) */
}

Comprobar si el rbol est vaco:
Esta funcin es fcil de implementar:
int Vacio(Arbol r) {
return r==NULL;
}
Comprobar si un nodo es hoja:
Esta funcin tambin es sencilla de implementar:
int EsHoja(pNodo r) {
return !r->derecho && !r->izquierdo;
92

}
Contar nmero de nodos:
Contar los nodos podemos recurrir a cualquiera de los tres modos de recorrer el rbol:
inorden, preorden o postorden y como accin incrementamos el contador de nodos. Para
implementar este algoritmo recurrimos a dos funciones:
int NumeroNodos(Arbol a, int *contador) {
*contador = 0;

auxContador(a, contador);
return *contador;
}

void auxContador(Arbol nodo, int *c) {
(*c)++; /* Accin: incrementar nmero de nodos. (Preorden) */
if(nodo->izquierdo) auxContador(nodo->izquierdo, c); /* Rama izquierda */
if(nodo->derecho) auxContador(nodo->derecho, c); /* Rama derecha */
}
Calcular la altura de un rbol:
Es un problema parecido al anterior, pero ahora tenemos que contar la altura, no en nmero
de nodos. Cada vez que lleguemos a un nodo hoja, verificamos si la altura del nodo es la
mxima, y si lo es, actualizamos la altura del rbol a ese valor:
1. Iniciamos un recorrido del rbol en postorden, con la variable de altura igual a cero.
2. Cada vez que empecemos a recorrer una nueva rama, incrementamos la altura para ese
nodo.
3. Despus de procesar las dos ramas, verificamos si la altura del nodo es mayor que la
variable que almacena la altura actual del rbol, si es as, actualizamos esa variable.
int AlturaArbol(Arbol a, int *altura) {
*altura = 0; /* (1) */

auxAltura(a, 0, altura);
return *altura;
}

void auxAltura(pNodo nodo, int a, int *altura) {
/* (2) Cada vez que llamamos a auxAltura pasamos como parmetro a+1 */
93

if(nodo->izquierdo) auxAltura(nodo->izquierdo, a+1, altura); /* Rama izquierda */
if(nodo->derecho) auxAltura(nodo->derecho, a+1, altura); /* Rama derecha */
if(EsHoja(nodo) && a > *altura) *altura = a; /* Proceso (Postorden) (3) */
}
Calcular la altura del nodo que contienen un dato concreto:
Lo que haremos ser buscar el elemento del nodo del que queremos averiguar la altura. Cada
vez que avancemos un nodo incrementamos la variable que contendr la altura del nodo.
1. Empezamos con el nodo raz apuntando a Raiz, y la 'Altura' igual a cero.
2. Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la
bsqueda y el valor de la altura es 'Altura'.
3. Incrementamos 'Altura'.
4. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la
bsqueda en el rbol izquierdo.
5. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la
bsqueda en el rbol derecho.
int Altura(Arbol a, int dat) {
int altura = 0;
pNodo actual = a; /* (1) */

while(!Vacio(actual)) {
if(dat == actual->dato) return altura; /* dato encontrado. (2) */
else {
altura++; /* (3) */
if(dat < actual->dato) actual = actual->izquierdo; /* (4) */
else if(dat > actual->dato) actual = actual->derecho; /* (5) */
}
}
return -1; /* No est en rbol */
}
Aplicar una funcin a cada elemento del rbol, segn los tres posibles recorridos:
Todos los recorridos se aplican de forma recursiva. En este ejemplo crearemos tres funciones,
una por cada tipo de recorrido, que aplicarn una funcin al elemento de cada nodo.
La funcin a aplicar puede ser cualquiera que admita como parmetro un puntero a un entero,
y que no tenga valor de retorno.
94

InOrden
En Inorden, primero procesamos el subrbol izquierdo, despus el nodo actual, y finalmente el
subrbol derecho:
void InOrden(Arbol a, void (*func)(int*)) {
if(a->izquierdo) InOrden(a->izquierdo, func); /* Subrbol izquierdo */
func(&(a->dato)); /* Aplicar la funcin al dato del nodo actual */
if(a->derecho) InOrden(a->derecho, func); /* Subrbol derecho */
}
PreOrden
En Preorden, primero procesamos el nodo actual, despus el subrbol izquierdo, y finalmente
el subrbol derecho:
void PreOrden(Arbol a, void (*func)(int*)) {
func(&(a->dato)); /* Aplicar la funcin al dato del nodo actual */
if(a->izquierdo) PreOrden(a->izquierdo, func); /* Subrbol izquierdo */
if(a->derecho) PreOrden(a->derecho, func); /* Subrbol derecho */
}
PostOrden
En Postorden, primero procesamos el subrbol izquierdo, despus el subrbol derecho, y
finalmente el nodo actual:
void PostOrden(Arbol a, void (*func)(int*)) {
if(a->izquierdo) PostOrden(a->izquierdo, func); /* Subrbol izquierdo */
if(a->derecho) PostOrden(a->derecho, func); /* Subrbol derecho */
func(&(a->dato)); /* Aplicar la funcin al dato del nodo actual */
Ejemplos de ABB en C++
Haremos ahora lo mismo que en el ejemplo en C, pero incluyendo todas las funciones y datos
en una nica clase.
Declaracin de clase ArbolABB:
Declaramos dos clases, una para nodo y otra para ArbolABB, la clase nodo la declararemos
como parte de la clase ArbolABB, de modo que no tendremos que definir relaciones de
amistad, y evitamos que otras clases o funciones tengan acceso a los datos internos de nodo.
class ArbolABB {
private:
//// Clase local de Lista para Nodo de ArbolBinario:
95

class Nodo {
public:
// Constructor:
Nodo(const int dat, Nodo *izq=NULL, Nodo *der=NULL) :
dato(dat), izquierdo(izq), derecho(der) {}
// Miembros:
int dato;
Nodo *izquierdo;
Nodo *derecho;
};

// Punteros de la lista, para cabeza y nodo actual:
Nodo *raz;
Nodo *actual;
int contador;
int altura;

public:
// Constructor y destructor bsicos:
ArbolABB() : raz(NULL), actual(NULL) {}
~ArbolABB() { Podar(raz); }
// Insertar en rbol ordenado:
void Insertar(const int dat);
// Borrar un elemento del rbol:
void Borrar(const int dat);
// Funcin de bsqueda:
bool Buscar(const int dat);
// Comprobar si el rbol est vaco:
bool Vacio(Nodo *r) { return r==NULL; }
// Comprobar si es un nodo hoja:
bool EsHoja(Nodo *r) { return !r->derecho && !r->izquierdo; }
// Contar nmero de nodos:
const int NumeroNodos();
const int AlturaArbol();
// Calcular altura de un int:
int Altura(const int dat);
// Devolver referencia al int del nodo actual:
int &ValorActual() { return actual->dato; }
// Moverse al nodo raz:
void Raiz() { actual = raz; }
96

// Aplicar una funcin a cada elemento del rbol:
void InOrden(void (*func)(int&) , Nodo *nodo=NULL, bool r=true);
void PreOrden(void (*func)(int&) , Nodo *nodo=NULL, bool r=true);
void PostOrden(void (*func)(int&) , Nodo *nodo=NULL, bool r=true);
private:
// Funciones auxiliares
void Podar(Nodo* &);
void auxContador(Nodo*);
void auxAltura(Nodo*, int);
};
Definicin de las funciones miembro:
Las definiciones de las funciones miembro de la clase no difieren demasiado de las que
creamos en C. Tan solo se han sustituido algunos punteros por referencias, y se usa el tipo bool
cuando es aconsejable.
Por ejemplo, en las funciones de recorrido de rboles, la funcin invocada acepta ahora una
referencia a un entero, en lugar de un puntero a un entero.
Ejemplo de ABB en C++ usando plantillas
Slo nos queda generalizar la clase del ejemplo anterior implementndola en forma de
plantilla.
El proceso es relativamente sencillo, slo tenemos que cambiar la declaracin de dato, y todas
sus referencias. Adems de cambiar la sintaxis de las definiciones de las funciones, claro.
Declaracin de la plantilla ArbolABB:
Se trata de una simple generalizacin de la clase del punto anterior:
template<class DATO>
class ABB {
private:
//// Clase local de Lista para Nodo de ArbolBinario:
template<class DATON>
class Nodo {
public:
// Constructor:
Nodo(const DATON dat, Nodo<DATON> *izq=NULL, Nodo<DATON> *der=NULL) :
dato(dat), izquierdo(izq), derecho(der) {}
// Miembros:
DATON dato;
Nodo<DATON> *izquierdo;
97

Nodo<DATON> *derecho;
};

// Punteros de la lista, para cabeza y nodo actual:
Nodo<DATO> *raz;
Nodo<DATO> *actual;
int contador;
int altura;

public:
// Constructor y destructor bsicos:
ABB() : raz(NULL), actual(NULL) {}
~ABB() { Podar(raz); }
// Insertar en rbol ordenado:
void Insertar(const DATO dat);
// Borrar un elemento del rbol:
void Borrar(const DATO dat);
// Funcin de bsqueda:
bool Buscar(const DATO dat);
// Comprobar si el rbol est vaco:
bool Vacio(Nodo<DATO> *r) { return r==NULL; }
// Comprobar si es un nodo hoja:
bool EsHoja(Nodo<DATO> *r) { return !r->derecho && !r->izquierdo; }
// Contar nmero de nodos:
const int NumeroNodos();
const int AlturaArbol();
// Calcular altura de un dato:
int Altura(const DATO dat);
// Devolver referencia al dato del nodo actual:
DATO &ValorActual() { return actual->dato; }
// Moverse al nodo raz:
void Raiz() { actual = raz; }
// Aplicar una funcin a cada elemento del rbol:
void InOrden(void (*func)(DATO&) , Nodo<DATO> *nodo=NULL, bool r=true);
void PreOrden(void (*func)(DATO&) , Nodo<DATO> *nodo=NULL, bool r=true);
void PostOrden(void (*func)(DATO&) , Nodo<DATO> *nodo=NULL, bool r=true);
private:
// Funciones auxiliares
void Podar(Nodo<DATO>* &);
void auxContador(Nodo<DATO>*);
98

void auxAltura(Nodo<DATO>*, int);
};
Definicin de las funciones miembro:
Las definiciones de las funciones miembro de la clase no difieren en nada de las que creamos
en el ejemplo anterior. Tan solo se han sustituido los tipos del dato por el tipo de dato de la
plantilla.
rboles AVL:
Arboles equilibrados
Ya vimos al final del captulo anterior que el comportamiento de los ABB no es siempre tan
bueno como nos gustara. Pues bien, para minimizar el problema de los ABB desequilibrados,
sea cual sea el grado de desequilibrio que tengan, se puede recurrir a algoritmos de
equilibrado de rboles globales. En cuanto a estos algoritmos, existen varios, por ejemplo,
crear una lista mediante la lectura en inorden del rbol, y volver a reconstruirlo equilibrado.
Conociendo el nmero de elementos no es demasiado complicado.
El problema de estos algoritmos es que requieren explorar y reconstruir todo el rbol cada vez
que se inserta o se elimina un elemento, de modo que lo que ganamos al acortar las
bsquedas, teniendo que hacer menos comparaciones, lo perdemos equilibrando el rbol.
Para resolver este inconveniente podemos recurrir a los rboles AVL.
Definicion
Un rbol AVL (llamado as por las iniciales de sus inventores: Adelson-Velskii y Landis) es un
rbol binario de bsqueda en el que para cada nodo, las alturas de sus subrboles izquierdo y
derecho no difieren en ms de 1.
No se trata de rboles perfectamente equilibrados, pero s son lo suficientemente equilibrados
como para que su comportamiento sea lo bastante bueno como para usarlos donde los ABB no
garantizan tiempos de bsqueda ptimos.
El algoritmo para mantener un rbol AVL equilibrado se basa en reequilibrados locales, de
modo que no es necesario explorar todo el rbol despus de cada insercin o borrado.
Operaciones en AVL
Los AVL son tambin ABB, de modo que mantienen todas las operaciones que poseen stos.
Las nuevas operaciones son las de equilibrar el rbol, pero eso se hace como parte de las
operaciones de insertado y borrado.
Factor de equilibrio
Cada nodo, adems de la informacin que se pretende almacenar, debe tener los dos punteros
a los rboles derecho e izquierdo, igual que los ABB, y adems un miembro nuevo: el factor de
equilibrio.
99

El factor de equilibrio es la diferencia entre las alturas del rbol derecho y el izquierdo:
FE = altura subrbol derecho - altura subrbol izquierdo;
Por definicin, para un rbol AVL, este valor debe ser -1, 0 1.

Rotaciones simples de nodos
Los reequilibrados se realizan mediante rotaciones, en el siguiente punto veremos cada caso,
ahora vamos a ver las cuatro posibles rotaciones que podemos aplicar.
Rotacin simple a la derecha (SD):
Esta rotacin se usar cuando el subrbol izquierdo de un nodo sea 2 unidades ms alto que el
derecho, es decir, cuando su FE sea de -2. Y adems, la raz del subrbol izquierdo tenga una FE
de -1, es decir, que est cargado a la izquierda.

Procederemos del siguiente modo:
Llamaremos P al nodo que muestra el desequilibrio, el que tiene una FE de -2. Y llamaremos Q
al nodo raz del subrbol izquierdo de P. Adems, llamaremos A al subrbol izquierdo de Q, B al
subrbol derecho de Q y C al subrbol derecho de P.
En el grfico que puede observar que tanto B como C tienen la misma altura (n), y A es una
unidad mayor (n+1). Esto hace que el FE de Q sea -1, la altura del subrbol que tiene Q como
raz es (n+2) y por lo tanto el FE de P es -2.
1. Pasamos el subrbol derecho del nodo Q como subrbol izquierdo de P. Esto mantiene el
rbol como ABB, ya que todos los valores a la derecha de Q siguen estando a la izquierda
de P.
2. El rbol P pasa a ser el subrbol derecho del nodo Q.
3. Ahora, el nodo Q pasa a tomar la posicin del nodo P, es decir, hacemos que la entrada al
rbol sea el nodo Q, en lugar del nodo P. Previamente, P puede que fuese un rbol completo
o un subrbol de otro nodo de menor altura.
100


En el rbol resultante se puede ver que tanto P como Q quedan equilibrados en cuanto altura.
En el caso de P porque sus dos subrboles tienen la misma altura (n), en el caso de Q, porque
su subrbol izquierdo A tiene una altura (n+1) y su subrbol derecho tambin, ya que a P se
aade la altura de cualquiera de sus subrboles.

Rotacin simple a la izquierda (SI):
Se trata del caso simtrico del anterior. Esta rotacin se usar cuando el subrbol derecho de
un nodo sea 2 unidades ms alto que el izquierdo, es decir, cuando su FE sea de 2. Y adems, la
raz del subrbol derecho tenga una FE de 1, es decir, que est cargado a la derecha.
101


Procederemos del siguiente modo:
Llamaremos P al nodo que muestra el desequilibrio, el que tiene una FE de 2. Y llamaremos Q
al nodo raz del subrbol derecho de P. Adems, llamaremos A al subrbol izquierdo de P, B al
subrbol izquierdo de Q y C al subrbol derecho de Q.
En el grfico que puede observar que tanto A como B tienen la misma altura (n), y C es una
unidad mayor (n+1). Esto hace que el FE de Q sea 1, la altura del subrbol que tiene Q como
raz es (n+2) y por lo tanto el FE de P es 2.
1. Pasamos el subrbol izquierdo del nodo Q como subrbol derecho de P. Esto mantiene el
rbol como ABB, ya que todos los valores a la izquierda de Q siguen estando a la derecha
de P.
2. El rbol P pasa a ser el subrbol izquierdo del nodo Q.
3. Ahora, el nodo Q pasa a tomar la posicin del nodo P, es decir, hacemos que la entrada al
rbol sea el nodo Q, en lugar del nodo P. Previamente, P puede que fuese un rbol completo
o un subrbol de otro nodo de menor altura.
102


En el rbol resultante se puede ver que tanto P como Q quedan equilibrados en cuanto altura.
En el caso de P porque sus dos subrboles tienen la misma altura (n), en el caso de Q, porque
su subrbol izquierdo A tiene una altura (n+1) y su subrbol derecho tambin, ya que a P se
aade la altura de cualquiera de sus subrboles.

Rotaciones dobles de nodos
Rotacin doble a la derecha (DD):
Esta rotacin se usar cuando el subrbol izquierdo de un nodo sea 2 unidades ms alto que el
derecho, es decir, cuando su FE sea de -2. Y adems, la raz del subrbol izquierdo tenga una FE
de 1, es decir, que est cargado a la derecha.
103


Este es uno de los posibles rboles que pueden presentar esta estructura, pero hay otras dos
posibilidades. El nodo R puede tener una FE de -1, 0 1. En cada uno de esos casos los rboles
izquierdo y derecho de R (B y C) pueden tener alturas de n y n-1, n y n, o n-1 y n,
respectivamente.
El modo de realizar la rotacin es independiente de la estructura del rbol R, cualquiera de las
tres produce resultados equivalentes. Haremos el anlisis para el caso en que FE sea -1.
En este caso tendremos que realizar dos rotaciones.
Llamaremos P al nodo que muestra el desequilibrio, el que tiene una FE de -2. Llamaremos Q al
nodo raz del subrbol izquierdo de P, y R al nodo raz del subrbol derecho de Q.
1. Haremos una rotacin simple de Q a la izquierda.
2. Despus, haremos una rotacin simple de P a la derecha.
Con ms detalle, procederemos del siguiente modo:
1. Pasamos el subrbol izquierdo del nodo R como subrbol derecho de Q. Esto mantiene el
rbol como ABB, ya que todos los valores a la izquierda de R siguen estando a la derecha
de Q.
2. Ahora, el nodo R pasa a tomar la posicin del nodo Q, es decir, hacemos que la raz del
subrbol izquierdo de P sea el nodo R en lugar de Q.
3. El rbol Q pasa a ser el subrbol izquierdo del nodo R.
104


4. Pasamos el subrbol derecho del nodo R como subrbol izquierdo de P. Esto mantiene el
rbol como ABB, ya que todos los valores a la derecha de R siguen estando a la izquierda
de P.
5. Ahora, el nodo R pasa a tomar la posicin del nodo P, es decir, hacemos que la entrada al
rbol sea el nodo R, en lugar del nodo P. Como en los casos anteriores, previamente, P
puede que fuese un rbol completo o un subrbol de otro nodo de menor altura.
6. El rbol P pasa a ser el subrbol derecho del nodo R.
105


Rotacin doble a la izquierda (DI):
Esta rotacin se usar cuando el subrbol derecho de un nodo sea 2 unidades ms alto que el
izquierdo, es decir, cuando su FE sea de 2. Y adems, la raz del subrbol derecho tenga una FE
de -1, es decir, que est cargado a la izquierda. Se trata del caso simtrico del anterior.

En este caso tambin tendremos que realizar dos rotaciones.
106

Llamaremos P al nodo que muestra el desequilibrio, el que tiene una FE de 2. Llamaremos Q al
nodo raz del subrbol derecho de P, y R al nodo raz del subrbol izquierdo de Q.
1. Haremos una rotacin simple de Q a la derecha.
2. Despus, haremos una rotacin simple de P a la izquierda.
Con ms detalle, procederemos del siguiente modo:
1. Pasamos el subrbol derecho del nodo R como subrbol izquierdo de Q. Esto mantiene el
rbol como ABB, ya que todos los valores a la derecha de R siguen estando a la izquierda
de Q.
2. Ahora, el nodo R pasa a tomar la posicin del nodo Q, es decir, hacemos que la raz del
subrbol derecho de P sea el nodo R en lugar de Q.
3. El rbol Q pasa a ser el subrbol derecho del nodo R.

107

4. Pasamos el subrbol izquierdo del nodo R como subrbol derecho de P. Esto mantiene el
rbol como ABB, ya que todos los valores a la izquierda de R siguen estando a la derecha
de P.
5. Ahora, el nodo R pasa a tomar la posicin del nodo P, es decir, hacemos que la entrada al
rbol sea el nodo R, en lugar del nodo P. Como en los casos anteriores, previamente, P
puede que fuese un rbol completo o un subrbol de otro nodo de menor altura.
6. El rbol P pasa a ser el subrbol izquierdo del nodo R.

Reequilibrados en arboles AVL
Cada vez que insertemos o eliminemos un nodo en un rbol AVL pueden suceder dos cosas:
que el rbol se mantenga como AVL o que pierda esta propiedad. En el segundo caso siempre
estaremos en uno de los explicados anteriormente, y recuperaremos el estado AVL aplicando la
rotacin adecuada.
Ya comentamos que necesitamos aadir un nuevo miembro a cada nodo del rbol para
averiguar si el rbol sigue siendo AVL, el Factor de Equilibrio. Cada vez que insertemos o
eliminemos un nodo deberemos recorrer el camino desde ese nodo hacia el nodo raz
actualizando los valores de FE de cada nodo. Cuando uno de esos valores sea 2 -2
aplicaremos la rotacin correspondiente.
108

Debido a que debemos ser capaces de recorrer el rbol en direccin a la raz, aadiremos un
nuevo puntero a cada nodo que apunte al nodo padre. Esto complicar algo las operaciones de
insercin, borrado y rotacin, pero facilita y agiliza mucho el clculo del FE, y veremos que las
complicaciones se compensan en gran parte por las facilidades obtenidas al disponer de este
puntero.
Nota: En rigor, no es necesario ese puntero, podemos almacenar el camino que recorremos
para localizar un nodo concreto usando una pila, y despus podemos usar la pila para
recuperar el camino en orden inverso. Pero esto nos obliga a introducir otra estructura
dinmica, y segn mi opinin, complica en exceso el algoritmo.
Cuando estemos actualizando los valores de FE no necesitamos calcular las alturas de las dos
ramas de cada nodo, sabiendo en valor anterior de FE, y sabiendo en qu rama hemos aadido
o eliminado el nodo, es fcil calcular el nuevo valor de FE. Si el nodo ha sido aadido en la rama
derecha o eliminado en la izquierda, y ha habido un cambio de altura en la rama, se
incrementa el valor de FE; si el nodo ha sido aadido en la rama izquierda o eliminado en la
derecha, y ha habido un cambio de altura en la rama, se decrementa el valor de FE.
Los cambios de altura en una rama se producen slo cuando el FE del nodo raz de esa rama ha
cambiado de 0 a 1 de 0 a -1. En caso contrario, cuando el FE cambia de 1 a 0 de -1 a 0, no se
produce cambio de altura.
Si no hay cambio de altura, los valores de FE del resto de los nodos hasta el raz no pueden
cambiar, recordemos que el factor de equilibrio se define como la diferencia de altura entre las
ramas derecha e izquierda de un nodo, la altura de la rama que no pertenece al camino no
puede cambiar, puesto que sigue teniendo los mismos nodos que antes, de modo que si la
altura de la rama que pertenece al camino no cambia, tampoco puede cambiar el valor de FE.
Por ejemplo, supongamos que en siguiente rbol AVL insertamos el nodo de valor 8:

Para empezar, cualquier nodo nuevo ser un nodo hoja, de modo que su FE ser siempre 0.
Ahora actualizamos el valor de FE del nodo padre del que acabamos de insertar (P). El valor
previo es 0, y hemos aadido un nodo en su rama izquierda, por lo tanto, el nuevo valor es -1.
Esto implica un cambio de altura, por lo tanto, continuamos camino hacia la raz.
109

A continuacin tomamos el nodo padre de P (Q), cuyo valor previo de FE era 1, y al que
tambin hemos aadido un nodo en su rama izquierda, por lo tanto decrementamos ese valor,
y el nuevo ser 0. En este caso no ha incremento de altura, la altura del rbol cuya raz es Q
sigue siendo la misma, por lo tanto, ninguno de los valores de FE de los nodos hasta el raz
puede haber cambiado. Es decir, no necesitamos seguir recorriendo el camino.
Si verificamos el valor de FE del nodo R vemos que efectivamente se mantiene, puesto que
tanto la altura del subrbol derecho como del izquierdo, siguen siendo las mismas.

Pero algunas veces, el valor de FE del nodo es -2 2, son los casos en los que perdemos la
propiedad AVL del rbol, y por lo tanto tendremos que recuperarla.
Reequilibrados en rboles AVL por insercin de un nodo
En ese caso, cuando el valor de FE de un nodo tome el valor -2 2, no seguiremos el camino,
sino que, con el valor de FE de el nodo actual y el del nodo derecho si FE es 2 o el del nodo
izquierdo si es -2, determinaremos qu tipo de rotacin debemos hacer.

FE nodo actual FE del nodo derecho FE del nodo izquierdo Rotacin
-2 No importa -1 RSD
-2 No importa 1 RDD
2 -1 No importa RDI
2 1 No importa RSI
El resto de los casos no nos interesan. Esto es porque en nodos desequilibrados hacia la
derecha, con valores de FE positivos, siempre buscaremos el equilibrio mediante rotaciones a
la izquierda, y viceversa, con nodos desequilibrados hacia la izquierda, con valores de FE
negativos, buscaremos el equilibrio mediante rotaciones a la derecha.
Supongamos que el valor de FE del nodo ha pasado de -1 a -2, debido a que se ha aadido un
nodo. Esto implica que el nodo aadido lo ha sido en la rama izquierda, si lo hubiramos
aadido en la derecha el valor de FE nunca podra decrecer.
110

Reequilibrados en rboles AVL por borrado de un nodo
Cuando el desequilibrio se debe a la eliminacin de un nodo la cosa puede ser algo diferente,
pero veremos que siempre se puede llegar a uno de los casos anteriores.
Supongamos el siguiente ejemplo, en el rbol AVL eliminaremos el nodo de valor 3:

El valor de FE del nodo P pasa de 1 a 2, sabemos que cuando el valor de FE de un nodo es 2
siempre tenemos que aplicar una rotacin a izquierdas. Para saber cual de las dos rotaciones
debemos aplicar miramos el valor de FE del nodo derecho. Pero en este caso, el valor de FE de
ese nodo es 0. Esto no quiere decir que no podamos aplicar ninguna de las rotaciones, por el
contrario, podremos aplicar cualquiera de ellas. Aunque por economa, lo razonable es aplicar
la rotacin simple.

Si aplicamos la rotacin simple, el resultado es:

Y aplicando la rotacin doble:
111


Del mismo modo, el valor de FE del nodo derecho podra haber sido 1 -1, en ese caso s est
determinado el tipo de rotacin a realizar.
El razonamiento es similar cuando se eliminan nodos y el resultado es que se obtiene un nodo
con FE de -2, en este caso se realizar una rotacin a derechas, y la rotacin depender del
valor de FE del nodo izquierdo al que muestra el desequilibrio. Si es 0 -1 haremos una
rotacin simple, si es 1, haremos una rotacin doble.
Tendremos entonces una tabla ms general para decidir la rotacin a aplicar:
FE nodo actual FE del nodo derecho FE del nodo izquierdo Rotacin
-2 No importa -1 RSD
-2 No importa 0 RSD
-2 No importa 1 RDD
2 -1 No importa RDI
2 0 No importa RSI
2 1 No importa RSI
Los rboles AVL siempre quedan equilibrados despus de una rotacin.
Esto puede comprobarse analizando los mtodos de rotacin que hemos estudiado, despus
de efectuada la rotacin, la altura del rbol cuya raz es el nodo rotado se mantiene, por lo
tanto, no necesitamos continuar el camino hacia la raz: sabemos que el rbol es AVL.
Algoritmos de AVL
De insercin de nodo
En general, la insercin de nodos en un rbol AVL es igual que en un rbol ABB, la diferencia es
que en un rbol AVL, despus de insertar el nodo debemos recorrer el rbol en sentido hacia la
raz, recalculando los valores de FE, hasta que se cumpla una de estas condiciones: que
lleguemos a la raz, que se encuentre un nodo con valor de FE de 2, -2, o que se llegue a un
nodo cuyo FE no cambie o decrezca en valor absoluto, es decir, que cambie de 1 a 0 de -1 a 0.
Podemos considerar que el algoritmo de insercin de nodos en rboles AVL es una ampliacin
del que vimos para rboles ABB.
112

De borrado de nodo
Lo mismo pasa cuando se eliminan nodos, el algoritmo es el mismo que en rboles ABB, pero
despus de eliminar el nodo debemos recorrer el camino hacia la raz recalculando los valores
de FE, y equilibrando el rbol si es necesario.
De recalcular FE
Ya comentamos ms atrs que para seguir el camino desde el nodo insertado o borrado hasta
el nodo raz tenemos dos alternativas:
1. Guardar en una pila los punteros a los nodos por los que hemos pasado para llegar al nodo
insertado o borrado, es decir, almacenar el camino.
2. Aadir un nuevo puntero a cada nodo que apunte al padre del nodo actual. Esto nos permite
recorrer el rbol en el sentido contrario al normal, es decir, en direccin a la raz.
Para calcular los nuevos valores de FE de los nodos del camino hay que tener en cuenta los
siguientes hechos:
- El valor de FE de un nodo insertado es cero, ya que siempre insertaremos nodos hoja.
- Si el nuevo valor de FE para cualquiera de los siguientes nodos del camino es cero,
habremos terminado de actualizar los valores de FE, ya que la rama mantiene su altura, la
insercin o borrado del nodo no puede influir en los valores de FE de los siguientes nodos
del camino.
- Cuando se elimine un nodo pueden pasar dos cosas. Siempre eliminamos un nodo hoja, ya
que cuando no lo es, lo intercambiamos con un nodo hoja antes de eliminarlo. Pero algunas
veces, el nodo padre del nodo eliminado se convertir a su vez en nodo hoja, y en ese caso
no siempre hay que dar por terminada la actualizacin del FE del camino. Por lo tanto,
cuando eliminemos un nodo, actualizaremos el valor de FE del nodo padre y
continuaremos el camino, independientemente del valor de FE calculado.
- A la hora de actualizar el valor de FE de un nodo, tenemos que distinguir cuando el
equilibrado sea consecuencia de una insercin o lo sea de una eliminacin.
Incrementaremos el valor de FE del nodo si la insercin fue en la rama derecha o si la
eliminacin fue en la rama izquierda, decrementaremos si la insercin fue en la izquierda
o la eliminacin en la derecha.
- Si en valor de FE es -2, haremos una rotacin doble a la derecha su el valor de FE del nodo
izquierdo es 1, y simple si es 1 0.
- Si en valor de FE es 2, haremos una rotacin doble a la izquierda su el valor de FE del
nodo izquierdo es -1, y simple si es -1 0.
- En cualquiera de los dos casos, podremos dar por terminado el recorrido del camino, ya
que la altura del rbol cuya raz es un nodo rotado no cambia.
- En cualquier otro caso, seguiremos actualizando hasta llegar al nodo raz.
113

De rotacin simple
A la hora de implementar los algoritmos que hemos visto para rotaciones simples tenemos dos
opciones: seguir literalmente los pasos de los grficos, o tomar un atajo, y hacerlo mediante
asignaciones. Nosotros lo haremos del segundo modo, ya que resulta mucho ms rpido y
sencillo.
Primero haremos las reasignaciones de punteros, de modo que el rbol resultante responda a
la estructura despus de la rotacin. Despus actualizaremos los punteros al nodo padre para
los nodos que han cambiado de posicin. Por ltimo actualizaremos los valores de FE de esos
mismos nodos.
Para la primera fase usaremos punteros auxiliares a nodo, que en el caso de rotacin a la
derecha necesitamos un puntero P al nodo con FE igual a -2. Ese ser el parmetro de entrada,
otro puntero al nodo izquierdo de P: Q. Y tres punteros ms a los rboles A, B y C.

En realidad, si nos fijamos en los grficos, los punteros a A y C no son necesarios, ya que ambos
conservan sus posiciones, A sigue siendo el subrbol izquierdo de Q y C el subrbol derecho de
P.
Usaremos otro puntero ms: Padre, que apunte al padre de P. Disponiendo de los punteros
Padre, P, Q y B, realizar la rotacin es muy sencillo:
if(Padre)
if(Padre->derecho == P) Padre->derecho = Q;
else Padre->izquierdo = Q;
else raz = Q;

// Reconstruir rbol:
P->izquierdo = B;
Q->derecho = P;
Hay que tener en cuenta que P puede ser la raz de un subrbol derecho o izquierdo de otro
nodo, o incluso la raz del rbol completo. Por eso comprobamos si P tiene padre, y si lo tiene,
114

cual de sus ramas apunta a P, cuando lo sabemos, hacemos que esa rama apunte a Q. Si Padre
es NULL, entonces P era la raz del rbol, as que hacemos que la nueva raz sea Q.
Slo nos queda trasladar el subrbol B a la rama izquierda de P, y Q a la rama derecha de P.
La segunda fase consiste en actualizar los punteros padre de los nodos que hemos cambiado
de posicin: P, B y Q.
P->padre = Q;
if(B) B->padre = P;
Q->padre = Padre;
El padre de P es ahora Q, el de Q es Padre, y el de B, si existe es P.
La tercera fase consiste en ajustar los valores de FE de los nodos para los que puede haber
cambiado.
Esto es muy sencillo, despus de una rotacin simple, los nicos valores de FE que cambian son
los de P y Q, y ambos valen 0.
// Rotacin simple a derechas
void RSD(Nodo* nodo) {
Nodo *Padre = nodo->padre;
Nodo *P = nodo;
Nodo *Q = P->izquierdo;
Nodo *B = Q->derecho;

if(Padre)
if(Padre->derecho == P) Padre->derecho = Q;
else Padre->izquierdo = Q;
else raz = Q;

// Reconstruir rbol:
P->izquierdo = B;
Q->derecho = P;

// Reasignar padres:
P->padre = Q;
if(B) B->padre = P;
Q->padre = Padre;

// Ajustar valores de FE:
P->FE = 0;
Q->FE = 0;
115

}
La rotacin a izquierdas es simtrica.
De rotacin doble
Para implementar las rotaciones dobles trabajaremos de forma anloga.
Primero haremos las reasignaciones de punteros, de modo que el rbol resultante responda a
la estructura despus de la rotacin. Despus actualizaremos los punteros al nodo padre para
los nodos que han cambiado de posicin. Por ltimo actualizaremos los valores de FE de esos
mismos nodos.
Para la primera fase usaremos punteros auxiliares a nodo, que en el caso de rotacin a la
derecha necesitamos un puntero P al nodo con FE igual a -2. Ese ser el parmetro de entrada,
otro puntero al nodo izquierdo de P: Q. Un tercero al nodo derecho de Q: R. Y cuatro punteros
ms a los rboles A, B, C y D.

En realidad, si nos fijamos en los grficos, los punteros a A y D no son necesarios, ya que ambos
conservan sus posiciones, A sigue siendo el subrbol izquierdo de Q y D el subrbol derecho de
116

P. Tambin en este caso usaremos otro puntero ms: Padre, que apunte al padre de P.
Disponiendo de los punteros Padre, P, Q, R, B y C, realizar la rotacin es muy sencillo:
if(Padre)
if(Padre->derecho == nodo) Padre->derecho = R;
else Padre->izquierdo = R;
else raz = R;

// Reconstruir rbol:
Q->derecho = B;
P->izquierdo = C;
R->izquierdo = Q;
R->derecho = P;
Ahora tambin hay que tener en cuenta que P puede ser la raz de un subrbol derecho o
izquierdo de otro nodo, o incluso la raz del rbol completo. Por eso comprobamos si P tiene
padre, y si lo tiene, cual de sus ramas apunta a P, cuando lo sabemos, hacemos que esa rama
apunte a R. Si Padre es NULL, entonces P era la raz del rbol, as que hacemos que la nueva
raz sea R.
Slo nos queda trasladar el subrbol B a la rama derecha de Q, C a la rama izquierda de P, Q a
la rama izquierda de R y P a la rama derecha de R.
La segunda fase consiste en actualizar los punteros padre de los nodos que hemos cambiado
de posicin: P, Q, R, B y C.
R->>padre = Padre;
P->padre = Q->padre = R;
if(B) B->padre = Q;
if(C) C->padre = P;
El padre de R es ahora Padre, el de P y Q es R, y el de B, si existe es Q, y el de C, si existe, es P.
La tercera fase consiste en ajustar los valores de FE de los nodos para los que puede haber
cambiado.
En las rotaciones dobles esto se complica un poco ya que puede suceder que el valor de FE de
R antes de la rotacin sea -1, 0 o 1. En cada caso, los valores de FE de P y Q despus de la
rotacin sern diferentes.
// Ajustar valores de FE:
switch(R->FE) {
case -1: Q->FE = 0; P->FE = 1; break;
case 0: Q->FE = 0; P->FE = 0; break;
117

case 1: Q->FE = -1; P->FE = 0; break;
}
R->FE = 0;
Si la altura de B es n-1 y la de C es n, el valor de FE de R es 1. Despus de la rotacin, la rama B
pasa a ser el subrbol derecho de Q, por lo tanto, la FE de Q, dado que la altura de su rama
izquierda es n, ser 0. La rama C pasa a ser el subrbol izquierdo de P, y dado que la altura de la
rama derecha es n, la FE de P ser -1.
Si la altura de B es n y la de C es n-1, el valor de FE de R es -1. Despus de la rotacin, la rama B
pasa a ser el subrbol derecho de Q, por lo tanto, la FE de Q, dado que la altura de su rama
izquierda es n, ser 0. La rama C pasa a ser el subrbol izquierdo de P, y dado que la altura de la
rama derecha es n, la FE de P ser 0.
Por ltimo, si la altura de B y C es n, el valor de FE de R es 0. Despus de la rotacin, la rama B
pasa a ser el subrbol derecho de Q, por lo tanto, la FE de Q, dado que la altura de su rama
izquierda es n, ser 0. La rama C pasa a ser el subrbol izquierdo de P, y dado que la altura de la
rama derecha es n, la FE de P ser 0.
// Rotacin doble a derechas
void RDD(Nodo* nodo) {
Nodo *Padre = nodo->padre;
Nodo *P = nodo;
Nodo *Q = P->izquierdo;
Nodo *R = Q->derecho;
Nodo *B = R->izquierdo;
Nodo *C = R->derecho;

if(Padre)
if(Padre->derecho == nodo) Padre->derecho = R;
else Padre->izquierdo = R;
else raz = R;

// Reconstruir rbol:
Q->derecho = B;
P->izquierdo = C;
R->izquierdo = Q;
R->derecho = P;

// Reasignar padres:
R->padre = Padre;
118

P->padre = Q->padre = R;
if(B) B->padre = Q;
if(C) C->padre = P;

// Ajustar valores de FE:
switch(R->FE) {
case -1: Q->FE = 0; P->FE = 1; break;
case 0: Q->FE = 0; P->FE = 0; break;
case 1: Q->FE = -1; P->FE = 0; break;
}
R->FE = 0;
}
Ejemplos de rbol AVL en C
No ha demasiado que aadir, construiremos los ejemplos de rboles AVL basndonos en los
ejemplos que hicimos para rboles binarios de bsqueda.
Slo tenemos que aadir cinco nuevas funciones: una para equilibrar el rbol, y cuatro para las
cuatro posibles rotaciones.
Adems, modificaremos ligeramente las funciones de insercin y borrado para que se equilibre
el rbol automticamente despus de cada insercin o borrado.
En la estructura de nodo para rbol AVL aadiremos un puntero al nodo padre y un valor
entero para almacenar el factor de equilibrio.
Cuando se inserten nuevos nodos hay que ajustar los valores de los nuevos miembros de nodo:
FE y padre. Seguidamente, llamaremos a la funcin "Equilibrar", salvo que el nodo insertado
sea el raz, ya que en ese caso no es necesario, evidentemente.
El procedimiento de equilibrar consiste en la implementacin del algoritmo que vimos en el
punto anterior:

/* Equilibrar rbol AVL partiendo de un nodo*/
void Equilibrar(Arbol *a, pNodo nodo, int rama, int nuevo) {
int salir = FALSE;

/* Recorrer camino inverso actualizando valores de FE: */
while(nodo && !salir) {
if(nuevo)
if(rama == IZQUIERDO) nodo->FE--; /* Depende de si aadimos ... */
else nodo->FE++;
119

else
if(rama == IZQUIERDO) nodo->FE++; /* ... o borramos */
else nodo->FE--;
if(nodo->FE == 0) salir = TRUE; /* La altura de las rama que
empieza en nodo no ha variado,
salir de Equilibrar */
else if(nodo->FE == -2) { /* Rotar a derechas y salir: */
if(nodo->izquierdo->FE == 1) RDD(a, nodo); /* Rotacin doble */
else RSD(a, nodo); /* Rotacin simple */
salir = TRUE;
}
else if(nodo->FE == 2) { /* Rotar a izquierdas y salir: */
if(nodo->derecho->FE == -1) RDI(a, nodo); /* Rotacin doble */
else RSI(a, nodo); /* Rotacin simple */
salir = TRUE;
}
if(nodo->padre)
if(nodo->padre->derecho == nodo) rama = DERECHO; else rama = IZQUIERDO;
nodo = nodo->padre; /* Calcular FE, siguiente nodo del camino. */
}
}
Las funciones para rotar son tambin sencillas, por ejemplo, la rotacin simple a la derecha:
/* Rotacin simple a derechas */
void RSD(Arbol *a, pNodo nodo) {
pNodo Padre = nodo->padre;
pNodo P = nodo;
pNodo Q = P->izquierdo;
pNodo B = Q->derecho;

if(Padre)
if(Padre->derecho == P) Padre->derecho = Q;
else Padre->izquierdo = Q;
else *a = Q;

/* Reconstruir rbol: */
P->izquierdo = B;
Q->derecho = P;

120

/* Reasignar padres: */
P->padre = Q;
if(B) B->padre = P;
Q->padre = Padre;

/* Ajustar valores de FE: */
P->FE = 0;
Q->FE = 0;
}
Y la rotacin doble a la derecha:
/* Rotacin doble a derechas */
void RDD(Arbol *raz, Arbol nodo) {
pNodo Padre = nodo->padre;
pNodo P = nodo;
pNodo Q = P->izquierdo;
pNodo R = Q->derecho;
pNodo B = R->izquierdo;
pNodo C = R->derecho;

if(Padre)
if(Padre->derecho == nodo) Padre->derecho = R;
else Padre->izquierdo = R;
else *raz = R;

/* Reconstruir rbol: */
Q->derecho = B;
P->izquierdo = C;
R->izquierdo = Q;
R->derecho = P;

/* Reasignar padres: */
R->padre = Padre;
P->padre = Q->padre = R;
if(B) B->padre = Q;
if(C) C->padre = P;

/* Ajustar valores de FE: */
switch(R->FE) {
121

case -1: Q->FE = 0; P->FE = 1; break;
case 0: Q->FE = 0; P->FE = 0; break;
case 1: Q->FE = -1; P->FE = 0; break;
}
R->FE = 0;
}
Ejemplos de arbol AVL en C++
Usando clases el ejemplo tambin est basado en el que hicimos para rboles binarios de
bsqueda, aadiendo las cinco funciones anteriores: Equilibrar, RSD, RSI, RDD y RDI. Adems
de las modificaciones en Insertar y Borrar.
Ejemplos de arbol AVL en C++ con plantillas
Usando plantillas no hay ms que generalizar el ejemplo de clases, cambiando en tipo de dato
a almacenar por el parmetro de la plantilla.

122

Programacin no numrica - Grafos
Definicin de grafo:
Desafortunadamente no existe una terminologa estandarizada en la teora de los grafos, por lo
tanto es oportuno aclarar que las presentes definiciones pueden variar ligeramente entre diferentes
publicaciones de estructura de datos y de teora de grafos, pero en general se puede decir que un
grafo como indica su nombre lo indica es la representacin (para nuestro caso) grfica de los datos
de una situacin particular, ejemplo:
Los datos contienen, en algunos casos, relaciones entre ellos que no es necesariamente jerrquica.
Por ejemplo, supongamos que unas lneas areas realizan vuelos entre las ciudades conectadas por
lneas como se ve en la figura anterior (ms adelante se presentaran grafos con estructuras de
datos); la estructura de datos que refleja esta relacin recibe el nombre de grafo.

Se suelen usar muchos nombres al referirnos a los elementos de una estructura de datos.
Algunos de ellos son elemento, tem, asociacin de tems, registro, nodo y objeto.
El nombre que se utiliza depende del tipo de estructura, el contexto en que usamos esa
estructura y quien la utiliza.
En la mayora de los textos de estructura de datos se utiliza el termino registro al hacer referencia
a archivos y nodo cuando se usan listas enlazadas, arboles y grafos.
Tambin un grafo es una terna G = (V,A,j ), en donde V y A son conjuntos finitos, y j es una
aplicacin que hace corresponder a cada elemento de A un par de elementos de V. Los elementos
de V y de A se llaman, respectivamente, "vrtices" y "aristas" de G, y j asocia entonces a cada
arista con sus dos vrtices. Esta definicin da lugar a una representacin grfica, en donde cada
vrtice es un punto del plano, y cada arista es una lnea que une a sus dos vrtices.
Si el dibujo puede efectuarse sin que haya superposicin de lneas, se dice que G es un grafo plano.
Por ejemplo, el siguiente es un grafo plano:
Los Angel es
Chi cago
Boston
Nueva York
Mi ami
Fi l adel fi a
Vuelos de lagunas aerolneas
123


GRAFOS EQUIVALENTES
Representacin de un grafo:
Existen dos formas de mantener un grafo G en la memoria de una computadora, una se llama
Representacin secuencial de G, la cual se basa en la matriz de adyacencia A; la otra forma, es
la llamada Representacin enlazada de G y se basa en listas enlazadas de vecinos.
Independientemente de la forma en que se mantenga un grafo G en la memoria de una
computadora, el grafo G normalmente se introduce en la computadora por su definicin formal:
Un conjunto de nodos y un conjunto de aristas
- Representacin secuencial de un grafo:
Considere el grafo siguiente G:

y suponga que los nodos se mantienen en memoria en un array DATOS tal como sigue:
DATOS: X, Y, Z, W
Para hallar la matriz de adyacencia A del grafo G, tenemos que tomar en cuenta que los
nodos estn normalmente ordenados de acuerdo con la forma en que aparecen en memoria; o
sea, asumimos que u1 = X, u2 = Y, u3 = Z, y u4 = W, la matriz de adyacencia A de G seria
la siguiente:
|
|
|
|
|
.
|

\
|
= A
0 1 0 0
1 0 1 0
1 0 0 0
1 1 1 0

Aqu oi j = 1 si hay una arista ui a uj ; si no oi j = 0.
As entonces para hallar la matriz de camino P de G mediante las potencias de la matriz de
adyacencia A, como G tiene cuatro nodos se calcula
:
4
, ,
4 3 2 4 3 2
B
y ,
A A A A A A A
+ + + =
x
y
z
w
124


1 0 1 0
1 1 0 0
0 1 0 0
2 1 1 0
2
|
|
|
|
|
.
|

\
|
= A
|
|
|
|
|
.
|

\
|
= A
1 1 0 0
1 1 1 0
1 0 1 0
2 2 1 0
3

|
|
|
|
|
.
|

\
|
= A
1 1 1 0
2 1 1 0
1 1 0 0
3 2 2 0
4
|
|
|
|
|
.
|

\
|
=
5 3 2 0
5 3 3 0
3 2 1 0
8 6 5 0
4
B

Por lo tanto la matriz de caminos P se obtiene ahora haciendo pi j = 1 siempre que haya una
entrada positiva en la matriz B4 . as
|
|
|
|
|
.
|

\
|
=
1 1 1 0
1 1 1 0
1 1 1 0
1 1 1 0
P
La matriz de caminos muestra que no hay camino de u1 a u2 de hecho, no hay camino de
ningn nodo a u1 por tanto, G no es fuertemente conexo.
- Representacin enlazada de un grafo:
Un grafo G se guarda en memoria como sigue:
NODO A B E D C
SIG 7 4 0 6 8 0 2 3
ADY 1 2 5 7 9
1 2 3 4 5 6 7 8
PRINCIPIO = 1, NDISP = 5
DEST 2 6 4 6 7 4 4 6
ENL 10 3 6 0 0 0 0 4 0 0
1 2 3 4 5 6 7 8 9 10
ADISP = 8
Para dibujar el respectivo grafo G, primero debemos buscar todos los vecinos de cada
NODO[K] recorriendo su lista de adyacencia que tiene el puntero de adyacencia ADY[J].
Esto da como resultado:
A: 2(B) y 6(D)
B: 6(D), 4(E) y 7(C)
C: 4(E)
D: 4(E)
E: 6(D)






125


Entonces procedemos a dibujar el diagrama del grafo como sigue:

Sea G un grafo dirigido con m nodos. La representacin secuencial de G en la memoria, o sea, la
representacin de G por su matriz de adyacencia A, tiene unas cuantas desventajas importantes.
En primer lugar, puede ser difcil insertar y eliminar nodos de G, esto es por que el tamao de A
debera ser cambiado y los nodos deberan ser reordenados, as que habra muchos cambios en la
matriz A; ms aun, si el numero de aristas es O(m) o O(m log2 m), entonces la matriz A estar
desperdiciada (contendr muchos ceros); por tanto, se desperdiciar una gran cantidad de espacio;
entonces G normalmente se representa en memoria por una representacin de listas enlazada,
tambin llamada estructura de adyacencia.
Considere el grafo G de la figura siguiente y su respectiva tabla de adyacencia, donde se muestra
cada nodo de G seguido por la lista de nodos adyacentes, tambin llamados sucesores o vecinos.

Para apreciar aun ms esta situacin, podemos tambin usar un diagrama esquemtico de la
representacin enlazada de G en la memoria, especficamente, la representacin enlazada
A
C
D E
B
Li sta de
Adyacenci a
A: B,C,D
B: C
C:
D: C,E
E: C
D
A
B
E
C
A
B
C X
D
E X X
X
X
X
PRINCIPIO
Li sta NODO Li sta ARISTA
126

contendr dos listas (o archivos), una lista de nodos NODO y una lista de aristas ARISTA, tal
como sigue:
Cada elemento de la lista NODO corresponder a un nodo de G y ser un registro de la forma:

NODO SIG ADY

Aqu NODO ser el nombre o valor clave del nodo, SIG ser un puntero al siguiente nodo de la
lista NODO y ADY ser un puntero al primer elemento de la lista de adyacencia del nodo, que se
mantiene en la lista ARISTA; el rea restante indica que puede haber otra informacin en el
registro, tal como el grado de entrada GraEnt del nodo, el grado de salida GraSal del nodo, el
ESTADO del nodo durante la ejecucin de un algoritmo, etc.
Adicional a esto, cada elemento de la lista ARISTA corresponder a una arista de G y ser un
registro de la forma:
DEST ENL


Donde el campo DEST apuntar a la posicin en la lista NODO del nodo destino o terminal de
la arista, el campo ENL enlazar juntas las aristas con el mismo nodo inicial, o sea, los nodos con
la misma lista de adyacencia, y el campo restante indica que puede existir otra informacin en el
registro correspondiente a la arista, tal como un campo ARIS conteniendo los datos etiquetados
de la arista cuando G es un grafo con etiquetas, un campo PESO conteniendo el peso de la arista
cuando G es un grafo con peso, etc.
Tecnicas bsicas de busqueda
BSQUEDA EN GRAFOS

Para efectuar una bsqueda de los vrtices de un grafo, se pueden emplear dos estrategias
diferentes:
Bsqueda en profundidad (BEP): Se comienza en cualquier vrtice y en cada paso se avanza a
un nuevo vrtice adyacente siempre que se pueda. Cuando todos los adyacentes a X hayan sido
visitados, se retrocede al vrtice desde el que se alcanz X y se prosigue. As se consigue etiquetar
(visitar) todos los vrtices de la componente conexa en que se encuentre el vrtice inicial.
Esta tcnica se utiliza cuando necesitamos encontrar respuesta a un problema sobre un grafo sin
condiciones de optimizacin.
La idea en general de la bsqueda en profundidad comenzando en un nodo A es la siguiente:
Primero examinamos el nodo inicial A. Luego examinamos cada nodo N de un camino P que
comience en A; a sea, procesamos un vecino de A, luego un vecino de un vecino de A y as
sucesivamente, hasta llegar a un punto muerto o final del camino P, y de aqu volvemos atrs
por P hasta que podamos continuar por otro camino P y as sucesivamente.
Este algoritmo es similar al del recorrido inorden de un rbol binario, y tambin a la forma en
que se debe pasar a travs de un laberinto. Observe que se hace uso una pila en lugar de una
cola, y este es el detalle fundamental que hace la diferencia para realizar la bsqueda en
profundidad.

Algoritmo para la bsqueda en profundidad:
Este algoritmo realiza la bsqueda en profundidad el grafo G comenzando en un nodo A.

127



1. Inicializar todos los nodos al estado de preparado (ESTADO=1)
2. Meter el nodo inicial A en la pila y cambiar su estado a estado de espera (ESTADO=2).
3. Repetir los pasos 4 y 5 hasta que la pila este vacia.
4. Sacar el nodo N en la cima de la pila. Procesar el nodo N y cambiar su
estado al de procesado (ESTADO=3).
5. Meter en la pila todos los vecinos de N que estn en estado de
preparados (ESTADO=1) y cambiar su estado a estado de espera
(ESTADO=2).
[ fin de bucle del paso 3 ]
6. Salir.

nota: tomado del libro Estructura de datos, serie schaum Mcgraw-Hill, pagina: 337, capitulo: 8
Grafos y sus aplicaciones, autor: Seymour Lipschutz

Bsqueda en anchura (BEA): A diferencia con la BEP ahora se visitan todos los vecinos de un
vrtice antes de pasar al siguiente. Por tanto no hay necesidad de retroceder. Una vez
etiquetados todos los vecinos de un vrtice X, se contina con el primer vrtice alcanzado
despus de X en la bsqueda.

Esta tcnica se utiliza para resolver problemas en los que se pide hallar una solucin ptima
entre varias. En general la bsqueda en anchura comenzando de un nodo de partida A es la
siguiente:

Primero examinamos el nodo de partida A.

Luego examinamos todos los vecinos de A. Luego examinamos todos los vecinos de los vecinos
de A y as sucesivamente. Con el uso de una cola, garantizamos que ningn nodo sea procesado
ms de una vez y usando un campo ESTADO que nos indica el estado actual de los nodos.

Algoritmo para la bsqueda en anchura:
Este algoritmo realiza la bsqueda en anchura en un grafo G comenzando en un nodo de partida
A.

1. Inicializar todos los nodos al estado de preparados (ESTADO=1).
2. Poner el nodo de partida A en la COLA y cambiar su estado a espera (ESTADO=2).
3. Repetir pasos 4 y 5 hasta que COLA est vaca.
4. Quitar el nodo del principio de la cola, N. Procesar N y cambiar su
estado a procesado (ESTADO=3).
5. Aadir a COLA todos los vecinos de N que estn en estado de
preparados (ESTADO=1) y cambiar su estado al de espera
128

(ESTADO=2).
[ fin del bucle del paso 3 ]
6. Salir.

nota: tomado del libro Estructura de datos, serie schaum Mcgraw-Hill, pagina: 334 - 335,
capitulo: 8 Grafos y sus aplicaciones, autor: Seymour Lipschutz

Arboles de recubrimiento mnimo (bsqueda del camino ms corto):

CAMINOS MINIMOS EN GRAFOS

Para lograr el propsito del recorrido mnimo dentro de un grafo G, es necesario para nuestro
caso en particular (puesto que no es la nica tcnica existente) la utilizacin del algoritmo de
WARSHALL para el camino mnimo, el cual se expresa de la forma siguiente:
Sea G un grafo con m nodos, u1 , u2 , ..., um suponga que queremos encontrar la matriz de
caminos P para el grafo G. WARSHALL dio un algoritmo para este propsito que es mucho ms
eficiente que calcular las potencias de la matriz de adyacencia A y aplicar la proposicin:

A A A A
m 3 2
. . . + + + + =
Bm

Donde sea A la matriz de adyacencia y P = Pij la matriz de caminos de un grafo G entonces, Pij
= 1 si y solo s hay un numero positivo en la entrada ij de la matriz

Este algoritmo de WARSHALL se usa para calcular el camino mnimo y existe un algoritmo
similar para calcular el camino mnimo de G cuando G tiene peso.

Algoritmo de WARSHALL:
Un grafo dirigido G con M nodos est en memoria por su matriz adyacente A, este algoritmo
encuentra la matriz de caminos (Booleana) P del grafo G.

1. [ Inicializar P ] repetir para I, J =1, 2, ... M:
si A[ I, J ]=0, entonces: hacer P[ I, J ]:=0;
si no: hacer P[ I, J ]:=1.
[ fin de bucle ]
2. [ Actualizar P ] repetir paso 3 y 4 para K=1, 2, ..., M:
3. repetir paso 4 para I=1, 2, ..., M:
4. repetir para J=1, 2, ..., M:
hacer P[ I, J ]:= P[ I, J ] V ( P[ I, J] ^ P[ K, J ]).
[ fin de bucle ]
[ fin de bucle paso 3 ]
[ fin de bucle paso 2 ]
5. Salir.


129

nota: tomado del libro Estructura de datos, serie schaum Mcgraw-Hill, pagina: 322, capitulo: 8
Grafos y sus aplicaciones, autor: Seymour Lipschutz


Algoritmo de matriz de camino mnimo:

Cuando se trata de un grafo con peso G de M nodos est memoria mediante su matriz de peso
W; este algoritmo encuentra la matriz Q tal que [ I, J ] es la longitud del camino mnimo del nodo
VI al nodo VJ . INFINITO es un nmero muy grande y MIN es la funcin del valor mnimo.

1. [ Inicializar Q ] repetir para I, J=1, 2, . . ., M:
si W [ I, J ] = 0, entonces: hacer Q [ I, J ]:= INFINITO;
si no: hacer Q [ I, J ] := W [ I, J ].
[ fin de bucle ]
2. [ Actualizar Q ] repetir pasos 3 y 4 para K=1, 2, . . ., M:
3. repetir paso 4 para I = 1, 2, . . ., M:
4. repetir para J = 1, 2, . . ., M:
hacer Q [ i, J ] := MIN(Q [ i, J ]+ Q [ i, K ]+ Q [ K, J ]).
[ fin de bucle ]
[ fin de bucle del paso 3 ]
[ fin de bucle del paso 2 ]
5. Salir.

nota: tomado del libro Estructura de datos, serie schaum Mcgraw-Hill,
pagina: 324, capitulo: 8 Grafos y sus aplicaciones, autor: Seymour Lipschutz

Enunciado para ejemplo:

Dado un grafo simple no dirigido, conexo y ponderado de n nodos etiquetados con los nmeros
naturales desde el 1 hasta el n, se numeran los ejes desde 1 hasta m de acuerdo con el orden.
Dados a continuacin dos nodos cualesquiera, se trata de encontrar el camino ms corto entre
ambos nodos, utilizando el algoritmo de Dijkstra.

Entrada: En la primera lnea, un nmero natural que indica el nmero de casos que se van a
plantear. Para cada caso, una lnea con el nmero de nodos n del grafo, y la representacin
decimal del mismo (entero menor que
|
|
.
|

\
|
2
2
n
) separados por un blanco. En la siguiente lnea,
separados por blancos, m nmeros naturales que representan los pesos de los ejes del grafo. En
la siguiente lnea, otro nmero natural p nos dice cuntos pares de nodos se van a proponer, y a
continuacin aparecen en lneas diferentes y separados por blancos todas estas parejas.

Salida: Para cada uno de los casos propuestos, el fichero de salida contendr una lnea indicando
el caso de que se trata en la forma Grafo # con el smbolo # sustituido por el nmero del caso.
Las siguientes m lneas contendrn la lista de adyacencias del grafo en la forma:

130

No.delnodo Nodoadyacente pesodeleje Nodoadyacente Pesodeleje...

Siempre separando con blancos y con los nodos adyacentes en orden creciente de nmero. A
continuacin, p lneas que resuelven las p parejas de nodos planteadas, componiendo cada lnea
en la forma:

Pesodelcamino... ...nodosintermedios... ...nodofinal...

Ejemplo de Entrada:
2
4 49
53 82 53
2
1 2
1 3
8 14728196
81 48 30 64 71 13 91 10 65
3
2 1
4 1
8 1

Ejemplo de Salida:
Grafo 1
1 2 53
2 1 53 4 82
3 4 53
4 2 82 3 53
53 1 2
188 1 2 4 3
Grafo 2
1 4 81
2 6 48 7 30 8 64
3 4 71 6 13
4 1 81 3 71 8 91
5 6 10 7 65
6 2 48 3 13 5 10
7 2 30 5 65
8 2 64 4 91
213 2 6 3 4 1
81 4 1
172 8 4 1

Algoritmo de Dijkstra: Este algoritmo construye el rbol de caminos de longitud mnima entre
un vrtice fijado V y los restantes vrtices en un grafo ponderado.

Observaciones:
1) Los pesos de las aristas deben ser no negativos.
131

2) El algoritmo de Dijkstra NO proporciona un rbol generador mnimo.

Ordenacin Topolgica:
Hasta recientemente todos los trabajos sobre Topologa (Digital principalmente) se basaban en
un enfoque de Teora de Grafos. Este enfoque presenta, sin embargo, el problema de determinar
la relacin de adyacencia ms razonable en Zn. Actualmente existen enfoques alternativos
basados en nociones de Topologa General. En este caso haremos una introduccin a algunos de
estos enfoques.

Topologa definicin:

1) Rama de la matemtica que estudia las propiedades del espacio que son invariantes por
homeomorfismos. Se trata de propiedades no mtricas, es decir, de propiedades cualitativas, y
no cuantitativas, lo que la distingue de la geometra comn. Se la suele denominar "geometra
dbil" o "geometra del caucho". Por ejemplo, una circunferencia es topolgicamente
equivalente a un cuadrado, por ms que sus propiedades mtricas sean diferentes

2) Una topologa en un conjunto X es una familia de subconjuntos de X que satisface ciertos
axiomas (ver espacio topolgico).

En esta seccin estudiaremos las diferentes estrategias que se han planteado principalmente
motivadas por problemas en el rea del reconocimiento de formas para dotar a la digitalizacin
D de un conjunto, de una estructura, no necesariamente explcitamente topolgica, en trminos
de la cual formular propiedades de D relacionadas con las propiedades de la imagen original.

Las imgenes 2-dimensionales son las mas ampliamente estudiadas, aunque ltimamente las 3-
dimensionales estn siendo muy utilizadas. Tambin se utilizan imgenes 4-dimensionales para
representar imgenes 3-dimensionales en movimiento.

De las estrategias planteadas, la primera y las ms utilizada es la introducida por Azriel Rosenfeld
en 1970. Se basa en la nocin de adyacencia entre puntos de Zn (adems de Zn tambin
considera en ocasiones los centros de una teselacin del plano por hexgonos). Su enfoque
descansa principalmente en nociones de Teora de Grafos.

Desde entonces la Topologa Digital ha proporcionado los fundamentos tericos para
importantes operaciones de procesamiento de imagen, como recuento de objetos,
adelgazamiento de imgenes, deteccin de bordes y relleno de contornos. El adelgazamiento de
imgenes es una operacin de pre procesamiento en reconocimiento de formas. Su objetivo es
reducir el conjunto de puntos de la imagen sin alterar la topologa de la misma.

Ordenacin topolgica:
132

Suponga que S es un grafo tal que cada nodo vi de S representa una tarea y cada arista ( u, v )
significa que la finalizacin de la tarea u es un pre-requisito para que comience la tarea v.
Suponga que tal grafo S contiene un ciclo tal que:

P=( u, v, w, u )
Esto significa que no podemos empezar v hasta completar u, no podemos empezar w hasta
terminar v y no podemos empezar u hasta completar w. As no podemos completar ninguna
tarea del ciclo. Por tanto, un grafo S as, que representa tareas y relaciones de precedencia, no
puede tener ciclos.

Ahora suponga que S es un grafo sin ciclos, considere la relacin < sobre S definida como sigue:
u < v si existe un camino de u a v

Esta relacin tiene las siguientes tres propiedades:
1. Para cada elemento u de S, tenemos que u < u. ( Irreflexivilidad )
2. Si u < v, entonces v < u. ( Asimetra )
3. Si u < v y v < w, entonces u < w. ( Transitividad )

Tal relacin < sobre S se llama ordenacin parcial de S, y S con tal ordenacin se llama conjunto
parcialmente ordenado o conjunto po. As, un grafo S sin ciclos se puede considerar un conjunto
parcialmente ordenado.

Por lo tanto, puede tambin suponer que si S es un conjunto parcialmente ordenado con la
ordenacin parcial denotada por <, entonces S se puede considerar un grafo cuyos nodos son
los elementos de S y cuyas aristas estn definidas como sigue:

( u, v ) es una arista en S si u < v

Ms aun, se puede demostrar que un conjunto S parcialmente ordenado, considerado como un
grafo, no tiene ciclos.

Como ejemplo podemos plantear que: sea S el grafo de la figura, observe que S no tiene ciclos.
As S se puede considerar un conjunto parcialmente ordenado. Note que G < C, ya que existe
un camino desde G hasta C. Similarmente, B < F y B < C. Por otro lado B no es menor que A, ya
que no existe camino de B a A, al igual que A no es menor que B.
133


Por lo tanto; sea S un grafo dirigido sin ciclos (o conjunto parcialmente ordenado). Una
ordenacin topolgica T de S es una ordenacin lineal de los nodos de S que preserva la
ordenacin parcial de S original, o sea, que si u < v en S (si hay un camino de u a v en S), entonces
u va delante de la v el la ordenacin lineal T, este se muestra en la siguiente figura, donde se
incluyen las aristas para indicar que concuerdan con la direccin de la ordenacin lineal.


Informacin adicional sobre Topologa:
Topologa combinatoria:
G
B
A
E
F
C
D
Lista de
Adyacencia
A: C
B: D, F
C:
D: C
E: E
F:
G: A, F
G B A D F C
B D G A F E C
E
C
Dos model os de ordenacin topol gi ca.
134

Rama de la topologa que reduce el estudio de curvas y superficies a ciertos esquemas
determinados por polgonos curvilneos, evitando de esta forma pensarlas como conjuntos de
puntos, como lo hace la topologa conjuntista. El tratamiento combinatorio es ms cercano al
lgebra, y reduce el concepto de homeomorfismo a unas pocas reglas que permiten decidir
cundo dos esquemas combinatorios son equivalentes.

Topologa inducida:
Dado un subconjunto A de un espacio topolgico X, se llama topologa inducida a la topologa
definida en A que toma como abiertos a todos los conjuntos de la forma U A, en donde U es
un abierto de X. En estas condiciones, se dice que A es un subespacio de X.

Topologa usual:
La topologa usual del espacio ndimensional (Rn) tiene como abiertos bsicos a las bolas n
dimensionales (abiertas). Es decir, un conjunto de Rn es abierto si y slo si es unin de cierto
nmero de bolas abiertas. Equivalentemente, diremos que A es abierto si y slo si para todo
punto x A existe una bola B contenida en A tal que x B (A es entorno de x).

Toro:
Se llama as a la superficie de revolucin engendrada por la rotacin de una circunferencia en
torno a un eje que no la toque en ninguno de sus puntos. Si bien esta definicin es geomtrica,
las propiedades topolgicas del toro son de gran importancia. En especial, la propiedad de tener
un asa, o agujero, que determina que existan en el toro lazos no reducibles. Un importante
teorema de la topologa combinatoria asegura que toda superficie cerrada y orientable es un
toro con n agujeros. El caso n = 0 corresponde obviamente a la esfera, si se la piensa como un
"toro sin agujeros", y el caso n = 1 es el toro usual. Si bien la definicin habitual del toro lo
presenta como una superficie sumergida en el espacio tridimensional, es fcil ver que es
homeomorfo al producto cartesiano de dos circunferencias, sumergido en R4 (espacio
cuatridimensional). Es decir, la definicin topolgica del toro es: T2 = S1 S1. Esto permite
generalizar, y definir al toro ndimensional como el producto cartesiano de n circunferencias, es
decir: Tn = S1 ... S1.

En la topologa combinatoria, el toro bidimensional se define identificando dos a dos los lados
opuestos de un rectngulo, como muestra la figura:








Algoritmo de ordenacin topolgica:

El siguiente algoritmo encuentra una ordenacin topolgica T de un grafo S sin ciclos.
1. Encontrar el grado de entrada GraEnt(N) de cada nodo N de S (se puede hacer recorriendo
cada lista de adyacencia)
b
b
a a
135

2. Poner en una cola todos los nodos con grado de entrada nulo.
3. Repetir los pasos 4 y 5 hasta que la cola est vaca.
4. Quitar el nodo N al frente de la cola (haciendo Frente:=Frente + 1)
5. Repetir lo siguiente para cada vecino M de N:
Hacer GraRnt(M):= GraEnt(M) 1 (esto elimina la arista de N a M)
si GraEnt(M)=0, entonces: Aadir M al final de la cola.
[ fin de bucle paso 5 ]
[ fin de bucle paso 3 ]
6. Salir.

nota: tomado del libro Estructura de datos, serie schaum Mcgraw-Hill,
pagina: 340, capitulo: 8 Grafos y sus aplicaciones, autor: Seymour Lipschutz

136





A N E X O


TEMAS AFINES Y


COMPLEMENTARIOS

137

Caminos y Conexin: Un camino en un grafo es una sucesin de vrtices y aristas de la forma
v0 a1 v1 a2...vk-1 ak vk donde la arista ai une los vrtices vi-1 y vi. ste es un camino de v0 a vk,
de longitud k, siendo v1,...,vk-1 los vrtices interiores del camino. Si v0=vk decimos que el camino
es cerrado. Un ciclo es un camino cerrado con todas sus aristas distintas y con todos sus vrtices
distintos (salvo, claro es, los extremos v0=vk).

Propiedades:

1) El n de caminos de longitud k de vi a vj es el elemento ij de la matriz M(G)k.
2) Un grafo G es bipartido G no tiene ciclos de longitud impar.
3) Se llama distancia entre dos vrtices u y v, a la longitud mnima de un camino que conecta
dichos vrtices y se designa por d(u,v).
4) Se llama dimetro de G a la mxima distancia entre dos vrtices de G, diam(G).
Un grafo es conexo si para cada par de vrtices u y v existe un camino de u a v. Si G es un grafo
no conexo (o disconexo), cada uno de sus subgrafos conexos maximales se llama componente
conexa de G.

Un vrtice v se llama vrtice-corte (o punto de articulacin) de G si el grafo G-{v} tiene ms
componentes conexas que G.

Una arista a de un grafo G se llama puente si G-{a} tiene ms componentes conexas que G.

Conexo: un espacio topolgico X se dice conexo si no contiene ningn subconjunto abierto y
cerrado, excepto y X. Intuitivamente, un conjunto es conexo cuando no est compuesto por
dos o ms partes separadas. Una definicin mucho ms fcil de entender es la de conjunto
arcoconexo. Sin embargo, se puede probar que ambas nociones no coinciden: todo conjunto
arcoconexo es conexo, pero la recproca es falsa. En la topologa usual, todo abierto conexo es
tambin arcoconexo.

Espacio ndimensional: se llama espacio ndimensional usual al conjunto Rn, construido como
el producto cartesiano R ... R (n veces), en donde R es el conjunto de los nmeros reales. Los
elementos de Rn se piensan como vectores de n coordenadas. El vector nulo es aquel cuyas
coordenadas son todas 0, y se lo llama "origen" o "centro de coordenadas". Por ejemplo, el plano
R2 es el conjunto de todos los pares ordenados (x,y) en donde sus dos coordenadas x, y son
nmeros reales cualesquiera, y su origen es el vector (0,0). A este espacio se le suele asignar una
topologa, conocida como topologa usual de Rn.


Espacio topolgico: se llama espacio topolgico a un conjunto X provisto de una topologa, es
decir, una familia de subconjuntos de X, llamados abiertos, que satisfacen los siguientes axiomas:
138


1. y X son conjuntos abiertos 2.La interseccin de un nmero finito de conjuntos abiertos es
un conjunto abierto 3.La unin de cualquier nmero de conjuntos abiertos es un conjunto
abierto

Se desprende de la definicin que en cualquier espacio topolgico X los conjuntos y X son a la
vez abiertos y cerrados (ver tambin: topologa usual)

Funcin continua: dados dos espacios topolgicos X e Y, la funcin f:X Y se dice continua en
un punto a X si dado un entorno V del punto f(a) e Y, existe un entorno U de a tal que f(U) V,
es decir, f(x) e V para todo x e U. Esto puede expresarse mediante la nocin de lmite: f es
continua en a si

En la topologa usual, la nocin de continuidad en a equivale a la propiedad de que si {xn} es
cualquier sucesin en X que converge a a, entonces la sucesin {f(xn)} converge a f(a).
Intuitivamente, podemos decir: "cuanto ms se acerca xn a a, ms se acerca f(xn) a f(a) ". f se
dice continua cuando es continua en todos sus puntos. Equivalentemente, f es continua si y slo
si la imagen inversa de un abierto cualquiera es un conjunto abierto.

Grupo fundamental: dado un espacio topolgico X, se puede formar el conjunto de todos los
lazos en X que salen de un cierto punto, considerando como equivalentes a dos lazos que se
puedan superponer mediante una homotopa (es decir, tales que se pueda deformar a uno de
ellos en forma continua hasta obtener el otro). A dicho conjunto se le asigna una estructura
(algebraica) de grupo, lo que determina el llamado grupo fundamental de X. Se trata de un
invariante topolgico muy til. Por ejemplo, el grupo fundamental de una circunferencia es Z, el
conjunto de los nmeros enteros (Z = {..., - 3, - 2, - 1, 0, 1, 2, 3, ...}), hecho que resulta claro pues
todo lazo cerrado sobre la circunferencia est determinado unvocamente por la cantidad de
vueltas, y el sentido en que se las recorre. El grupo fundamental de un toro es Z Z, pues en este
caso deben tenerse en cuenta las vueltas dadas "alrededor" del agujero, y tambin "a travs"
del mismo. Este resultado es, claro est, coherente con el hecho de que el toro puede pensarse
como el producto cartesiano de dos circunferencias (ver: toro).

Homeomorfismo: se llama homeomorfismo entre dos espacios topolgicos X e Y a una funcin
f: X Y que resulte biunvoca y bicontinua, es decir:
f es "uno a uno" (biunvoca), lo que significa que para cada elemento x e X existe un nico y e Y
tal que f(x) = y y viceversa. Esto permite definir la funcin inversa, f-
1
:Y X
f y f-
1
son continuas (f es bicontinua)

139

La nocin de homeomorfismo responde a la idea intuitiva de "deformacin", y determina cierta
clase de equivalencia: dos espacios homeomorfos tienen las mismas propiedades topolgicas.

Homologa: invariante topolgico que asocia a cada espacio topolgico una estructura
algebraica llamada "complejo". Como invariante, tiene mayor precisin que el grupo
fundamental, aunque su definicin y clculo resultan ms complicados.

Homotopa: dados dos espacios topolgicos X e Y, una homotopa es una funcin continua h:X
[ a,b] Y, en donde [ a,b] es un intervalo cerrado. Por comodidad, siempre supondremos que
[ a,b] es el intervalo [ 0,1] . Se puede interpretar intuitivamente la nocin de homotopa
pensando al [ 0,1] como un intervalo de tiempo, y en consecuencia h representa una cierta
deformacin a partir del instante inicial t = 0, hasta llegar a t = 1 pasando por cada instante t fijo.

Identificar: operacin topolgica que responde a la nocin intuitiva de "pegar". Consiste en
definir alguna relacin de equivalencia entre puntos de un espacio topolgico X, lo que permite
definir el espacio cociente. Por ejemplo, si se identifican uno a uno los puntos de dos lados
opuestos de un rectngulo, se obtiene una superficie tubular similar a un "cinturn", o una
porcin de cilindro. En cambio, si esta identificacin se efecta orientando a los dos lados en
sentidos opuestos, se obtiene una Banda de Mbius.

Interior: dado un conjunto A, si llama interior de A al mayor abierto contenido en A. Notacin:
A = interior de A . Por definicin, es claro que un conjunto es abierto si y slo si coincide con su
interior. El interior de A se puede pensar como el conjunto de puntos de A que no pertenecen a
su frontera, es decir: A = A - Fr(A).

Intervalo: dados dos nmeros reales a < b, se llama intervalo entre a y b al conjunto de puntos
de la recta contenidos entre a y b. Caben cuatro posibilidades, segn se incluya o no a cada uno
de los extremos:

1. (a,b) = { x R / a < x < b } (intervalo abierto)
2. [a,b) = { x R / a x < b } (intervalo semiabierto)
3. (a,b] = { x R / a < x b } (intervalo semiabierto)
4. [a,b] = { x e R / a s x s b } (intervalo cerrado)

Tambin se definen los siguientes intervalos no acotados: ( a,+ ), [ a,+ ),

( , b ), ( , b ] . Por ejemplo, ( a, + ) = { x e R / x > a }. Los smbolos + y responden
nicamente a una mayor simplicidad en la escritura, ya que no se trata de nmeros reales. Por
esa razn, todo intervalo no acotado es abierto en su "extremo infinito". Obviamente, el
140

intervalo ( ,+ ) equivale a toda la recta R. Es fcil ver que cualquier intervalo abierto es
homeomorfo a R.

Invariante: se llama invariante topolgico a aquellas propiedades de un espacio topolgico que
permanecen cuando se le aplica un homeomorfismo. Algunos invariantes muy conocidos son la
compacidad, la conexin, el grupo fundamental, la homologa, etc. En general, cada teora
matemtica tiene sus propios invariantes: as, los invariantes geomtricos son las propiedades
que conserva una figura cuando se le aplica una rotacin o una traslacin (movimientos rgidos).

Matrices: la matriz de adyacencia de un grafo G con n vrtices {v1,...,vn} es la matriz nxn ,
M(G)=(aij), donde aij es el n de aristas que unen vi con vj. La matriz de incidencia de un grafo
simple G con n vrtices {v1,...,vn} y k aristas {e1,...,ek} es la matriz nxk, I(G)=(bij), donde bij=1 si
vi es incidente con ej y bij=0 en caso contrario.

Plano proyectivo: espacio definido en geometra proyectiva, de acuerdo con la idea intuitiva de
agregar al plano euclidiano un "horizonte", de modo tal que dos rectas paralelas determinen un
(nico) punto. Las rectas resultan entonces cerradas, es decir, homeomorfas a una
circunferencia, hecho relacionado adems con la propiedad que tiene el plano proyectivo de ser
compacto. Al horizonte, que tambin es una recta, se lo suele llamar "recta impropia", pues est
compuesta de puntos impropios, tambin llamados puntos "del infinito".

En la geometra proyectiva los conceptos de "punto" y "recta" son duales, puesto que pueden
intercambiarse. Por ejemplo, el enunciado: "Dos puntos determinan una nica recta" se
transforma en su dual "Dos rectas determinan un nico punto", que tambin es vlido, aunque
no lo es en la geometra euclidiana.

Poliedro topolgico: generalizacin de la nocin geomtrica de poliedro. Consiste en un sistema
formado por un nmero finito de polgonos topolgicos sujetos a ciertas condiciones, entre las
cuales se tiene, por ejemplo, que dos polgonos distintos no tienen puntos interiores comunes,
que los lados de los polgonos del sistema coinciden dos a dos, etc.

Polgono topolgico: generalizacin de la nocin geomtrica de polgono. Consiste en tomar
cierto nmero finito n > 1 de puntos en una circunferencia. Los arcos as determinados sern los
lados, y los puntos se llamarn vrtices del polgono. El polgono estar formado entonces, por
el conjunto de lados y la regin interior a la circunferencia.
Recorridos en un Grafo: Un camino euleriano en un grafo es un camino que contiene a todas las
aristas del grafo exactamente una vez. Un grafo es euleriano si contiene un camino euleriano
cerrado.

Teorema: Un grafo conexo G es euleriano Todos los vrtices de G tienen grado par.
141

Consecuencia: Un grafo conexo G tiene un camino euleriano no cerrado G tiene, exactamente,
dos vrtices de grado impar.

Algoritmo de Fleury (para construir un camino euleriano cerrado en un grafo euleriano).

Paso 1.- Se comienza en un vrtice cualquiera v0 .
Paso 2.- Si se ha construido el camino v0 a1 v1 a2...vk-1 ak vk con aristas distintas, se elige la
arista siguiente ak+1 con las condiciones: (1) ak+1 incidente con vk y (2) no ser puente en el grafo
G- {a1,a2,...,ak} (salvo que no haya alternativa).
Paso 3.- Se sigue hasta que el camino contenga todas las aristas.

Un camino hamiltoniano en un grafo es un camino que contiene a todos los vrtices del grafo
exactamente una vez (salvo v0=vn, si el camino es cerrado). Un grafo hamiltoniano es aquel que
contiene un ciclo hamiltoniano.

Propiedad: Un grafo bipartido G=(V1 V2 , A) con | V1| =|V2|no es hamiltoniano.

Teorema: Sea G un grafo simple de n vrtices. Si para todo par de vrtices x e y no adyacentes
se cumple que d(x)+d(y) > n , entonces G es hamiltoniano.

Teorema: Si G es un grafo hamiltoniano entonces, para todo S V se cumple que el nmero de
componentes conexas de G - S, es menor o igual que |S|.

Observacin: NO hay caracterizacin para los grafos hamiltonianos.
142

Bibliografia:
1) Balabaniam, N.: Circuitos Elctricos. MacGraw Hill. 1994. 127 135.
2) Balabaniam, N.; Bickart, T.A.; Seshu, S.: Teora de Redes Elctricas. Revert, 1972. 200 204.
3) Budak, A. Passive and Active Network Analysis and Synthesis. Houghton Mifflin, 1974. 97
140.
4) Lipschults, Seymour: Estructura de Datos teora y problemas. Schaum-McGraw-Hill. 1988.
5) Folk, M y Zoellick, B.: Estructura de Archivos, Addison-Wesley, Reading, MA, 1992. 420 423.
6) Cormen, Leiserson, Rivest: Introduccin a la Algoritmica, The MIT Press-Mc Graw Hill, 1990.
199 215.
7) A.Giraldo, Topologa Digital, Prepublicaciones del Departamento de Matemtica Aplicada,
FIM/2/DMA/97, Facultad de Informtica, UPM, 1997.
8) A.Giraldo, Digitizations preserving shape, Vision Geometry VI, Proc. of the 1997 SPIE
Conference on Vision Geometry, San Diego, 1997.
9) G.T.Herman, Anlisis de la Imagen en Aplicacin topolgica, Visin de la Computadora,
Procesando Grficos e Imagen, 52, 1990, 409-415.
10) E.Khalimsky, Topological structures in computer science, J. Appl. Math. Simulation, 1, 1987,
25-40.
11) T.Y.Kong, R.Kopperman y P.R.Meyer, A Topological Approach to Digital Topology, American
Mathematical Monthly, 98, 1991, 901-917.1.
12) T.Y.Kong, R.Kopperman y P.R.Meyer (eds.), Problema especial en Topologa Digital, Topologa
y sus Aplicaciones, 46, 1992.
13) T.Y.Kong y A.Rosenfeld, Digital Topology: Introduction and Survey, Computer Vision,
Graphics and Image Processing, 48, 1989, 357-393.
14) T.Y.Kong y A.Rosenfeld (eds.), Problema especial en Topologa y Geometra en Visin de la
Computadora, Peridico de Imagen Matemtico y Visin, 6, 1996.
15) V.A.Kovalevsky, Finite Topology as Applied to Image Analysis, Computer Vision, Graphics and
Image Processing, 46, 1989, 141-161.
16) E.H.Kronhemeir, Alternativas topolgicas Digitales, Topologa y sus Aplicaciones, 46, 1992,
269-277.
17) Knuth D.E.; Clasificacin y bsqueda. El Arte de Programar Ordenadores Vol. III. Ed. Revert
S.A., 1987.
18) Knuth D.E.; Algoritmos Fundamentales. El Arte de Programar Ordenadores Vol. I. Ed. Revert
S.A., 1980.
19) Aho A. V., Hopcroft J.E., Ullman J.D.; Estructuras de Datos y Algoritmos. Ed. Addison-Wesley,
1988.
20) Deitel H.M., Deitel P.J.; C++ How To Program. Ed. Prentice Hall, 1994.

You might also like