Sei sulla pagina 1di 117

UNIVERSIDAD POLITÉCNICA ESTATAL DEL CARCHI

FACULTAD DE INDUSTRIAS AGROPECUARIAS Y


CIENCIAS AMBIENTALES

CARRERA DE COMPUTACIÓN

PORTAFOLIO DE ANALISIS DE ALGORITMOS

AUTORES: Cristian Villacreces

TUTOR: Samuel Lascano

Tulcán, febrero de 2019


MISIÓN

“La Universidad Politécnica Estatal del Carchi es una institución de educación superior
pública y acreditada, que satisface las demandas sociales a través de la formación de grado
y posgrado, la investigación, la vinculación con la sociedad y la gestión, generando
conocimientos que contribuyen al desarrollo económico, social, científico-tecnológico,
cultural y ambiental de la región.”

VISIÓN

“Ser una universidad sin fronteras geográficas, acreditada, líder en la formación integral
y reconocida por su excelencia, calidad, transparencia y compromiso con el desarrollo de
la región y del país”.

“CARERA DE CIENCIAS DE LA COMPUTACION”

MISIÓN

“Formar profesionales en computación capaces de proponer y generar soluciones


tecnológicas e innovadoras que contribuyan al desarrollo del sector de las TIC y la
disminución de la brecha digital en la región, con sólidas bases académicas e
investigativas y enmarcados en los aspectos crítico, ético, legal y compromiso social”

VISIÓN

“Ser una carrera acreditada, líder en la formación integral de profesionales en


computación y reconocida por su calidad, transparencia y compromiso con el desarrollo
del sector de las TIC en la región”

2
UNIVERSIDAD POLITÉCNICA ESTATAL DEL CARCHI

SILABO

1 DATOS DEL PROFESOR

1.1 NOMBRE: SAMUEL B. LASCANO RIVERA

1.2 NÚMERO DE 18025902222


CÉDULA:

INGENIERO
1.3.2 N° DE
1.3 TÍTULO DE 1.3.1 EN SISTEMAS 1042-12-
REGISTRO
TERCER NIVEL DESCRIPCIÓN: E 1185274
SENESCYT:
INFORMATICA
MAESTRIA EN 1.4.2 N° DE
1.4 TÍTULO DE 1.4.1 1015-2017-
DESARROLLO DE REGISTRO
CUARTO NIVEL DESCRIPCIÓN: 1917500
SOFTWARE SENESCYT:

1.5 NÚMERO 0984925548


TELEFÓNICO:

1.6 CORREO samuelascanoupec@gmail.com


ELECTRÓNICO:

2. DATOS DE LA ASIGNATURA

2.1 FACULTAD: INDUSTRIAS AGROPECUARIAS Y CIENCIAS AMBIENTALES

2.2 CARRERA: INGENIERÍA EN INFORMÁTICA


2.3 PERÍODO 01 de Octubre 2018 –
2.3.1 N°: 4 2.3.2 FECHA:
ACADÉMICO: 06 Febrero 2019
2.4 ASIGNATURA: ANÁLISIS DE ALGORITMOS
2.5 CÓDIGO DE
I CCAAUPPP23
ASIGNATURA:
2.6.1 D: 96 2.6.1.1 AAP 45 2.6.1.2 AC 51
2.6 HORAS:
2.6.2 APE: 20 2.6.3 AA: 44 TOTAL: 160
2.7 PRERREQUISITOS Estructura de Datos 2.7.1 CÓDIGO CCEDUPPP17

2.8 CORREQUISITOS 2.8.1 CÓDIGO

3
3. CONSTRUCCIÓN DEL CONOCIMIENTO

3.1 N° DE LA UNIDAD: 1 3.2 NOMBRE DE LA UNIDAD: Notaciones asintóticas. 3.3 N° DE HORAS: 15

Formular y desarrollar algoritmos simples utilizando


para ello pseudocódigo declarativo o diagramas de
flujo haciendo uso de herramientas computacionales 3.5 AMBIENTE DE
3.4 RESULTADO DE APRENDIZAJE: Curso
gráficas, que le permitan depurar errores de lógica, APRENDIZAJE:
en problemas simples de ingeniería y manejo de
información.
3.8 DOCENCIA
3.7 HORAS 3.11 ACTIVIDADES DE 3.12 ACTIVIDADES DE 3.13 ACTIVIDADES
3.6 FOLIO 3.9 AA 3.10 CONTENIDO
CLASE 3.8.1 AAP 3.8.2 AC APRENDIZAJE EVALUACIÓN AUTÓNOMAS

Elabore un resumen
Introducción y Representación Evaluación diagnostica sobre
Clase Magistral utilizando organizadores
1 3 1.5 1.5 3 de algoritmos.
Taller en grupo
el tema de introducción a
gráficos sobre la
Estructura. Algoritmos.
introducción a Algoritmos.
Pruebas informales Elabore un resumen
Análisis Empírico
Clase Magistral utilizando organizadores
2 3 1.5 1.5 3 Análisis Analítico Trabajos prácticos gráficos sobre los
Taller en grupo
Prácticas del laboratorio algoritmos
3 Clase Magistral Taller colaborativo.
3 1.5 1.5 3 Ordenamiento
Taller en grupo
Ejercicios Prácticos
Prácticas del laboratorio
Pruebas informales
Clase Magistral Resolución de Problemas
4 3 1.5 1.5 3 Iteración. Trabajos prácticos Ejercicios Prácticos
Taller en grupo
Prácticas del laboratorio
Taller colaborativo.
Clase Magistral Resolución de Problemas
5 3 1.5 1.5 3 Notación Asintótica Taller en grupo
Evaluación Sumativa de Ejercicios Prácticos
Unidad
Thomas H. Cormen, (2015) Introducción a los Algoritmos | 4ta Edición | England , Editorial The MIT Press Cambridge, Massachusetts
3.14 BIBLIOGRAFÍA BÁSICA:

Michael T. Goodrich, (2014) Data Structures and Algorithms in Java Department of Computer Science University of California, Editorial Irvine
3.15 BIBLIOGRAFÍA COMPLEMENTARIA:
3.1 N° DE LA UNIDAD: 2 3.2 NOMBRE DE LA UNIDAD: Ecuaciones de recurrencia 3.3 N° DE HORAS: 15

Diseñar e implementar soluciones a problemas del


entorno mediante el diseño de algoritmos 3.5 AMBIENTE DE
3.4 RESULTADO DE APRENDIZAJE: Curso / Laboratorio de Informática
recursivos, utilizando las estructuras de datos APRENDIZAJE:
lineales, como lo son las pilas, colas y listas.

3.8 DOCENCIA
3.7 HORAS 3.11 ACTIVIDADES DE 3.12 ACTIVIDADES DE 3.13 ACTIVIDADES
3.6 FOLIO 3.9 AA 3.10 CONTENIDO
CLASE 3.8.1 AAP 3.8.2 AC APRENDIZAJE EVALUACIÓN AUTÓNOMAS

Pilas
Clase Magistral Taller colaborativo.
6 3 1.5 1.5 3 Colas Taller en grupo
Ejercicios Prácticos
Prácticas del laboratorio

listas.
El concepto de Pruebas informales
Resolución de Problemas
7 3 1.5 1.5 3 Taller en grupo Trabajos prácticos Ejercicios Prácticos
recursividad. Prácticas del laboratorio

Funciones matemáticas
recursivas.
8 Clase Magistral Taller colaborativo.
3 1.5 1.5 3 Funciones recursivas Taller en grupo Ejercicios Prácticos
Prácticas del laboratorio
simples.

Estrategias de dividir y
Pruebas informales
conquistar. Resolución de Problemas
9 3 1.5 1.5 3 Clase Magistral Trabajos prácticos Ejercicios Prácticos
Prácticas del laboratorio

Backtracking recursivo Taller colaborativo.


Clase Magistral Resolución de Problemas
10 3 1.5 1.5 3 Taller en grupo
Evaluación Sumativa de Ejercicios Prácticos
Unidad

5
Thomas H. Cormen, (2015) Introducción a los Algoritmos | 4ta Edición | England , Editorial The MIT Press Cambridge, Massachusetts
3.14 BIBLIOGRAFÍA BÁSICA:
Michael T. Goodrich, (2014) Data Structures and Algorithms in Java Department of Computer Science University of California, Editorial
3.15 BIBLIOGRAFÍA COMPLEMENTARIA: Irvine

3.1 N° DE LA UNIDAD: 3 3.2 NOMBRE DE LA UNIDAD: Dividir y conquistar 3.3 N° DE


18
HORAS:
Identificar las técnicas fundamentales de análisis y diseño de
algoritmos que permitan comprender la naturaleza de los
problemas tan independientemente como sea posible de los 3.5 AMBIENTE DE Curso / Laboratorio de Informática
3.4 RESULTADO DE APRENDIZAJE:
aspectos de implementación (tanto hardware como software) APRENDIZAJE:
y resolverlos eficientemente.

3.8 DOCENCIA
3.7 HORAS 3.11 ACTIVIDADES DE 3.12 ACTIVIDADES DE 3.13 ACTIVIDADES
3.6 FOLIO 3.9 AA 3.10 CONTENIDO
CLASE 3.8.1 AAP 3.8.2 AC APRENDIZAJE EVALUACIÓN AUTÓNOMAS

Algoritmos numéricos
Clase Magistral Taller colaborativo.
11 3 1.5 1.5 3 simples. Taller en grupo
Ejercicios Prácticos
Prácticas del laboratorio

Representación de grafos
(Listas y Matrices de Pruebas informales
Resolución de Problemas
12 3 1.5 1.5 3 Clase Magistral Trabajos prácticos Ejercicios Prácticos
adyacencia). Prácticas del laboratorio

Recorridos por amplitud y


Clase Magistral Taller colaborativo.
13 3 1.5 1.5 3 profundidad. Taller en grupo
Ejercicios Prácticos
Prácticas del laboratorio

6
El algoritmo del camino más
corto (algoritmos de Dijkstra Pruebas informales
Resolución de Problemas
14 3 1.5 1.5 3 Clase Magistral Trabajos prácticos Ejercicios Prácticos
y Floyd). Prácticas del laboratorio

Árbol de expansión mínima


(algoritmos de Kruskal y Clase Magistral Taller colaborativo.
15 3 1.5 1.5 3 Taller en grupo
Ejercicios Prácticos
Prim). Prácticas del laboratorio

Ordenamiento Topológico. Taller colaborativo.


Clase Magistral Resolución de Problemas
16 3 1.5 1.5 3 Taller en grupo
Evaluación Sumativa de Ejercicios Prácticos
Unidad
Thomas H. Cormen, (2015) Introducción a los Algoritmos | 4ta Edición | England , Editorial The MIT Press Cambridge, Massachusetts
3.14 BIBLIOGRAFÍA BÁSICA:

Michael T. Goodrich, (2014) Data Structures and Algorithms in Java Department of Computer Science University of California, Editorial Irvine
3.15 BIBLIOGRAFÍA COMPLEMENTARIA:

3.1 N° DE LA UNIDAD: 4 3.2 NOMBRE DE LA UNIDAD: Quicksort 3.3 N° DE HORAS: 15

Implementa aplicaciones móviles considerando los


3.5 AMBIENTE DE
3.4 RESULTADO DE APRENDIZAJE: estándares y normatividad vigente. Curso / Laboratorio de Informática
APRENDIZAJE:

3.8 DOCENCIA
3.7 HORAS 3.11 ACTIVIDADES DE 3.12 ACTIVIDADES DE 3.13 ACTIVIDADES
3.6 FOLIO 3.9 AA 3.10 CONTENIDO
CLASE 3.8.1 AAP 3.8.2 AC APRENDIZAJE EVALUACIÓN AUTÓNOMAS

Búsqueda secuencial y Pruebas informales


Clase Magistral Resolución de Problemas
17 3 1.5 1.5 3 binaria. Taller en grupo
Trabajos prácticos Ejercicios Prácticos
Prácticas del laboratorio
Algoritmos cuadráticos de
Taller colaborativo.
18 3 1.5 1.5 3 ordenamiento (selección, Clase Magistral Ejercicios Prácticos
Prácticas del laboratorio
inserción).

7
Algoritmos de tipo O ( logN )
(Quicksort, Pruebas informales
19 Clase Magistral Resolución de Problemas
3 1.5 1.5 3 Taller en grupo
Trabajos prácticos Ejercicios Prácticos
heapsort,mergesort). Prácticas del laboratorio

Tablas de (hash) incluyendo


estrategias de solución para Taller colaborativo.
20 3 1.5 1.5 3 Clase Magistral Ejercicios Prácticos
las colisiones. Prácticas del laboratorio

Arboles de búsqueda binaria Taller colaborativo.


Clase Magistral Resolución de Problemas
21 3 1.5 1.5 3 Taller en grupo
Evaluación Sumativa de Ejercicios Prácticos
Unidad
Thomas H. Cormen, (2015) Introducción a los Algoritmos | 4ta Edición | England , Editorial The MIT Press Cambridge, Massachusetts
3.14 BIBLIOGRAFÍA BÁSICA:
Michael T. Goodrich, (2014) Data Structures and Algorithms in Java Department of Computer Science University of California, Editorial
3.15 BIBLIOGRAFÍA COMPLEMENTARIA: Irvine

8
3.1 N° DE LA UNIDAD: 5 3.2 NOMBRE DE LA UNIDAD: Medianas y selección 3.3 N° DE HORAS: 33

Analizar, diseñar e implementar algoritmos para


problemas de búsqueda y recorrido en el que se
3.5 AMBIENTE DE
3.4 RESULTADO DE APRENDIZAJE: tengan que tomar decisiones que dependan del Curso / Laboratorio de Informática
APRENDIZAJE:
estado del sistema, haciendo uso de estructuras de
datos no lineales.
3.8 DOCENCIA
3.7 HORAS 3.11 ACTIVIDADES DE 3.12 ACTIVIDADES DE 3.13 ACTIVIDADES
3.6 FOLIO 3.9 AA 3.10 CONTENIDO
CLASE 3.8.1 AAP 3.8.2 AC APRENDIZAJE EVALUACIÓN AUTÓNOMAS

Concepto de Grafos. Pruebas informales


Clase Magistral Resolución de Problemas
22 3 1.5 1.5 3 Taller en grupo
Trabajos prácticos Ejercicios Prácticos
Prácticas del laboratorio
Grafos Dirigidos y Grafos
Taller colaborativo.
23 3 1.5 1.5 3 no Dirigidos. Clase Magistral Ejercicios Prácticos
Prácticas del laboratorio

Utilización de los Grafos. Pruebas informales


24 Clase Magistral Resolución de Problemas
3 1.5 1.5 3 Taller en grupo
Trabajos prácticos Ejercicios Prácticos
Prácticas del laboratorio
Medida de la E ciencia. En
Taller colaborativo.
25 3 1.5 1.5 3 tiempo y espacio. Clase Magistral Ejercicios Prácticos
Prácticas del laboratorio

Matrices de Adyacencia. Pruebas informales


Clase Magistral Resolución de Problemas
26 3 1.5 1.5 3 Taller en grupo
Trabajos prácticos Ejercicios Prácticos
Prácticas del laboratorio
Matrices de Adyacencia
Taller colaborativo.
27 3 1.5 1.5 3 etiquetada. Clase Magistral Ejercicios Prácticos
Prácticas del laboratorio

Listas de Adyacencia. Pruebas informales


Clase Magistral Resolución de Problemas
28 3 1.5 1.5 3 Taller en grupo
Trabajos prácticos Ejercicios Prácticos
Prácticas del laboratorio

9
Implementación de Grafos
usando Matrices de Taller colaborativo.
29 3 1.5 1.5 3 Clase Magistral Ejercicios Prácticos
Adyacencia. Prácticas del laboratorio

Implementación de Grafos
usando Listas de Pruebas informales
Clase Magistral Resolución de Problemas
30 3 1.5 1.5 3 Taller en grupo
Trabajos prácticos Ejercicios Prácticos
Adyacencia.
Prácticas del laboratorio

Inserción, Búsqueda y
Taller colaborativo.
31 3 1.5 1.5 3 Eliminación de nodos y Clase Magistral Ejercicios Prácticos
Prácticas del laboratorio
aristas
Taller colaborativo.
Algoritmos de búsqueda en Clase Magistral Resolución de Problemas
32 3 1.5 1.5 3 Taller en grupo
Evaluación Sumativa de Ejercicios Prácticos
grafos.
Unidad
Thomas H. Cormen, (2015) Introducción a los Algoritmos | 4ta Edición | England , Editorial The MIT Press Cambridge, Massachusetts
3.14 BIBLIOGRAFÍA BÁSICA:
Michael T. Goodrich, (2014) Data Structures and Algorithms in Java Department of Computer Science University of California, Editorial
3.15 BIBLIOGRAFÍA COMPLEMENTARIA: Irvine

4. PRÁCTICAS Y EXPERIMENTACIÓN

4.3 N° DE HORAS
4.1 N° DE LA PRÁCTICA: 1 4.2 NOMBRE DE LA PRÁCTICA: Desarrollo de Aplicación 20
PRÁCTICAS:

4.5 RESULTADO DE
4.4 UNIDAD A LA QUE CORRESPONDE LA PRACTICA: 2-3-4-5
APRENDIZAJE:

10
4.7 HORAS 4.10 AMBIENTE DE 4.11 ACTIVIDADES DE LA 4.12 ACTIVIDADES DE 4.13 ACTIVIDADES
4.6 FOLIO 4.8 APE 4.9 AA
CLASE APRENDIZAJE PRACTICA EVALUACIÓN AUTONOMAS

Evaluación del informe de la


7 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 1
Evaluación del informe de la
9 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 2
Evaluación del informe de la
11 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 3
Evaluación del informe de la
13 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 4
Evaluación del informe de la
15 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 5
Evaluación del informe de la
17 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 6
Evaluación del informe de la
19 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 7
Evaluación del informe de la
24 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 8
Evaluación del informe de la
26 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 9
Evaluación del informe de la
28 2 2 2 Laboratorio Practica en grupo Informe de laboratorio
practica 10

4.14 BIBLIOGRAFÍA BÁSICA: Thomas H. Cormen, (2015) Introducción a los Algoritmos | 4ta Edición | England , Editorial The MIT Press Cambridge, Massachusetts

4.15 BIBLIOGRAFÍA COMPLEMENTARIA: Michael T. Goodrich, (2014) Data Structures and Algorithms in Java Department of Computer Science University of California, Editorial Irvine

11
5. RECURSOS

Diapositivas
5.1 RECURSOS Videos
FÍSICOS: Biblioteca virtual y física.

Material apoyo en el aula virtual


5.2 RECURSOS Proyector
TECNOLÓGICOS: Laboratorio informático

12
Unidad 1

Notaciones asintóticas

TEMA 1  INTRODUCCIÓN Y REPRESENTACIÓN DE ALGORITMOS.


ESTRUCTURA

Introducción

 Un ordenador es un sistema para procesar información

Ilustración 1- Ordenador es un sistema para procesar información

 Ciclo de vida del software

Ilustración 2- Ciclo de vida del Software

Algoritmo

 “Un Algoritmo es una secuencia de operaciones detalladas y no ambiguas, que, al


ejecutarse paso a paso, conducen a la solución de un problema” (Balderrama,
2012)

13
 Algoritmo (según el DRAE): (del árabe al-Khowârizmî) “Conjunto ordenado y
finito de operaciones que permite hallar la solución de un problema “
Ejemplos sencillos de algoritmos según esta definición podrían ser una receta de
cocina o las instrucciones para armar una bicicleta.

1. Objetivo

Definir qué es un algoritmo


Describir las características que debe cumplir un algoritmo
Representar un algoritmo
Definir qué es un programa
2. Procedimiento o desarrollo

Teniendo en cuenta los conceptos anteriores podemos establecer un concepto en general


el cual sería: un algoritmo es la ejecución finita de pasos para resolver un problema.

Ejemplos:

Cuando vas a comer.

 PASOS
1. Compras o haces de comer.
2. Te lavas las manos.
3. Sirves la comida.
4. Te sientas en la mesa.
5. Comes.
 RESULTADO
Necesidad satisfecha

Definiciones básicas:

 Procesador: cualquier entidad capaz de resolver un problema


 Entorno: conjunto de utensilios que el procesador puede utilizar
 Estado: situación en la que se encuentra un entorno en un momento dado.
 Acción: Conjunto finito de operaciones que permiten llegar de un estado inicial
bien definido a otro también bien definido.

Tipos de acciones:

14
Acción primitiva o elemental
 Puede ser realizada directamente por el procesador.
Acción compuesta o abstracta
 Ha de descomponerse en acciones más elementales para poder ser
entendida por un procesador.

Características de un algoritmo:

 Preciso (no ambiguo): la instrucción a ejecutar en cada paso queda determinada


perfectamente.
 Determinista: debe comportarse del mismo modo ante las mismas condiciones. Si
se sigue dos veces en el mismo entorno, el resultado obtenido es el mismo.
 Finito: Tiene fin tras un número determinado de pasos.

Lenguajes de representación algorítmica

Tipos de representación

 Pseudocódigo
 Diagramas de flujo

3.1.1 Pseudocódigo:
Inicio Leer (lado)
“Lenguaje similar al natural, pero al que se
añaden reglas para conseguir A  lado * lado una definición
precisa del algoritmo” Imprimir(A) (Aguilar, 2008)

Fin y español (o inglés o cualquier otro idioma) que se


“Mezcla de lenguaje de programación
emplea, dentro de la programación estructurada, para realizar el diseño de un programa.
En esencial, el seudocódigo se puede definir como un lenguaje de especificaciones de
algoritmos.” (Balderrama, 2012)

Algunas reglas:

 Empieza por la palabra “Inicio” y termina con la palabra “Fin “


 Se escribe una acción por línea
 Se subrayan las palabras clave
 Las líneas que están entre llaves ({ }) se denomina comentario.

15
Diagramas de flujo Inicio Leer (lado)
Un diagrama de flujo es la representación gráfica de A  lado * lado
un algoritmo. También se puede decir que es la Imprimir(A)
representación detallada en forma gráfica de cómo
Fin
deben realizarse los pasos en la computadora para
producir resultados.

Esta representación gráfica se da cuando varios símbolos (que indican diferentes


procesos en la computadora), se relacionan entre sí mediante líneas que indican el orden
en que se deben ejecutar los procesos. (Aguilar, 2008)

Podemos decir que un diagrama de flujo sería una representación gráfica similar a un
mapa mental con simbología propia de programación para la ejecución de un programa o
solución

16
Ejemplos de Algoritmo

 Multiplicación “à la russe”
 Método tradicional
 Divide y vencerás

Lenguajes de programación

1. Lenguaje máquina:

Es el que entienden los circuitos del computador (CPU)

Inconvenientes:

 depende del modelo de computadora;


 el repertorio de instrucciones es muy reducido
 es muy laborioso
2. Ensamblador (lenguaje de bajo nivel)

Código nemotécnico para recordar mejor las instrucciones máquina

Se mantienen los otros inconvenientes del lenguaje máquina

3. Lenguajes de alto nivel

No dependen de la computadora, y facilitan la tarea de programación

 FORTRAN: (Formula Translation): Primer LAN (década de los 50). Aplicaciones


científico-técnicas (grandes computadores y supercomputadores)
 COBOL: (COmmon Busines Oriented Language): 1960. Aplicaciones
comerciales y de gestión.
 BASIC: (Beginner’s All-purpose Symbolic Instruction Code). Desarrollado a
mediados de los 60 como lenguaje interactivo paraprincipiantes de programación.
 Visual BASIC: es el lenguaje más popular. Versión de Microsoft del BASIC.
Permite crear programas en un ambiente visual (lenguaje de 4ª generación).
 C: Desarrollado en Bell Labs a comienzos de los 70. Es complejo, pero es potente,
flexible y eficiente (el más utilizado para PCs y estaciones de trabajo).

17
 Pascal: Creado por Wirth en 1971. El mejor lenguaje para aprender a programar
y describir algoritmos.
 Ada: Es un lenguaje definido por el Ministerio de Defensa de USA a finales de
los 70. Esta basado en el Pascal y tiene unas reglas muy estrictas.
 C++: Ideado a comienzos de los 80 en los BellLabs. Es una variante del C que
permite utilizar la moderna metodología de la programación (“programación
orientada a objetos”)
 Java: Desarrollado en 1991 por Sun, es similar a C++ pero más sencillo de
aprender y usar. Muy usado para programa interactivos y dinámicos (“applets” de
web). Se ha definido un computador virtual Java compatible, cualquier
computador con un programa que lo emule puede ejecutar aplicaciones Java.
4. Traductores
 Traducción:” Proceso por el cual se convierte el texto del programa de entrada en
el de salida.” (Balderrama, 2012)
Lenguaje fuente: lenguaje en el que se escribe la entrada
Lenguaje objeto: lenguaje en el que se escribe la salida. En general, muy
diferente del lenguaje fuente
 Compilador: “Programa que acepta como entrada un texto de programa escrito en
un cierto lenguaje de alto nivel y genera como salida texto de programa en otro
lenguaje, generalmente lenguaje máquina.” (Aguilar, 2008)
5. Compiladores

 Compilar ≈ Convertir de un formato a otro

El significado deberá permanecer inalterado en la conversión

La entrada está escrita en un lenguaje  Tiene estructura

Semántica asociada y descrita en términos de esa estructura

 El compilador “comprende” el programa y recolecta su significado en una


representación semántica intermedia

A la hora de generar la salida  se genera estructura y significado

6. Interpretes
 El procesamiento del programa es entre mínimo y moderado

18
 El mecanismo de interpretación es un programa (sw)
 La ejecución del programa es, en general, más lenta y más segura

La diferencia más destacable entre un compilador y un intérprete

“mientras un intérprete acepta un programa fuente que traduce y ejecuta


simultáneamente analizando cada sentencia o instrucción por separado, un
compilador efectúa dicha operación en dos fases independientes, primero traduce
completamente el programa fuente y seguidamente ejecuta el programa” (Quero,
2003)

3. Conclusiones

 Cada algoritmo tiene una eficiencia diferente dependiendo el tamaño de datos.


4. Recomendaciones

 Distinguir la mejor forma de valorización de cada algoritmo.

TEMA 2  ANÁLISIS EMPÍRICO, ANÁLISIS ANALÍTICO

Introducción

El análisis empírico y analítico son las dos formas de valorar la eficiencia del algoritmo
que es analíticamente (de forma teórica) y empíricamente que consiste en ejecutar cada
código en una maquia real.
1. Objetivo

Conocer las formas valoración de la eficiencia de los algoritmos.


2. Procedimiento o desarrollo

Existen dos formas de valorar la eficiencia de los algoritmos: empíricamente y


analíticamente.
Empíricamente: consiste en ejecutar cada algoritmo en una maquina real, para instancias
de diferente tamaño del problema considerado y obtener los resultados de tiempos
consumidos y espacios utilizados.
Posee varios inconvenientes

19
 Requiere una adecuada selección de los datos de entrada, lo cual no es
necesariamente fácil de realizar.
 Requiere múltiples ejecuciones de un mismo algoritmo, y por lo tanto, mucho
tiempo.
 Está excesivamente ligado a una maquina concreta, por lo que en algunos casos
los resultados no son extrapolables.
Analíticamente: consiste en determinar matemáticamente la cantidad de recursos
(tiempo, espacio) que consume un algoritmo en función del “tamaño” de las instancias de
problemas que resuelve.
 Por tamaño se pueden entender varias cosas: Número de ítems de entrada,
valor(es) de los ítems, espacio de almacenamiento, etc.
 La eficiencia se convierte en función 𝑡𝑛 que permite calcular el tiempo/espacio
requerido por el algoritmo para problemas de tamaño n.
 La función 𝑡𝑛 se identifica a partir de una o un conjuntos de operaciones básicas.

3. Conclusiones

 Cada algoritmo tiene una eficiencia diferente dependiendo el tamaño de datos.


4. Recomendaciones

 Distinguir la mejor forma de valorización de cada algoritmo.

Tema 3  Ordenamiento

Introducción

20
En el presente informe se da a conocer lo que es un ordenamiento y los diferentes tipos
de algoritmos que se puede desarrollar para dar una mejor comprensión de su
funcionamiento, explicando lo que hace cada uno de estos métodos y dando un ejemplo.

1. Objetivo

Conocer y desarrollar los algoritmos de ordenamiento para tener en cuenta el


funcionamiento de cada uno y cuál es el más apto para nuestros proyectos.

2. Procedimiento o desarrollo

¿Qué es ordenamiento?

Es la operación de arreglar los registros de una tabla en algún orden secuencial de acuerdo
a un criterio de ordenamiento.

El ordenamiento se efectúa con base en el valor de algún campo en un registro.

El propósito principal de un ordenamiento es el de facilitar las búsquedas de los miembros


del conjunto ordenado. (rmurillo95, 2010)

Ej. De ordenamientos:

Dir. Telefónico, tablas de contenido, bibliotecas y diccionarios, etc.

El ordenar un grupo de datos significa mover los datos o sus referencias para que queden
en una secuencia tal que represente un orden, el cual puede ser numérico, alfabético o
incluso alfanumérico, ascendente o descendente.

Tipos de ordenamientos:

Los 2 tipos de ordenamientos que se pueden realizar son: los internos y los externos.

 Los internos:

Son aquellos en los que los valores a ordenar están en memoria principal, por lo que se
asume que el tiempo que se requiere para acceder cualquier elemento sea el mismo (a[1],
a[500], etc). (rmurillo95, 2010)

 Los externos:

Son aquellos en los que los valores a ordenar están en memoria secundaria (disco, cinta,
cilindro magnético, etc), por lo que se asume que el tiempo que se requiere para acceder

21
a cualquier elemento depende de la última posición accesada (posición 1, posición 500,
etc).

Clasificación de los algoritmos de ordenamiento de información:

El hecho de que la información está ordenada, nos sirve para poder encontrarla y
accesarla de manera más eficiente ya que de lo contrario se tendría que hacer de manera
secuencial. (rmurillo95, 2010)

A continuación se describirán 4 grupos de algoritmos para ordenar información:

1. Algoritmos de inserción:

En este tipo de algoritmo los elementos que van a ser ordenados son considerados uno a
la vez. Cada elemento es INSERTADO en la posición apropiada con respecto al resto de
los elementos ya ordenados.

Entre estos algoritmos se encuentran el de INSERCION DIRECTA, SHELL SORT,


INSERCION BINARIA y HASHING.

2. Algoritmos de intercambio:

En este tipo de algoritmos se toman los elementos de dos en dos, se comparan y se


INTERCAMBIAN si no están en el orden adecuado. Este proceso se repite hasta que se
ha analizado todo el conjunto de elementos y ya no hay intercambios. (rmurillo95, 2010)

Entre estos algoritmos se encuentran el BURBUJA y QUICK SORT.

3. Algoritmos de selección:

En este tipo de algoritmos se SELECCIONA o se busca el elemento más pequeño (o más


grande) de todo el conjunto de elementos y se coloca en su posición adecuada. Este
proceso se repite para el resto de los elementos hasta que todos son analizados.
Entre estos algoritmos se encuentra el de SELECCION DIRECTA. (rmurillo95, 2010)

4. Algoritmos de enumeración:

En este tipo de algoritmos cada elemento es comparado contra los demás. En la


comparación se cuenta cuántos elementos son más pequeños que el elemento que se está
analizando, generando así una ENUMERACION. El número generado para cada
elemento indicará su posición. (rmurillo95, 2010)

22
Los métodos simples son: Inserción (o por inserción directa), selección, burbuja y shell,
en dónde el último es una extensión al método de inserción, siendo más rápido. Los
métodos más complejos son el quick-sort (ordenación rápida) y el heap sort.

A continuación se mostrarán los métodos de ordenamiento más simples.

METODO DE INSERCIÓN.

Este método toma cada elemento del arreglo para ser ordenado y lo compara con los que
se encuentran en posiciones anteriores a la de él dentro del arreglo. Si resulta que el
elemento con el que se está comparando es mayor que el elemento a ordenar, se recorre
hacia la siguiente posición superior. Si por el contrario, resulta que el elemento con el que
se está comparando es menor que el elemento a ordenar, se detiene el proceso de
comparación pues se encontró que el elemento ya está ordenado y se coloca en su posición
(que es la siguiente a la del último número con el que se comparó). (rmurillo95, 2010)

Procedimiento INSERTION SORT

Este procedimiento recibe el arreglo de datos a ordenar a [] y altera las posiciones de sus
elementos hasta dejarlos ordenados de menor a mayor. Representa el número de
elementos que contiene a [].

Paso 1: [Para cada pos. del arreglo] 𝐹𝑜𝑟 𝑖 < − 2 𝑡𝑜 𝑁 𝑑𝑜

Paso 2: [𝐼𝑛𝑖𝑐𝑖𝑎𝑙𝑖𝑧𝑎 𝑣 𝑦 𝑗] 𝑣 < − 𝑎[𝑖]

𝑗 < − 𝑖.

Paso 3: [𝐶𝑜𝑚𝑝𝑎𝑟𝑎 𝑣 𝑐𝑜𝑛 𝑙𝑜𝑠 𝑎𝑛𝑡𝑒𝑟𝑖𝑜𝑟𝑒𝑠] 𝑊ℎ𝑖𝑙𝑒 𝑎[𝑗 − 1] > 𝑣 𝐴𝑁𝐷 𝑗 > 1 𝑑𝑜

Paso 4: [𝑅𝑒𝑐𝑜𝑟𝑟𝑒 𝑙𝑜𝑠 𝑑𝑎𝑡𝑜𝑠 𝑚𝑎𝑦𝑜𝑟𝑒𝑠] 𝑆𝑒𝑡 𝑎[𝑗] < − 𝑎[𝑗 − 1],

Paso 5: [𝐷𝑒𝑐𝑟𝑒𝑚𝑒𝑛𝑡𝑎 𝑗] 𝑠𝑒𝑡 𝑗 < − 𝑗 − 1.

Paso 5: [𝐼𝑛𝑠𝑒𝑟𝑡𝑎 𝑣 𝑒𝑛 𝑠𝑢 𝑝𝑜𝑠𝑖𝑐𝑖ó𝑛] 𝑆𝑒𝑡 𝑎[𝑗] < − 𝑣.

Paso 6: [𝐹𝑖𝑛] 𝐸𝑛𝑑.

Ejemplo:

Si el arreglo a ordenar es a = [′𝑎′, ′𝑠′, ′𝑜′, ′𝑟′, ′𝑡′, ′𝑖′, ′𝑛′, ′𝑔′, ′𝑒′, ′𝑥′, ′𝑎′, ′𝑚′, ′𝑝′, ′𝑙′, ′𝑒′], el
algoritmo va a recorrer el arreglo de izquierda a derecha. Primero toma el segundo dato
's' y lo asigna a v y i toma el valor de la posición actual de v.

23
Luego compara esta 's' con lo que hay en la posición j-1, es decir, con 'a'. Debido a que 's'
no es menor que 'a' no sucede nada y avanza i.

Ahora v toma el valor 'o' y lo compara con 's', como es menor recorre a la 's' a la posición
de la 'o'; decremento j, la cual ahora tiene la posición en dónde estaba la 's'; compara a 'o'
con a [j-1] , es decir, con 'a'. Como no es menor que la 'a' sale del for y pone la 'o' en la
posición a[j]. El resultado hasta este punto es el arreglo siguiente: a = ['a','o','s','r',....]
(rmurillo95, 2010)

Así se continúa y el resultado final es el arreglo ordenado:

𝑎 = [′𝑎′, ′𝑎′, ′𝑒′, ′𝑒′, ′𝑔′, ′𝑖′, ′𝑙′, ′𝑚′, ′𝑛′, ′𝑜′, ′𝑝′, ′𝑟′, ′𝑠′, ′𝑡′, ′𝑥′]

MÉTODO DE SELECCIÓN.

El método de ordenamiento por selección consiste en encontrar el menor de todos los


elementos del arreglo e intercambiarlo con el que está en la primera posición. Luego el
segundo más pequeño, y así sucesivamente hasta ordenar todo el arreglo. (rmurillo95,
2010)

Procedimiento SELECTION SORT

Paso 1: [Para cada pos. del arreglo] 𝐹𝑜𝑟 𝑖 < − 1 𝑡𝑜 𝑁 𝑑𝑜

Paso 2: [Inicializa la pos. del menor] 𝑚𝑒𝑛𝑜𝑟 < − 𝑖

Paso 3: [Recorre todo el arreglo] 𝐹𝑜𝑟 𝑗 < − 𝑖 + 1 𝑡𝑜 𝑁 𝑑𝑜

Paso 4: [Si a[j] es menor] 𝐼𝑓 𝑎[𝑗] < 𝑎[𝑚𝑒𝑛𝑜𝑟] 𝑡ℎ𝑒𝑛

Paso 5: [Reasigna el apuntador al menor] 𝑚𝑖𝑛 = 𝑗

Paso 6: [Intercambia los datos de la pos.

Min y posición i] 𝑆𝑤𝑎𝑝(𝑎, 𝑚𝑖𝑛, 𝑗).

Paso 7: [𝐹𝑖𝑛] 𝐸𝑛𝑑.

Ejemplo:

El arreglo a ordenar es a = [′𝑎′, ′𝑠′, ′𝑜′, ′𝑟′, ′𝑡′, ′𝑖′, ′𝑛′, ′𝑔′, ′𝑒′, ′𝑥′, ′𝑎′, ′𝑚′, ′𝑝′, ′𝑙′, ′𝑒′].

Se empieza por recorrer el arreglo hasta encontrar el menor elemento. En este caso el
menor elemento es la primera 'a'. De manera que no ocurre ningún cambio. Luego se
procede a buscar el siguiente elemento y se encuentra la segunda 'a'.

24
Esta se intercambia con el dato que está en la segunda posición, la 's', quedando el arreglo
así después de dos recorridos: 𝑎 =
[′𝑎′, ′𝑎′, ′𝑜′, ′𝑟′, ′𝑡′, ′𝑖′, ′𝑛′, ′𝑔′, ′𝑒′, ′𝑥′, ′𝑠′, ′𝑚′, ′𝑝′, ′𝑙′, ′𝑒′].

El siguiente elemento, el tercero en orden de menor mayor es la primera 'e', la cual se


intercambia con lo que está en la tercera posición, o sea, la 'o'. Le sigue la segunda 's', la
cual es intercambiada con la 'r'.

El arreglo ahora se ve de la siguiente manera: a =


[′𝑎′, ′𝑎′, ′𝑒′, ′𝑒′, ′𝑡′, ′𝑖′, ′𝑛′, ′𝑔′, ′𝑜′, ′𝑥′, ′𝑠′, ′𝑚′, ′𝑝′, ′𝑙′, ′𝑟′].

De esta manera se va buscando el elemento que debe ir en la siguiente posición hasta


ordenar todo el arreglo.

El número de comparaciones que realiza este algoritmo es:

Para el primer elemento se comparan n-1 datos, en general para el elemento i-ésimo se
hacen n-i comparaciones, por lo tanto, el total de comparaciones es:

La sumatoria para 𝑖 𝑑𝑒 1 𝑎 𝑛 − 1 (𝑛 − 𝑖) = 1/2 𝑛 (𝑛 − 1).

MÉTODO BURBUJA.

El bubble sort, también conocido como ordenamiento burbuja, funciona de la siguiente


manera: Se recorre el arreglo intercambiando los elementos adyacentes que estén
desordenados. Se recorre el arreglo tantas veces hasta que ya no haya cambios.
Prácticamente lo que hace es tomar el elemento mayor y lo va recorriendo de posición en
posición hasta ponerlo en su lugar. (rmurillo95, 2010)

Procedimiento BUBBLE SORT

Paso 1: [Inicializa i al final de arreglo] 𝐹𝑜𝑟 𝑖 < − 𝑁 𝑑𝑜𝑤𝑛 𝑡𝑜 1 𝑑𝑜

Paso 2: [Inicia desde la segunda pos.] 𝐹𝑜𝑟 𝑗 < − 2 𝑡𝑜 𝑖 𝑑𝑜

Paso 4: [Si a[j-1] es mayor que el que le sigue] 𝐼𝑓 𝑎[𝑗 − 1] < 𝑎[𝑗] 𝑡ℎ𝑒𝑛

Paso 5: [Los intercambia] 𝑆𝑤𝑎𝑝(𝑎, 𝑗 − 1, 𝑗).

Paso 7: [𝐹𝑖𝑛] 𝐸𝑛𝑑.

Tiempo de ejecución del algoritmo burbuja:

1. Para el mejor caso (un paso) O(n)

25
2. Peor caso n(n-1)/2
3. Promedio O(n2)

MÉTODO DE SHELL.

Ordenamiento de disminución incremental.

Nombrado así debido a su inventor Donald Shell.

Ordena subgrupos de elementos separados K unidades (respecto de su posición en el


arreglo) del arreglo original. El valor K es llamado incremento.

Después de que los primeros K subgrupos han sido ordenados (generalmente utilizando
INSERCION DIRECTA), se escoge un nuevo valor de K más pequeño, y el arreglo es de
nuevo partido entre el nuevo conjunto de subgrupos. Cada uno de los subgrupos mayores
es ordenado y el proceso se repite de nuevo con un valor más pequeño de K. (rmurillo95,
2010)

Eventualmente el valor de K llega a ser 1, de tal manera que el subgrupo consiste de todo
el arreglo ya casi ordenado.

Al principio del proceso se escoge la secuencia de decrecimiento de incrementos; el


último valor debe ser 1.

"Es como hacer un ordenamiento de burbuja pero comparando e intercambiando


elementos."

Cuando el incremento toma un valor de 1, todos los elementos pasan a formar parte del
subgrupo y se aplica inserción directa.

El método se basa en tomar como salto N/2 (siendo N el número de elementos) y luego
se va reduciendo a la mitad en cada repetición hasta que el salto o distancia vale 1.

Procedimiento SHELL SORT

𝑐𝑜𝑛𝑠𝑡

𝑀𝐴𝑋𝐼𝑁𝐶 = _____;

𝑖𝑛𝑐𝑟𝑒𝑚𝑒𝑛𝑡𝑜𝑠 = 𝑎𝑟𝑟𝑎𝑦[1. . 𝑀𝐴𝑋𝐼𝑁𝐶] 𝑜𝑓 𝑖𝑛𝑡𝑒𝑔𝑒𝑟;

𝑣𝑎𝑟

𝑗, 𝑝, 𝑛𝑢𝑚, 𝑖𝑛𝑐𝑟𝑒, 𝑘: 𝑖𝑛𝑡𝑒𝑔𝑒𝑟;

26
𝑏𝑒𝑔𝑖𝑛

𝑓𝑜𝑟 𝑖𝑛𝑐𝑟𝑒 ∶= 1 𝑡𝑜 𝑀𝐴𝑋𝐼𝑁𝐶 𝑑𝑜 𝑏𝑒𝑔𝑖𝑛 /∗ 𝑝𝑎𝑟𝑎 𝑐𝑎𝑑𝑎 𝑢𝑛𝑜 𝑑𝑒 𝑙𝑜𝑠 𝑖𝑛𝑐𝑟𝑒𝑚𝑒𝑛𝑡𝑜𝑠 ∗/

𝑘 ∶= 𝑖𝑛𝑐[𝑖𝑛𝑐𝑟𝑒]; /∗ 𝑘 𝑟𝑒𝑐𝑖𝑏𝑒 𝑢𝑛 𝑡𝑖𝑝𝑜 𝑑𝑒 𝑖𝑛𝑐𝑟𝑒𝑚𝑒𝑛𝑡𝑜 ∗/

𝑓𝑜𝑟 𝑝 ∶
= 𝑘 + 1 𝑡𝑜 𝑀𝐴𝑋𝑅𝐸𝐺 𝑑𝑜 𝑏𝑒𝑔𝑖𝑛 /
∗ 𝑖𝑛𝑠𝑒𝑟𝑐𝑖ó𝑛 𝑑𝑖𝑟𝑒𝑐𝑡𝑎 𝑝𝑎𝑟𝑎 𝑒𝑙 𝑔𝑟𝑢𝑝𝑜 𝑞𝑢𝑒 𝑠𝑒 𝑒𝑛𝑐𝑢𝑒𝑛𝑡𝑟𝑎 𝑐𝑎𝑑𝑎 𝐾 𝑝𝑜𝑠𝑖𝑐𝑖𝑜𝑛𝑒𝑠 ∗/

𝑛𝑢𝑚 ∶= 𝑟𝑒𝑔[𝑝];

𝑗 ∶= 𝑝 − 𝑘;

𝑤ℎ𝑖𝑙𝑒 (𝑗 > 0) 𝐴𝑁𝐷 (𝑛𝑢𝑚 < 𝑟𝑒𝑔[𝑗]) 𝑏𝑒𝑔𝑖𝑛

𝑟𝑒𝑔[𝑗 + 𝑘] ∶= 𝑟𝑒𝑔[𝑗];

𝑗 ∶= 𝑗 − 𝑘;

𝑒𝑛𝑑;

𝑟𝑒𝑔[𝑗 + 𝑘] ∶= 𝑛𝑢𝑚;

𝑒𝑛𝑑

𝑒𝑛𝑑

𝑒𝑛𝑑;

Ejemplo:

Para el arreglo a = [6, 1, 5, 2, 3, 4, 0]

Tenemos el siguiente recorrido:

Recorrido Salto Lista Ordenada Intercambio

1 3 2,1,4,0,3,5,6 (6,2), (5,4), (6,0)

2 3 0,1,4,2,3,5,6 (2,0)

3 3 0,1,4,2,3,5,6 Ninguno

4 1 0,1,2,3,4,5,6 (4,2), (4,3)

27
5 1 0,1,2,3,4,5,6 Ninguno

3. Conclusión

Los métodos de ordenamiento nos sirven para ordenar a información que nosotros
deseamos para una mejor administración de ella.

4. Recomendación

Tener encuentra el funcionamiento de cada uno para saber que método es el más adecuado
en el momento de desarrollar nuestro proyecto.

TEMA 4  ITERACIÓN

Introducción

• La iteración en las matemáticas

La Iteración, en matemática, se refiere al proceso de iteración de una función, es decir,


aplicando la función repetidamente, usando la salida de una iteración como la entrada a
la siguiente. La iteración de funciones aparentemente simples puede producir
comportamientos complejos y problemas difíciles - por ejemplo, ver la conjetura de
Collatz y las secuencias del malabarista.

Otro uso de la iteración en matemáticas es en métodos iterativos que se usan para producir
soluciones numéricas aproximadas a ciertos problemas matemáticos. El método de
Newton es un ejemplo de un método iterativo (Hernández, 2014).

• La iteración en la programación

La iteración es el acto de repetir un proceso, para generar una secuencia de resultados


(posiblemente ilimitada), con el objetivo de acercarse a un propósito o resultado deseado.
En el contexto de las matemáticas o la informática, la iteración (junto con la técnica
relacionada de recursión) es un bloque de construcción estándar de algoritmos.

28
En la programación de computadoras, la iteración, también llamada con el término inglés
loop, es una estructura de control, dentro de un algoritmo que resuelve un problema dado,
que ordena a la computadora ejecutar repetidamente una secuencia de instrucciones,
generalmente hasta la ocurrencia de condiciones lógicas específicas.

1. Objetivo

Formular y desarrollar algoritmos simples utilizando para ello pseudocódigo


declarativo o diagramas de flujo haciendo uso de herramientas computacionales
gráficas.

2. Procedimiento o desarrollo

Ejemplo

/∗

∗ 𝑇𝑜 𝑐ℎ𝑎𝑛𝑔𝑒 𝑡ℎ𝑖𝑠 𝑙𝑖𝑐𝑒𝑛𝑠𝑒 ℎ𝑒𝑎𝑑𝑒𝑟, 𝑐ℎ𝑜𝑜𝑠𝑒 𝐿𝑖𝑐𝑒𝑛𝑠𝑒 𝐻𝑒𝑎𝑑𝑒𝑟𝑠 𝑖𝑛 𝑃𝑟𝑜𝑗𝑒𝑐𝑡 𝑃𝑟𝑜𝑝𝑒𝑟𝑡𝑖𝑒𝑠.

∗ 𝑇𝑜 𝑐ℎ𝑎𝑛𝑔𝑒 𝑡ℎ𝑖𝑠 𝑡𝑒𝑚𝑝𝑙𝑎𝑡𝑒 𝑓𝑖𝑙𝑒, 𝑐ℎ𝑜𝑜𝑠𝑒 𝑇𝑜𝑜𝑙𝑠 | 𝑇𝑒𝑚𝑝𝑙𝑎𝑡𝑒𝑠

∗ 𝑎𝑛𝑑 𝑜𝑝𝑒𝑛 𝑡ℎ𝑒 𝑡𝑒𝑚𝑝𝑙𝑎𝑡𝑒 𝑖𝑛 𝑡ℎ𝑒 𝑒𝑑𝑖𝑡𝑜𝑟.

∗/

𝑝𝑎𝑐𝑘𝑎𝑔𝑒 𝑓𝑖𝑏𝑜𝑛𝑎𝑐𝑐𝑖_𝑟𝑒𝑐𝑢𝑟𝑠𝑖𝑣𝑜;

/∗∗

∗ @𝑎𝑢𝑡ℎ𝑜𝑟 𝑢𝑠𝑢𝑎𝑟𝑖𝑜

∗/

𝑝𝑢𝑏𝑙𝑖𝑐 𝑐𝑙𝑎𝑠𝑠 𝐹𝑖𝑏𝑜𝑛𝑎𝑐𝑐𝑖_𝑟𝑒𝑐𝑢𝑟𝑠𝑖𝑣𝑜 {

𝑠𝑡𝑎𝑡𝑖𝑐 𝑖𝑛𝑡 𝑓𝑖𝑏𝑜𝑛𝑎𝑐𝑐𝑖 (𝑖𝑛𝑡 𝑛𝑢𝑚𝑒𝑟𝑜){

29
𝑖𝑓(𝑛𝑢𝑚𝑒𝑟𝑜 == 1 || 𝑛𝑢𝑚𝑒𝑟𝑜 == 2) 𝑟𝑒𝑡𝑢𝑟𝑛 1;

𝑒𝑙𝑠𝑒

𝑟𝑒𝑡𝑢𝑟𝑛 𝑓𝑖𝑏𝑜𝑛𝑎𝑐𝑐𝑖(𝑛𝑢𝑚𝑒𝑟𝑜 − 1) + 𝑓𝑖𝑏𝑜𝑛𝑎𝑐𝑐𝑖(𝑛𝑢𝑚𝑒𝑟𝑜 − 2);

/∗∗

∗ @𝑝𝑎𝑟𝑎𝑚 𝑎𝑟𝑔𝑠 𝑡ℎ𝑒 𝑐𝑜𝑚𝑚𝑎𝑛𝑑 𝑙𝑖𝑛𝑒 𝑎𝑟𝑔𝑢𝑚𝑒𝑛𝑡𝑠

∗/

𝑝𝑢𝑏𝑙𝑖𝑐 𝑠𝑡𝑎𝑡𝑖𝑐 𝑣𝑜𝑖𝑑 𝑚𝑎𝑖𝑛(𝑆𝑡𝑟𝑖𝑛𝑔[] 𝑎𝑟𝑔𝑠) {

𝐹𝑖𝑏𝑜𝑛𝑎𝑐𝑐𝑖_𝑟𝑒𝑐𝑢𝑟𝑠𝑖𝑣𝑜 𝑟𝑒𝑐𝑢𝑟𝑠𝑖𝑣𝑖𝑑𝑎𝑑 = 𝑛𝑒𝑤 𝐹𝑖𝑏𝑜𝑛𝑎𝑐𝑐𝑖_𝑟𝑒𝑐𝑢𝑟𝑠𝑖𝑣𝑜();

𝑆𝑦𝑠𝑡𝑒𝑚. 𝑜𝑢𝑡. 𝑝𝑟𝑖𝑛𝑡𝑙𝑛(𝑟𝑒𝑐𝑢𝑟𝑠𝑖𝑣𝑖𝑑𝑎𝑑. 𝑓𝑖𝑏𝑜𝑛𝑎𝑐𝑐𝑖(5));

// 𝑇𝑂𝐷𝑂 𝑐𝑜𝑑𝑒 𝑎𝑝𝑝𝑙𝑖𝑐𝑎𝑡𝑖𝑜𝑛 𝑙𝑜𝑔𝑖𝑐 ℎ𝑒𝑟𝑒

3. Conclusión

La iteración es un algoritmo que se basa en las matemáticas y un método de repetición


para generar una secuencia de datos hasta llegar a su resultado requerido.

4. Recomendación

Se recomienda realizar ejercicios para tener más claro el tema de iteración por medio del
análisis de algoritmos.

TEMA 5  NOTACIÓN ASINTÓTICA

30
Unidad 2

Ecuaciones de recurrencia

TEMA 1  PILAS, COLAS

Introducción

En ciencias de la computación, una pila o LIFO (Last in, First Out) es un tipo abstracto

de datos que sirve como una colección de elementos. Este nombre hace alusión a las pilas

físicas (ej. pilas de platos), con dos operadores principales.

En lenguajes de alto nivel, una pila puede ser fácilmente implementada a través de un

arreglo o una lista ligada. En la librería STL se implementa sobre una cola de doble fin

(deque). De tal manera que todos sus métodos son llamadas a los métodos de este ´ultimo.

Está implementado en base a templates por lo que es posible declarar pilas de un gran

número de tipos de elementos.

1. Objetivo

Aprender el funcionamiento de los métodos de las pilas y las colas en java y en general

para las ciencias de la computación.

2. Procedimiento o desarrollo

PILAS

La pila es una secuencia de elementos del mismo tipo en la que el acceso a la misma se

realiza por un único lugar denominado cima:

Vemos como el acceso a los elementos de la pila se realiza siempre sobre un único

extremo. Las operaciones que caracterizan la pila son las de introducir un nuevo elemento

31
sobre la cima (push) y la de extraer el elemento situado en la cima (pop). Una forma de

ver esta estructura de datos es como una pila de libros en la que sólo se puede coger el

libro que está en la cima o apilar más libros sobre la misma, pero los libros que sostienen

la pila no son accesibles pues de otro modo todo se desmoronaría. (Nektezer, 2011)

De aquí que decimos que una lista se comporta como una pila, ya que las inserciones y

las extracciones solo pueden hacerse desde la parte superior de la pila. Esto se

conoce también como LIFO (Last In First Out).

Las pilas son muy útiles en varios escenarios de programación. Dos de los más comunes

son:

Pilas que contienen direcciones de retorno:

Cuando el código llama a un método, la dirección de la primera instrucción que sigue a

la llamada se inserta en la parte superior de la pila de llamadas de métodos del thread

actual. Cuando el método llamado ejecuta la instrucción return, se saca la dirección de la

parte superior de la pila y la ejecución continúa en esa dirección. Si un método llama a

otro método, el comportamiento LIFO de la pila asegura que la instrucción return del

segundo método transfiere la ejecución al primer método, y la del primer método

transfiere la ejecución al código que sigue al código que llamó al primer método. Como

resultado una pila "recuerda" las direcciones de retorno de los métodos llamados.

Pilas que contienen todos los parámetros del método llamado y las variables locales:

32
Cuando se llama a un método, la JVM reserva memoria cerca de la dirección de retorno

y almacena todos los parámetros del método llamado y las variables locales de ese

método. Si el método es un método de ejemplar, uno de los parámetros que almacena en

la pila es la referencia this del objeto actual.

El interfaz en Java que define esta clase de objetos y sus métodos son los siguientes:

Pila.java

Ilustración 3- Interface Pila

Veremos ahora dos implementaciones de pila, mediante arrays y listas enlazadas.

Ilustración 4- Implementación de pila, mediante arrays y listas enlazadas

 Implementación de pilas mediante arrays

 Implementemos una Pila mediante un vector

 PilaArray.java

33
Ilustración 5- PilaArray Implementación

La dimensión de la pila se establece al crear la pila, mediante el constructor. En el

siguiente ejemplo creamos una pila con capacidad para 125 elementos

𝑃𝑖𝑙𝑎𝐴𝑟𝑟𝑎𝑦 𝑝𝑖𝑙𝑎_𝑑𝑒_𝑒𝑗𝑒𝑚𝑝𝑙𝑜 = 𝑛𝑒𝑤 𝑃𝑖𝑙𝑎𝐴𝑟𝑟𝑎𝑦(125);

Si hubiéramos usado el constructor por defecto se hubiera establecido el tamaño de la pila

en 1000 elementos.

Definimos un campo privado top para conocer en todo momento cuál es la cima de la

pila. De esta forma, si queremos añadir un nuevo elemento a la pila (push) lo haremos en

la posición siguiente a la que nos indica este campo. Observe como sólo se inserta un

nuevo elemento sobre la cima cuando hay espacio suficiente, es decir la longitud de la

pila es menor que su capacidad. Primero se incrementa el valor del campo top y después

se inserta el elemento en la pila.

Ilustración 6-Object o

34
Para implementar las operaciones pop y primero se comprueba que la lista no es vacía,

en cuyo caso se devuelve un valor nulo (null). Para el caso de pop se decremento la

variable top para eliminar el objeto de la cima, mientras que para primero no, puesto que

en este último sólo se está consultando la cima.

Ilustración 7Objeto pop

Implementación de pilas mediante listas enlazadas

Utilizaremos ahora la clase Nodo definida anteriormente para ver esta otra

implementación a la que llamaremos Pila Enlazada. Los campos que definiremos para

esta clase son top, que almacena el nodo que está en la cima de la pila y la longitud de

esta.

Ilustración 8- Pila enlazada

35
PilaEnlazada.java

Ilustración 9- Pila enlazada

A continuación, vemos como se insertan los nodos por la cima de la pila. Para ello se crea

un nuevo nodo y se le asigna como siguiente nodo la antigua cima de la pila. El siguiente

paso es actualizar la cima de la pila con el nuevo nodo creado.

El funcionamiento del pop es el siguiente. Si la lista esta vacía devuelve un valor nulo.

En caso contrario actualiza la cima al siguiente elemento por debajo del nodo situado en

la cima y devuelve el valor del nodo cima:

36
El mecanismo que sigue el método primero es similar al visto en el pop, aunque se

elimina la cima, únicamente se devuelve su valor:

COLAS

En una Cola los elementos se añaden desde la parte de atrás o la parte final de la cola, sin

embargo, la información se extrae desde el frente, es decir, los elementos que se añadieron

primero serán los primeros en salir, esto se conoce como estructura FIFO

(FirstInFirstOut)

Los elementos de la cola se añaden y se eliminan de tal manera que el primero en entrar

es el primero en salir. La adición de elementos se realiza a través de una operación

llamada encolar (enqueue), mientras que la eliminación se denomina desencolar

(dequeue). La operación de encolar inserta elementos por un extremo de la cola, mientras

que la de desencolar los elimina por el otro. (Zapata, 2010)

El siguiente interfaz muestras las operaciones típicas para colas:

Cola.java

La siguiente es una posible implementación de colas mediante la clase Nodo:

ColaEnlazada.java

37
Ilustración 10-Cola enlazada

Vemos como la clase Cola contiene dos campos, cola y cabecera que apuntan al principio

y al final de la cola. La cabecera la utilizaremos para extraer elementos. Para insertar

utilizaremos la cola.

La operación encolar crea un nodo cuyo sucesor es nulo. Esto es porque añadimos al final

de la cola, es decir, donde apunta el campo cola. Si la cola es vacía la cabecera y

la cola apuntan al mismo objeto Nodo.

38
Para eliminar (desencolar) y para consultar (cabecera) se utiliza el campo cabecero. Se

extraen/consultan elementos de la cabeza de la cola.

3. Conclusiones

Es importante mencionar es una lista ordenada o estructura de datos en la que el modo de

acceso a sus elementos es de tipo LIFO (del inglés Last In First Out, último en entrar,

primero en salir) que permite almacenar y recuperar datos.

4. Recomendaciones

Identificar los estados de los servicios y administrarlos de manera adecuada caso contrario

provocaría fallas en el sistema.

TEMA 2  LISTAS, EL CONCEPTO DE RECURSIVIDAD

39
TEMA 3  FUNCIONES MATEMÁTICAS RECURSIVAS, FUNCIONES
RECURSIVAS SIMPLES

TEMA 4  ESTRATEGIAS DE DIVIDIR Y CONQUISTAR

Introducción

El término Divide y Vencerás en su acepción más amplia es algo más que una técnica de
diseño de algoritmos. De hecho, suele ser considerada una filosofía general para resolver
problemas y de aquí que su nombre no sólo forme parte del vocabulario informático, sino
que también se utiliza en muchos otros ámbitos. En nuestro contexto, Divide y Vencerás
es una técnica de diseño de algoritmos que consiste en resolver un problema a partir de la
solución de subproblemas del mismo tipo, pero de menor tamaño. Si los subproblemas
son todavía relativamente grandes se aplicará de nuevo esta técnica hasta alcanzar
subproblemas lo suficientemente pequeños para ser solucionados directamente. Ello
naturalmente sugiere el uso de la recursión en las implementaciones de estos algoritmos.
1. Objetivo

Diseñar un programa que permita observar el funcionamiento de la técnica divide y


vencerás
2. Procedimiento o desarrollo

Divide y vencerás

Tanto el ordenamiento por mezcla como el ordenamiento rápido emplean un


paradigma algorítmico común que se basa en la recursividad. Este paradigma, divide
y vencerás, separa un problema en subproblemas que se parecen al problema original,
de manera recursiva resuelve los subproblemas y, por último, combina las soluciones
de los subproblemas para resolver el problema original. Como divide y vencerás
resuelve subproblemas de manera recursiva, cada subproblema debe ser más pequeño
que el problema original, y debe haber un caso base para los subproblemas. Debes
pensar que los algoritmos de divide y vencerás tienen tres partes:

40
1. Divide el problema en un número de subproblemas que son instancias más pequeñas
del mismo problema.
2. Vence los subproblemas al resolverlos de manera recursiva. Si son los
suficientemente pequeños, resuelve los subproblemas como casos base.
3. Combina las soluciones de los subproblemas en la solución para el problema original.
Puedes recordar fácilmente los pasos para un algoritmo de divide y vencerás
como divide, conquista, combina. Aquí está cómo ver un paso, al suponer que cada
paso de dividir crea dos subproblemas (aunque algunos algoritmos de divide y
vencerás crean más de dos):

Ilustración 11Divide-Venceras

Si expandimos a dos pasos recursivos más, se ve así:

41
Como divide y vencerás crea por lo menos dos subproblemas, un algoritmo de divide y
vencerás hace muchas llamadas recursivas.

Ilustración 12-LLamadas recursivas

La mayoría de los pasos en un ordenamiento por son sencillos. Puedes comprobar el caso
base de manera sencilla. Encontrar el punto medio q q en el paso de dividir también es
muy fácil. Tienes que hacer dos llamadas recursivas en el paso de vencer. En el paso de
combinar, en donde tienes que mezclar los dos arreglos ordenados, es en donde se hace
el trabajo de verdad.
3. Concusión

La técnica de "divide y vencerás" por tanto simplifica mucho los problemas a resolver,
aunque puede generar otro tipo de "efectos secundarios" o problemas secundarios, aunque
de menor envergadura
4. Recomendaciones

Tema 5  Backtracking recursivo

Introducción

42
El algoritmo de back tracking es utilizado para resolver problemas en los que la solución
consta de una serie de decisiones adecuadas hasta un objetivo. De esta forma genera todas
las secuenciadas de forma sistemática y organizada hasta encontrar la correcta. En una
primera medida se utilizó un algoritmo de back tracking para generar un laberinto
aleatorio, posteriormente se desarrolló en un algoritmo de back tracking recursivo para el
problema del laberinto planteado y luego se buscó desarrollar el mismo algoritmo, pero
de forma no recursiva.

1. Objetivo

Conocer la estructura del algoritmo Back tracking Recursivo y sus principales


propiedades, y que se puede realizar con el algoritmo Back tracking Recursivo.

2. Procedimiento o desarrollo

QUÉ ES BACKTRACKING

Según (Lazaro, s.f.), nos dice que: Cuando un problema no tiene un método algorítmico
para resolverse, en general la única forma posible de resolverlo es la búsqueda exhaustiva
de soluciones entre todas las posibilidades del problema; este método se conoce como
fuerza bruta: se generan todos los casos posibles y se testean uno a uno hasta encontrar
las soluciones necesarias (a veces basta con encontrar una, en otras ocasiones hay que
encontrar todas ellas, o quedarse con la mejor).

También (Lazaro, s.f.), expone que: Como el árbol de decisiones no es una estructura
almacenada en memoria, se dice que Backtracking utiliza un árbol implícito y que se
habitualmente se denomina árbol de expansión o espacio de búsqueda. Básicamente,
Backtracking es un método recursivo para buscar de soluciones por etapas de manera
exhaustiva, usando prueba y error para obtener la solución completa del problema
añadiendo decisiones a las soluciones parciales.

Implementación del Algoritmo

Según (Ivan, 2013), nos dice que: Este algoritmo es usado en muchos ámbitos de
programación, por ejemplo, para el cálculo de expresiones reguladores o para tareas de
reconocimiento de texto y sintaxis en lenguajes regulares y también como soporte para
muchos algoritmos de inteligencia artificial. El backtracking está relacionada con la

43
búsqueda combinatoria, donde el orden de los elementos no importa, donde se generan
secuencias completas hasta llegar al objetivo deseado.

Problemas de Decisión:

 Búsqueda de las soluciones que satisfacen ciertas restricciones.

Problemas de Optimización:

 Búsqueda de la mejor solución en base a una función objetivo.

También (Ivan, 2013), nos explica que: Esta definición del algoritmo de backtracking
recursivo deja bien en claro que la aplicación de este algoritmo para la resolución de un
problema como el laberinto es más que correcta. En esta implementación tenemos que
recorrer un laberinto, que como ya vimos antes puede ser análogamente representado
como un árbol, en el cual debemos explorar los caminos y volver hacia atrás cuando nos
encontramos sin salida, hasta llegar a un punto en que podamos tomar un camino
alternativo aun no explorado y recorrer este proceso se repite sucesivamente hasta llegar
al punto deseado.

Seudocódigo algoritmo de backtracking:

 En los casos planteados se toma como posición inicial las coordenadas (1,1)
siendo esta la que representa al inicio del laberinto, por ende, se toma como final
del laberinto a la esquina opuesta, al llegar a esta la función se deja de llamarse
recursivamente y retorna el ultimo nodo. La función cargar, posibles, caminos es
vital para el funcionamiento del programa, esta se encarga de verificar en qué
dirección se puede seguir caminando en base a la posición actual y al paso anterior
que realizamos.

44
También (Ivan, 2013), dice que: Cada vez que una celda vecina esta libre y se puede
avanzar hacia ella, esta función asigna memoria y crea un nuevo nodo en función de los
datos actuales y lo almacena en una de las ramas del nodo actual. Una vez cargados los
caminos posibles, cada rama del nodo actual representa un camino que seguir, entonces
se evalúan una a una mediante la misma función de backtracking. El hecho que la función
retorne el último elemento del árbol, el cual representa el fin del laberinto hace posible
que a partir de este se recorra el árbol de forma inversa y se pueda construir un nuevo
árbol de forma muy simple eliminando los demás nodos que no pertenecen a la solución.

3. Conclusiones

Se concluye que: El algoritmo de back tracking normalmente es utilizado para

resolver problemas en los que la solución consta de una serie de decisiones

adecuadas hasta llegar a un objetivo. De esta forma genera todas las secuenciadas de

forma sistemática y organizada hasta encontrar la correcta.

También se concluye que: El algoritmo de backtracking genera un laberinto

aleatorio, posteriormente se desarrolló en un algoritmo de backtracking recursivo

para el problema de un laberinto planteado.

4. Recomendaciones

45
Unidad 3

Dividir y conquistar

TEMA 1  ALGORITMOS NUMÉRICOS SIMPLES

TEMA 2  REPRESENTACIÓN DE GRAFOS (LISTAS Y MATRICES DE


ADYACENCIA)

Introducción

Para las matemáticas y las ciencias de la computación, un grafo es el principal objeto de


estudio de la teoría de grafos. De esta forma, un grafo se representa gráficamente como
un conjunto de puntos llamados vértices o nodo, unidos por líneas aristas. Los grafos
permiten estudiar las interrelaciones entre unidades que se encuentran en interacción.

Son diagramas que si se interpretan en forma adecuada proporcionan información, como


por ejemplo los mapas, diagramas de circuitos o de flujo, entre otros. Una matriz de
adyacencia es una forma de representar un grafo. La matriz de adyacencia es una matriz
2D de tamaño V x V, donde V es el número de vértices en un grafo.

Deje que la matriz 2D sea adj [] [], una ranura adj [i] [j] = 1 indica que hay un borde desde
el vértice i hasta el vértice j. La matriz de adyacencia para el grafo no dirigido siempre es
simétrica. La Matriz de Adyacencia también se usa para representar gafos ponderados. Si
adj [i] [j] = w, entonces hay un borde desde el vértice i hasta el vértice j con peso w.

1. Objetivo

Investigar los conceptos, características para la representación de grafos (listas y


matrices de adyacencia).

46
Conceptualizar el tema de matriz adyacencia para tener un conocimiento claro y
preciso en el desarrollo de ejercicios de grafos.

2. Procedimiento o desarrollo

Representación De Grafos
Un Grafo no es más que un conjunto de nodos o vértices que se encuentran relacionados
con unas aristas. Además, los vértices tienen un valor y en ocasiones las aristas también y
se le conoce como el costo.

Representación Gráfica de un Grafo

Ilustración 13Representación de un Grafo

Como se puede ver los puntos son los nodos o vértices, y las líneas son las aristas, en el
caso de la imagen es la representación gráfica de un grafo dirigido ya que las aristas
tienen un único sentido, ya que de A a D se puede ir pero de D a A no. Si el grafo fuera
no dirigido se podría ya que las aristas no tienen dirección.

Aplicación

47
La teoría de Grafos se aplica hoy en día en muchos campos, tales como en Internet, ya
que cada computador es un vértice y la conexión entre ellos son las aristas, además se usa
para hallar la ruta más corta en empresas de transporte, y en muchas otras áreas. Hay
varias maneras de representar grafos, cada uno con sus ventajas y desventajas. Algunas
situaciones, o algoritmos que queremos ejecutar que tengan grafos como entrada,
requieren una representación, y otros requieren una representación diferente. Aquí,
veremos tres formas de representar grafos.

Matrices de adyacencia

Para un grafo con ∣V∣ |V| ∣V∣ vértices, una matriz de adyacencia es una matriz de ∣V∣×∣V∣
|V| \times |V| ∣V∣×∣V∣ de ceros y unos, donde la entrada en el renglón i i i y la columna j
j j es 1 si y solo si la arista (i,j) (i, j) (i,j) está en el grafo. Si quieres indicar un peso de la
arista, ponlo en la entrada del renglón i i i, columna j j j y reserva un valor especial (tal
vez null) para indicar una arista ausente. Aquí está la matriz de adyacencia para el grafo
de la red social:

En JavaScript, representamos esta matriz como:

48
Con una matriz de adyacencia, podemos averiguar si una arista está presente en un tiempo
constante, solo buscando la entrada correspondiente en la matriz. Por ejemplo, si la matriz
de adyacencia se llama graph, entonces podemos consultar si la arista (i,j) (i, j) (i,j) se
encuentra en el grafo al mirar graph[i][j]. ¿Entonces cuál es la desventaja de una matriz
de adyacencia? Dos cosas, en realidad. En primer lugar, ocupa un espacio Θ(V2)
\Theta(V^2) Θ(V2), incluso si el grafo es disperso: relativamente pocas aristas. En otras
palabras, para un grafo disperso, la matriz de adyacencia es en su mayoría 0s, y utilizamos
mucho espacio para representar solo algunas aristas. En segundo lugar, si quieres
averiguar cuáles vértices son adyacentes a un vértice dado i i i, tienes que mirar en todas
las entradas ∣V∣ |V| ∣V∣ en el renglón i i i, incluso si solo un pequeño número de vértices
son adyacentes al vértice i i i.

Para un grafo no dirigido, la matriz de adyacencia es simétrica: la entrada del renglón i i


i, columna j j j es 1 si y solo si la entrada del renglón j j j, columna i i i es 1. Para un grafo
dirigido, la matriz de adyacencia no necesita ser simétrica.

Listas de adyacencia

Representar un grafo con listas de adyacencia combina las matrices de adyacencia con
las listas de aristas. Para cada vértice i i i, almacena un arreglo de los vértices adyacentes
a él. Típicamente tenemos un arreglo de ∣V∣ |V| ∣V∣ listas de adyacencia, una lista de
adyacencia por vértice. Aquí está una representación de una lista de adyacencia del grafo
de la red social:

En JavaScript, representamos estas listas de adyacencia como:

49
Podemos llegar a la lista de adyacencia de cada vértice en un tiempo constante, porque
solo tenemos que indexar en un arreglo. Para averiguar si una arista (i,j) (i, j) (i,j) está
presente en el grafo, vamos a la lista de adyacencia de i i i en un tiempo constante y luego
buscamos j j j en la lista de adyacencia de i i i. Si el grafo está ponderado, entonces cada
elemento en cada lista de adyacencia es un arreglo de dos elementos o un objeto, que da
el número de vértice y el peso de la arista.
Puedes usar un bucle for para iterar sobre los vértices en una lista de adyacencia. Por
ejemplo, supón que tienes una representación de una lista de adyacencia de un grafo en
la variable graph, de modo que graph[i] es un arreglo que contiene los vecinos del vértice
i i i.
 Resultados
Representación de grafos
CLASE PRINCIPAL

𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑎𝑤𝑡. 𝐵𝑜𝑟𝑑𝑒𝑟𝐿𝑎𝑦𝑜𝑢𝑡;


𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑎𝑤𝑡. 𝑒𝑣𝑒𝑛𝑡. 𝐴𝑐𝑡𝑖𝑜𝑛𝐸𝑣𝑒𝑛𝑡;
𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑎𝑤𝑡. 𝑒𝑣𝑒𝑛𝑡. 𝐴𝑐𝑡𝑖𝑜𝑛𝐿𝑖𝑠𝑡𝑒𝑛𝑒𝑟;
𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑢𝑡𝑖𝑙. 𝑉𝑒𝑐𝑡𝑜𝑟;

𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎𝑥. 𝑠𝑤𝑖𝑛𝑔.∗;

𝑝𝑢𝑏𝑙𝑖𝑐 𝑐𝑙𝑎𝑠𝑠 𝑃𝑟𝑖𝑛𝑐𝑖𝑝𝑎𝑙 𝑒𝑥𝑡𝑒𝑛𝑑𝑠 𝐽𝐴𝑝𝑝𝑙𝑒𝑡{

50
𝑃𝑎𝑛𝑒𝑙𝐷𝑖𝑏𝑢𝑗𝑜 𝑝𝑑;
𝑖𝑛𝑡 𝑚𝑎𝑥 = 0;
𝐽𝑇𝑒𝑥𝑡𝐹𝑖𝑒𝑙𝑑 𝑣𝑎𝑙𝑜𝑟;

𝑝𝑢𝑏𝑙𝑖𝑐 𝑣𝑜𝑖𝑑 𝑖𝑛𝑖𝑡(){

𝑝𝑑 = 𝑛𝑒𝑤 𝑃𝑎𝑛𝑒𝑙𝐷𝑖𝑏𝑢𝑗𝑜();
𝑎𝑑𝑑(𝑝𝑑);

𝐽𝑃𝑎𝑛𝑒𝑙 𝑝𝑑𝑎𝑡𝑜𝑠 = 𝑛𝑒𝑤 𝐽𝑃𝑎𝑛𝑒𝑙();

𝐽𝐵𝑢𝑡𝑡𝑜𝑛 𝑎𝑔𝑟𝑒𝑔𝑎𝑟 = 𝑛𝑒𝑤 𝐽𝐵𝑢𝑡𝑡𝑜𝑛("𝐴𝑔𝑟𝑒𝑔𝑎𝑟 𝑁𝑜𝑑𝑜");


𝑎𝑔𝑟𝑒𝑔𝑎𝑟. 𝑎𝑑𝑑𝐴𝑐𝑡𝑖𝑜𝑛𝐿𝑖𝑠𝑡𝑒𝑛𝑒𝑟(𝑛𝑒𝑤 𝐴𝑐𝑡𝑖𝑜𝑛𝐿𝑖𝑠𝑡𝑒𝑛𝑒𝑟(){

@𝑂𝑣𝑒𝑟𝑟𝑖𝑑𝑒
𝑝𝑢𝑏𝑙𝑖𝑐 𝑣𝑜𝑖𝑑 𝑎𝑐𝑡𝑖𝑜𝑛𝑃𝑒𝑟𝑓𝑜𝑟𝑚𝑒𝑑(𝐴𝑐𝑡𝑖𝑜𝑛𝐸𝑣𝑒𝑛𝑡 𝑒) {
𝑖𝑓(𝑚𝑎𝑥 < 10){
𝑡𝑟𝑦{
𝐺𝑟𝑎𝑓𝑜 𝑔𝑓 = 𝑛𝑒𝑤 𝐺𝑟𝑎𝑓𝑜("" + 𝐼𝑛𝑡𝑒𝑔𝑒𝑟. 𝑝𝑎𝑟𝑠𝑒𝐼𝑛𝑡(𝑣𝑎𝑙𝑜𝑟. 𝑔𝑒𝑡𝑇𝑒𝑥𝑡()));
𝑝𝑑. 𝑔𝑒𝑡𝑉𝑔𝑟𝑎𝑓𝑜𝑠(). 𝑎𝑑𝑑(𝑔𝑓);
𝑝𝑑. 𝑟𝑒𝑝𝑎𝑖𝑛𝑡();
𝑟𝑒𝑝𝑎𝑖𝑛𝑡();
𝑚𝑎𝑥 + +;
}𝑐𝑎𝑡𝑐ℎ(𝑁𝑢𝑚𝑏𝑒𝑟𝐹𝑜𝑟𝑚𝑎𝑡𝐸𝑥𝑐𝑒𝑝𝑡𝑖𝑜𝑛 𝑛𝑒){
𝐽𝑂𝑝𝑡𝑖𝑜𝑛𝑃𝑎𝑛𝑒. 𝑠ℎ𝑜𝑤𝑀𝑒𝑠𝑠𝑎𝑔𝑒𝐷𝑖𝑎𝑙𝑜𝑔(𝑛𝑢𝑙𝑙, "𝐷𝑖𝑔𝑖𝑡𝑒 𝑢𝑛 𝑛𝑢𝑚𝑒𝑟𝑜 𝑣𝑎𝑙𝑖𝑑𝑜");
}
}
}
});

𝑣𝑎𝑙𝑜𝑟 = 𝑛𝑒𝑤 𝐽𝑇𝑒𝑥𝑡𝐹𝑖𝑒𝑙𝑑(5);


𝑝𝑑𝑎𝑡𝑜𝑠. 𝑎𝑑𝑑(𝑛𝑒𝑤 𝐽𝐿𝑎𝑏𝑒𝑙("𝑉𝑎𝑙𝑜𝑟 𝑉𝑒𝑟𝑡𝑖𝑐𝑒" +
""));

51
𝑝𝑑𝑎𝑡𝑜𝑠. 𝑎𝑑𝑑(𝑣𝑎𝑙𝑜𝑟);
𝑝𝑑𝑎𝑡𝑜𝑠. 𝑎𝑑𝑑(𝑎𝑔𝑟𝑒𝑔𝑎𝑟);
𝑎𝑑𝑑(𝑝𝑑𝑎𝑡𝑜𝑠, 𝐵𝑜𝑟𝑑𝑒𝑟𝐿𝑎𝑦𝑜𝑢𝑡. 𝑆𝑂𝑈𝑇𝐻);

}
CLASE PANEL DE CONTROL

𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑎𝑤𝑡. 𝐵𝑎𝑠𝑖𝑐𝑆𝑡𝑟𝑜𝑘𝑒;


𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑎𝑤𝑡. 𝐶𝑜𝑙𝑜𝑟;
𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑎𝑤𝑡. 𝐺𝑟𝑎𝑝ℎ𝑖𝑐𝑠;
𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑎𝑤𝑡. 𝐺𝑟𝑎𝑝ℎ𝑖𝑐𝑠2𝐷;
𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑢𝑡𝑖𝑙. 𝑉𝑒𝑐𝑡𝑜𝑟;

𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎𝑥. 𝑠𝑤𝑖𝑛𝑔.∗;

𝑝𝑢𝑏𝑙𝑖𝑐 𝑐𝑙𝑎𝑠𝑠 𝑃𝑎𝑛𝑒𝑙𝐷𝑖𝑏𝑢𝑗𝑜 𝑒𝑥𝑡𝑒𝑛𝑑𝑠 𝐽𝑃𝑎𝑛𝑒𝑙 {

𝑖𝑛𝑡 𝑥 = 150;
𝑖𝑛𝑡 𝑦 = 150;
𝑖𝑛𝑡 𝑎𝑛𝑐ℎ𝑜 = 30;
𝑖𝑛𝑡 𝑎𝑙𝑡𝑜 = 30;
𝑝𝑢𝑏𝑙𝑖𝑐 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑥𝑣𝑠;
𝑝𝑢𝑏𝑙𝑖𝑐 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑦𝑣𝑠;
𝑝𝑢𝑏𝑙𝑖𝑐 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐺𝑟𝑎𝑓𝑜 > 𝑣𝑔𝑟𝑎𝑓𝑜𝑠;
𝑖𝑛𝑡 𝑖𝑛𝑑𝑖𝑐𝑒 = 0;

𝑝𝑢𝑏𝑙𝑖𝑐 𝑃𝑎𝑛𝑒𝑙𝐷𝑖𝑏𝑢𝑗𝑜(){
𝑣𝑔𝑟𝑎𝑓𝑜𝑠 = 𝑛𝑒𝑤 𝑉𝑒𝑐𝑡𝑜𝑟();
𝑥𝑣𝑠 = 𝑛𝑒𝑤 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑦𝑣𝑠 = 𝑛𝑒𝑤 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑠𝑒𝑡𝐷𝑜𝑢𝑏𝑙𝑒𝐵𝑢𝑓𝑓𝑒𝑟𝑒𝑑(𝑡𝑟𝑢𝑒);

52
}

𝑝𝑢𝑏𝑙𝑖𝑐 𝑣𝑜𝑖𝑑 𝑝𝑎𝑖𝑛𝑡𝐶𝑜𝑚𝑝𝑜𝑛𝑒𝑛𝑡(𝐺𝑟𝑎𝑝ℎ𝑖𝑐𝑠 𝑔𝑟𝑎𝑓𝑖𝑐𝑜){


𝑠𝑢𝑝𝑒𝑟. 𝑝𝑎𝑖𝑛𝑡𝐶𝑜𝑚𝑝𝑜𝑛𝑒𝑛𝑡𝑠(𝑔𝑟𝑎𝑓𝑖𝑐𝑜);
𝐺𝑟𝑎𝑝ℎ𝑖𝑐𝑠2𝐷 𝑔 = (𝐺𝑟𝑎𝑝ℎ𝑖𝑐𝑠2𝐷)𝑔𝑟𝑎𝑓𝑖𝑐𝑜;
𝑖𝑓(𝑣𝑔𝑟𝑎𝑓𝑜𝑠. 𝑠𝑖𝑧𝑒()! = 0){
𝑔. 𝑠𝑒𝑡𝐶𝑜𝑙𝑜𝑟(𝐶𝑜𝑙𝑜𝑟. 𝑊𝐻𝐼𝑇𝐸);
𝑔. 𝑓𝑖𝑙𝑙𝑅𝑒𝑐𝑡(0, 0, 𝑔𝑒𝑡𝑊𝑖𝑑𝑡ℎ(), 𝑔𝑒𝑡𝐻𝑒𝑖𝑔ℎ𝑡());
𝑔. 𝑠𝑒𝑡𝐶𝑜𝑙𝑜𝑟(𝐶𝑜𝑙𝑜𝑟. 𝐵𝐿𝐴𝐶𝐾);
𝑖𝑛𝑡 𝑟𝑎𝑑𝑖𝑜 = 100;
𝑓𝑙𝑜𝑎𝑡 𝑎𝑛𝑔𝑢𝑙𝑜 = 360/10;
𝑎𝑛𝑔𝑢𝑙𝑜 = (𝑓𝑙𝑜𝑎𝑡) 𝑀𝑎𝑡ℎ. 𝑡𝑜𝑅𝑎𝑑𝑖𝑎𝑛𝑠(𝑎𝑛𝑔𝑢𝑙𝑜);
𝑓𝑜𝑟(𝑖𝑛𝑡 𝑖 = 𝑖𝑛𝑑𝑖𝑐𝑒; 𝑖 < 𝑣𝑔𝑟𝑎𝑓𝑜𝑠. 𝑠𝑖𝑧𝑒(); 𝑖 + +){
𝑖𝑛𝑡 𝑥𝑣 = (𝑖𝑛𝑡)(𝑥 + 𝑟𝑎𝑑𝑖𝑜 ∗ 𝑀𝑎𝑡ℎ. 𝑐𝑜𝑠(𝑖 ∗ 𝑎𝑛𝑔𝑢𝑙𝑜));
𝑖𝑛𝑡 𝑦𝑣 = (𝑖𝑛𝑡) (𝑦 − 𝑟𝑎𝑑𝑖𝑜 ∗ 𝑀𝑎𝑡ℎ. 𝑠𝑖𝑛(𝑖 ∗ 𝑎𝑛𝑔𝑢𝑙𝑜));
𝑥𝑣𝑠. 𝑎𝑑𝑑(𝑥𝑣);
𝑦𝑣𝑠. 𝑎𝑑𝑑(𝑦𝑣);
𝑖𝑛𝑑𝑖𝑐𝑒 + +;
}
}
𝑓𝑜𝑟(𝑖𝑛𝑡 𝑖 = 0; 𝑖 < 𝑣𝑔𝑟𝑎𝑓𝑜𝑠. 𝑠𝑖𝑧𝑒(); 𝑖 + +){
𝑓𝑜𝑟(𝑖𝑛𝑡 𝑗 = 0; 𝑗 < 𝑣𝑔𝑟𝑎𝑓𝑜𝑠. 𝑠𝑖𝑧𝑒(); 𝑗 + +){
𝑔. 𝑠𝑒𝑡𝑆𝑡𝑟𝑜𝑘𝑒(𝑛𝑒𝑤 𝐵𝑎𝑠𝑖𝑐𝑆𝑡𝑟𝑜𝑘𝑒(2));
𝑔. 𝑠𝑒𝑡𝐶𝑜𝑙𝑜𝑟(𝐶𝑜𝑙𝑜𝑟. 𝐵𝐿𝐴𝐶𝐾);
𝑔. 𝑑𝑟𝑎𝑤𝐿𝑖𝑛𝑒(𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑖) + 15, 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑖) + 15, 𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑗) + 15, 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑗)
+ 15);
𝑔. 𝑠𝑒𝑡𝐶𝑜𝑙𝑜𝑟(𝐶𝑜𝑙𝑜𝑟. 𝑊𝐻𝐼𝑇𝐸);
𝑔. 𝑓𝑖𝑙𝑙𝑂𝑣𝑎𝑙(𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑖), 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑖), 𝑎𝑛𝑐ℎ𝑜, 𝑎𝑙𝑡𝑜);
𝑔. 𝑠𝑒𝑡𝐶𝑜𝑙𝑜𝑟(𝐶𝑜𝑙𝑜𝑟. 𝐵𝐿𝐴𝐶𝐾);
𝑔. 𝑑𝑟𝑎𝑤𝑂𝑣𝑎𝑙(𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑖), 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑖), 𝑎𝑛𝑐ℎ𝑜, 𝑎𝑙𝑡𝑜);
𝑔. 𝑑𝑟𝑎𝑤𝑆𝑡𝑟𝑖𝑛𝑔("" + 𝑣𝑔𝑟𝑎𝑓𝑜𝑠. 𝑔𝑒𝑡(𝑖). 𝑜𝑏𝑡𝑒𝑛𝑒𝑟𝐷𝑎𝑡𝑜(), 𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑖) + ((𝑎𝑛𝑐ℎ𝑜/2)
− 3), 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑖) + ((𝑎𝑙𝑡𝑜/2) + 3));
𝑔. 𝑠𝑒𝑡𝐶𝑜𝑙𝑜𝑟(𝐶𝑜𝑙𝑜𝑟. 𝑊𝐻𝐼𝑇𝐸);

53
𝑔. 𝑓𝑖𝑙𝑙𝑂𝑣𝑎𝑙(𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑗), 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑗), 𝑎𝑛𝑐ℎ𝑜, 𝑎𝑙𝑡𝑜);
𝑔. 𝑠𝑒𝑡𝐶𝑜𝑙𝑜𝑟(𝐶𝑜𝑙𝑜𝑟. 𝐵𝐿𝐴𝐶𝐾);
𝑔. 𝑑𝑟𝑎𝑤𝑂𝑣𝑎𝑙(𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑗), 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑗), 𝑎𝑛𝑐ℎ𝑜, 𝑎𝑙𝑡𝑜);
𝑔. 𝑑𝑟𝑎𝑤𝑆𝑡𝑟𝑖𝑛𝑔("" + 𝑣𝑔𝑟𝑎𝑓𝑜𝑠. 𝑔𝑒𝑡(𝑗). 𝑜𝑏𝑡𝑒𝑛𝑒𝑟𝐷𝑎𝑡𝑜(), 𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑗) + ((𝑎𝑛𝑐ℎ𝑜/2)
− 3), 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑗) + ((𝑎𝑙𝑡𝑜/2) + 3));
}
}
}
𝑝𝑢𝑏𝑙𝑖𝑐 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐺𝑟𝑎𝑓𝑜 > 𝑔𝑒𝑡𝑉𝑔𝑟𝑎𝑓𝑜𝑠() {
𝑟𝑒𝑡𝑢𝑟𝑛 𝑣𝑔𝑟𝑎𝑓𝑜𝑠;
}
𝑝𝑢𝑏𝑙𝑖𝑐 𝑣𝑜𝑖𝑑 𝑠𝑒𝑡𝑉𝑔𝑟𝑎𝑓𝑜𝑠(𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐺𝑟𝑎𝑓𝑜 > 𝑣𝑔𝑟𝑎𝑓𝑜𝑠) {
𝑡ℎ𝑖𝑠. 𝑣𝑔𝑟𝑎𝑓𝑜𝑠 = 𝑣𝑔𝑟𝑎𝑓𝑜𝑠;
}
}

CLASE GRAFO

𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑢𝑡𝑖𝑙. 𝑉𝑒𝑐𝑡𝑜𝑟;


𝑝𝑢𝑏𝑙𝑖𝑐 𝑐𝑙𝑎𝑠𝑠 𝐺𝑟𝑎𝑓𝑜 {

𝑝𝑟𝑖𝑣𝑎𝑡𝑒 𝑆𝑡𝑟𝑖𝑛𝑔 𝑑𝑎𝑡𝑜;

𝑝𝑢𝑏𝑙𝑖𝑐 𝐺𝑟𝑎𝑓𝑜(𝑆𝑡𝑟𝑖𝑛𝑔 𝑠){


𝑑𝑎𝑡𝑜 = 𝑠;
}

𝑝𝑢𝑏𝑙𝑖𝑐 𝑆𝑡𝑟𝑖𝑛𝑔 𝑜𝑏𝑡𝑒𝑛𝑒𝑟𝐷𝑎𝑡𝑜(){


𝑟𝑒𝑡𝑢𝑟𝑛 𝑑𝑎𝑡𝑜;
}
}
EJERCICIO
CLASE PRINCIPAL

54
CLASE PANEL DE DIBUJO

55
56
CLASE GRAFO

FUNCIONAMIENTO

57
58
3. Conclusiones

La clase Grafo solo es para almacenar el valor de cada grafo, además así es más orientada
a objetos y facilita la programación.

59
La clase Panel Dibujo es la que se encargar de dibujar los vértices o nodos y de pintar las
líneas que vendrían a hacer las aristas. Además, dibuja el valor del vértice. En esta clase
hay una parte del código que es pura matemática, esto lo que hace es hacer que el grafo
pinte los nodos en forma circular y así hacer que se vea más limpia a la vista la gráfica.

Lo que hacemos es primero calcular el ángulo de separación entre nodos, por eso 360 lo
divido entre 10, ya que este es el máximo de vértices a dibujar. Y luego en el para el
ángulo se va multiplicando por i, para poder ir moviéndose y así dibujar correctamente el
grafo.

La clase Principal es la encargada de crear el campo de texto para colocar el valor


del vértice a insertar y de crear el botón que va ir añadiendo vértices al grafo.

4. Recomendación

TEMA 3  RECORRIDOS POR AMPLITUD Y PROFUNDIDAD

Introducción

Los Árboles son las estructuras de datos más utilizadas, pero también una de las más
complejas, Los Árboles se caracterizan por almacenar sus nodos en forma jerárquica y no
en forma lineal como las Listas Ligadas, Colas, Pilas, etc.

Los recorridos son algoritmos que nos permiten recorrer un árbol en un orden especifico,
los recorridos nos pueden ayudar encontrar un nodo en el árbol, o buscar una posición
determinada para insertar o eliminar un nodo.

Encontramos también las búsquedas no informadas son aquellas en que se realiza el viaje
por todo el árbol sin tener una pista de donde pueda estar el dato deseado. Este tipo de
búsquedas también se conocen como búsquedas a ciegas.

60
1. Objetivo

Conocer la estructura que conforman los árboles para una comprensión clara y precisa.

Investigar ejercicios sobre el tema tratado para poner en práctica lo aprendido.

2. Procedimiento o desarrollo

RECORRIDOS POR AMPLITUD Y PROFUNDIDAD

Un GRAFO es un conjunto de nodos o vértices (V) y un conjunto de aristas (E), donde


cada arista relaciona a un par de nodos pertenecientes a V.

La estructura algebraica para los grafos es G = (V, E).

RECORRIDO DE GRAFOS.

El recorrido que se hace con este tipo de algoritmos es a cíclico por lo que se dice que el
recorrido es de árbol, sin embargo, la entrada sigue siendo un grafo.

Un árbol es un grafo conexo a cíclico, y para cada par de vértices distintos sólo existirá
un único camino. Un árbol está conformado por vértices (nodos) y arcos (aristas), al igual
que un grafo. Si existe un camino de longitud 1 entre dos nodos en un árbol uno de ellos
será el padre y el otro será el hijo. (Rodriguez, 2015)

Los vértices pueden ser de tres tipos:

Raíz: Es el único nodo que no tiene padre.

Nodo Interno: Es aquel que posee al menos un hijo.

Nodo Externo: Es aquel que no tiene hijos, también se le denomina hoja.

RECORRIDOS DE GRAFOS

Recorrido (o búsqueda) en profundidad

La idea es alejarse lo más posible del nodo inicial (sin repetir nodos), luego devolverse
un paso e intentar lo mismo por otro camino.

Recorrido (o búsqueda) en amplitud

Se visita a todos los vecinos directos del nodo inicial, luego a los vecinos de los vecinos,
etc. (Rodriguez, 2015).

61
ALGORITMO DE BÚSQUEDA EN AMPLITUD O ANCHURA (BFS readth First
Search)

Es un algoritmo para recorrer o buscar elementos en un grafo (usado frecuentemente sobre


árboles). Intuitivamente, se comienza en la raíz (eligiendo algún nodo como elemento raíz
en el caso de un grafo) y se exploran todos los vecinos de este nodo. A continuación, para
cada uno de los vecinos se exploran sus respectivos vecinos adyacentes, y así hasta que
se recorra todo el árbol. (Peñafiel, 2013)

La búsqueda en anchura supone que el recorrido se haga por niveles. Para entender más
fácilmente de que se trata, hemos indicado en la siguiente imagen un grafo ejemplo en
donde cada color representa un nivel, tomando como raíz o nodo inicial el que tiene el
número 1. El recorrido se hará en orden numérico de forma consecutiva hasta llegar al
nodo número 7. (Palma, 2014)

Ilustración 14Recorrido por Amplitud

La estrategia que usaremos para garantizar este recorrido es utilizar una cola que nos
permita almacenar temporalmente todos los nodos de un nivel, para ser procesados antes
de pasar al siguiente nivel hasta que la cola esté vacía.

𝑞𝑢𝑒𝑢𝑒 < 𝑆𝑡𝑎𝑡𝑒 > 𝑞;


𝑞. 𝑝𝑢𝑠ℎ(𝑆𝑡𝑎𝑡𝑒(𝑟𝑎𝑖
𝑚𝑎𝑟𝑘[𝑟𝑎𝑖𝑧] = 𝑡𝑟𝑢𝑒;

62
Inmediatamente después de declarar nuestra estructura de cola, agregamos el nodo raíz
para poder iniciar el proceso de búsqueda. Esto se hace porque necesitamos tener al menos
un elemento en nuestra cola, dado que la condición de salida es que la cola esté vacía.
Luego marcamos el nodo raíz como visitado.

𝑤ℎ𝑖𝑙𝑒(! 𝑞. 𝑒𝑚𝑝𝑡𝑦())

𝑆𝑡𝑎𝑡𝑒 𝑠𝑡 = 𝑞. 𝑓𝑟𝑜𝑛𝑡();
𝑞. 𝑝𝑜𝑝();
𝑖𝑓 (𝑠𝑡. 𝑛𝑜𝑑𝑒 == 𝑛𝑜𝑑𝑜){
𝑝𝑟𝑖𝑛𝑡𝑓("′%𝑑′𝑛", 𝑛𝑜𝑑𝑜);
𝑟𝑒𝑡𝑢𝑟𝑛;
}𝑒𝑙𝑠𝑒 𝑝𝑟𝑖𝑛𝑡𝑓("%𝑑 ", 𝑠𝑡. 𝑛𝑜𝑑𝑒);

𝑖𝑛𝑡 𝑇 = (𝑖𝑛𝑡)𝑔𝑟𝑎𝑝ℎ. 𝐺[𝑠𝑡. 𝑛𝑜𝑑𝑒]. 𝑠𝑖𝑧𝑒();


𝑓𝑜𝑟(𝑖𝑛𝑡 𝑖 = 0; 𝑖 < 𝑇; + + 𝑖)
{
𝑖𝑓 (! 𝑚𝑎𝑟𝑘[𝑔𝑟𝑎𝑝ℎ. 𝐺[𝑠𝑡. 𝑛𝑜𝑑𝑒][𝑖]. 𝑛𝑜𝑑𝑒])
{
𝑚𝑎𝑟𝑘[𝑔𝑟𝑎𝑝ℎ. 𝐺[𝑠𝑡. 𝑛𝑜𝑑𝑒][𝑖]. 𝑛𝑜𝑑𝑒] = 𝑡𝑟𝑢𝑒;
𝑞. 𝑝𝑢𝑠ℎ(𝑆𝑡𝑎𝑡𝑒(𝑔𝑟𝑎𝑝ℎ. 𝐺[𝑠𝑡. 𝑛𝑜𝑑𝑒][𝑖]. 𝑛𝑜𝑑𝑒));
}
}
}

Cada vez que visitamos un nodo, lo desencolamos e imprimimos por pantalla el valor del
nodo para ir indicando el recorrido. Luego agregamos a la cola todos los nodos del
siguiente nivel y los marcamos como visitados antes de comenzar el ciclo de nuevo, en el
que procesaremos estos nuevos nodos que hemos agregado a la cola.

Si encontramos el elemento buscado, la función BFS retornará al “main” e imprimirá


entre comillas simples el valor del elemento buscado.

63
Podríamos hacer otro tipo de mensaje para indicar que el elemento ha sido encontrado,
calcular el número de nodos que fueron visitados o incluso generar un mensaje especial
en el caso de que el elemento no haya sido encontrado. Por el momento la función ha
quedado lo más sencilla posible para enfocarnos únicamente en cómo hacer el recorrido.

ALGORITMO DE BÚSQUEDA EN PROFUNDIDAD (DFS Depth First Search)

Es un algoritmo que permite recorrer todos los nodos de un grafo o árbol (teoría de grafos)
de manera ordenada, pero no uniforme. Su funcionamiento consiste en ir expandiendo
todos y cada uno de los nodos que va localizando, de forma recurrente, en un camino
concreto. Cuando ya no quedan más nodos que visitar en dicho camino, regresa
(Backtracking), de modo que repite el mismo proceso con cada uno de los hermanos del
nodo ya procesado. (Peñafiel, 2013)

En el caso de la búsqueda en profundidad lo que se quiere es recorrer desde la raíz hasta


los nodos extremos u hojas por cada una de las ramas. En este caso los niveles de cada
nodo no son importantes. En la siguiente imagen podemos ver el orden en que se hace el
recorrido desde el nodo raíz, indicado con el número uno, hasta el nodo número siete.
(Palma, 2014)

Ilustración 15 Recorrido por Profundidad

64
La forma más intituiva de hacer este algoritmo es de forma recursiva, de lo contrario
tendríamos que usar en lugar de una cola una pila, pero con la recursión nos ahorramos
la necesidad de utilizar esta estructura explícitamente y en lugar de ello nos valemos de
la pila de recursión.

En este caso pasaremos por parámetro el nodo a buscar y el nodo actual (El nodo que está
siendo visitado en cada ambiente de recursión), que en la primera llamada será el nodo
raíz.

𝑣𝑜𝑖𝑑 𝐷𝐹𝑆(𝑐𝑜𝑛𝑠𝑡 𝑖𝑛𝑡 𝑛𝑜𝑑𝑜, 𝑖𝑛𝑡 𝑛𝑜𝑑𝑜𝐴𝑐𝑡){

𝑚𝑎𝑟𝑘[𝑛𝑜𝑑𝑜𝐴𝑐𝑡] = 𝑡𝑟𝑢𝑒;

𝑖𝑓(𝑚𝑎𝑟𝑘[𝑛𝑜𝑑𝑜] == 𝑡𝑟𝑢𝑒) 𝑟𝑒𝑡𝑢𝑟𝑛;

𝑖𝑓 (𝑛𝑜𝑑𝑜𝐴𝑐𝑡 == 𝑛𝑜𝑑𝑜){

𝑝𝑟𝑖𝑛𝑡𝑓("′%𝑑′𝑛", 𝑛𝑜𝑑𝑜);

𝑟𝑒𝑡𝑢𝑟𝑛;

}𝑒𝑙𝑠𝑒 𝑖𝑓(𝑚𝑎𝑟𝑘[𝑛𝑜𝑑𝑜] == 𝑡𝑟𝑢𝑒) 𝑟𝑒𝑡𝑢𝑟𝑛;

𝑒𝑙𝑠𝑒{

𝑝𝑟𝑖𝑛𝑡𝑓("%𝑑 ", 𝑛𝑜𝑑𝑜𝐴𝑐𝑡);

𝑖𝑛𝑡 𝑇 = (𝑖𝑛𝑡)𝑔𝑟𝑎𝑝ℎ. 𝐺[𝑛𝑜𝑑𝑜𝐴𝑐𝑡]. 𝑠𝑖𝑧𝑒();

𝑓𝑜𝑟(𝑖𝑛𝑡 𝑖 = 0; 𝑖 < 𝑇; + + 𝑖)

𝑖𝑓 (! 𝑚𝑎𝑟𝑘[𝑔𝑟𝑎𝑝ℎ. 𝐺[𝑛𝑜𝑑𝑜𝐴𝑐𝑡][𝑖]. 𝑛𝑜𝑑𝑒]) 𝐷𝐹𝑆(𝑛𝑜𝑑𝑜, 𝑔𝑟𝑎𝑝ℎ. 𝐺[𝑛𝑜𝑑𝑜𝐴𝑐𝑡][𝑖]. 𝑛𝑜𝑑𝑒);

65
En cada llamada recursiva marcaremos el nodo actual como visitado y luego verificamos
si es el nodo buscado para salir de la recursión, este será nuestro caso base. De no ser el
nodo requerido, se hace la llamada recursiva con todos los nodos hijos del nodo actual,
pero en este caso, a diferencia del recorrido BFS, no se visitarán todos los hijos de forma
consecutiva, sino que el algoritmo recorrerá en profundidad hasta llegar a un nodo
extremo o nodo hoja, antes de retornar al ambiente de recursión en donde se encuentran
los otros nodos hijos.

EJEMPLO DE RECORRIDO POR AMPLITUD Y PROFUNDIDAD

𝑖𝑚𝑝𝑜𝑟𝑡 𝑗𝑎𝑣𝑎. 𝑢𝑡𝑖𝑙. 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡;

/∗∗
∗ 𝐶𝑙𝑎𝑠𝑒 𝐺𝑟𝑎𝑓𝑜
∗/
𝑝𝑢𝑏𝑙𝑖𝑐 𝑐𝑙𝑎𝑠𝑠 𝐺𝑟𝑎𝑓𝑜 {

𝑝𝑢𝑏𝑙𝑖𝑐 𝑖𝑛𝑡[][] 𝑔 = {{2, 1, 0, 1, 0},


{1, 2, 1, 0, 0},
{0, 1, 2, 1, 0},
{1, 0, 1, 2, 1},
{0, 0, 0, 1, 2}};
𝑝𝑟𝑖𝑣𝑎𝑡𝑒 𝑏𝑜𝑜𝑙𝑒𝑎𝑛[] 𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝐴𝑛𝑐ℎ𝑢𝑟𝑎 = 𝑛𝑒𝑤 𝑏𝑜𝑜𝑙𝑒𝑎𝑛[5];
𝑝𝑟𝑖𝑣𝑎𝑡𝑒 𝑏𝑜𝑜𝑙𝑒𝑎𝑛[] 𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑 = 𝑛𝑒𝑤 𝑏𝑜𝑜𝑙𝑒𝑎𝑛[5];

𝑝𝑢𝑏𝑙𝑖𝑐 𝐺𝑟𝑎𝑓𝑜() {
}

𝑝𝑢𝑏𝑙𝑖𝑐 𝑖𝑛𝑡[][] 𝑔𝑒𝑡𝐺() {


𝑟𝑒𝑡𝑢𝑟𝑛 𝑔;
}

RECORRIDO POR AMPLITUD

66
𝑝𝑢𝑏𝑙𝑖𝑐 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝐴𝑛𝑐ℎ𝑢𝑟𝑎(𝑖𝑛𝑡 𝑛𝑜𝑑𝑜𝐼) {

𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠 = 𝑛𝑒𝑤 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();

𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝐴𝑛𝑐ℎ𝑢𝑟𝑎[𝑛𝑜𝑑𝑜𝐼] = 𝑡𝑟𝑢𝑒;

𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑐𝑜𝑙𝑎 = 𝑛𝑒𝑤 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();

𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠. 𝑎𝑑𝑑(𝑛𝑜𝑑𝑜𝐼);

𝑐𝑜𝑙𝑎. 𝑎𝑑𝑑(𝑛𝑜𝑑𝑜𝐼);

𝑤ℎ𝑖𝑙𝑒 (! 𝑐𝑜𝑙𝑎. 𝑖𝑠𝐸𝑚𝑝𝑡𝑦()) {


𝑖𝑛𝑡 𝑗 = 𝑐𝑜𝑙𝑎. 𝑟𝑒𝑚𝑜𝑣𝑒(0);

𝑓𝑜𝑟 (𝑖𝑛𝑡 𝑖 = 0; 𝑖 < 𝑔. 𝑙𝑒𝑛𝑔𝑡ℎ; 𝑖 + +) {

𝑖𝑓 (𝑔[𝑗][𝑖] == 1 && ! 𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝐴𝑛𝑐ℎ𝑢𝑟𝑎[𝑖]) {


𝑐𝑜𝑙𝑎. 𝑎𝑑𝑑(𝑖);
𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠. 𝑎𝑑𝑑(𝑖);
𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝐴𝑛𝑐ℎ𝑢𝑟𝑎[𝑖] = 𝑡𝑟𝑢𝑒;
}
}
}
𝑟𝑒𝑡𝑢𝑟𝑛 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠;
}

RECORRIDO POR PROFUNDIDAD

𝑝𝑢𝑏𝑙𝑖𝑐 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑(𝑖𝑛𝑡 𝑛𝑜𝑑𝑜𝐼) {

67
𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠 = 𝑛𝑒𝑤 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑[𝑛𝑜𝑑𝑜𝐼] = 𝑡𝑟𝑢𝑒;

𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑐𝑜𝑙𝑎 = 𝑛𝑒𝑤 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠. 𝑎𝑑𝑑(𝑛𝑜𝑑𝑜𝐼);
𝑐𝑜𝑙𝑎. 𝑎𝑑𝑑(𝑛𝑜𝑑𝑜𝐼);
𝑤ℎ𝑖𝑙𝑒 (! 𝑐𝑜𝑙𝑎. 𝑖𝑠𝐸𝑚𝑝𝑡𝑦()) {
𝑖𝑛𝑡 𝑗 = 𝑐𝑜𝑙𝑎. 𝑟𝑒𝑚𝑜𝑣𝑒(0);

𝑓𝑜𝑟 (𝑖𝑛𝑡 𝑖 = 0; 𝑖 < 𝑔. 𝑙𝑒𝑛𝑔𝑡ℎ; 𝑖 + +) {

𝑖𝑓 (𝑔[𝑗][𝑖] == 1 && ! 𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑[𝑖]) {


𝑐𝑜𝑙𝑎. 𝑎𝑑𝑑(𝑖);

𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠. 𝑎𝑑𝑑𝐴𝑙𝑙(𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑(𝑖));
𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑[𝑖] = 𝑡𝑟𝑢𝑒;
}
}
}
𝑟𝑒𝑡𝑢𝑟𝑛 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠;
}
}

68
Para probar los métodos se ejecuta el siguiente código:

𝑝𝑢𝑏𝑙𝑖𝑐 𝑐𝑙𝑎𝑠𝑠 𝑃𝑟𝑢𝑒𝑏𝑎 {

/∗∗
∗/
𝑝𝑢𝑏𝑙𝑖𝑐 𝑠𝑡𝑎𝑡𝑖𝑐 𝑣𝑜𝑖𝑑 𝑚𝑎𝑖𝑛(𝑆𝑡𝑟𝑖𝑛𝑔[] 𝑎𝑟𝑔𝑠) {

𝐺𝑟𝑎𝑓𝑜 𝑔 = 𝑛𝑒𝑤 𝐺𝑟𝑎𝑓𝑜();


𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑒𝑛𝐴𝑛𝑐ℎ𝑢𝑟𝑎 = 𝑔. 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝐴𝑛𝑐ℎ𝑢𝑟𝑎(0);
𝑆𝑦𝑠𝑡𝑒𝑚. 𝑜𝑢𝑡. 𝑝𝑟𝑖𝑛𝑡𝑙𝑛(“𝑅𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜 𝑒𝑛 𝑎𝑛𝑐ℎ𝑢𝑟𝑎 𝑑𝑒 𝑢𝑛 𝑔𝑟𝑎𝑓𝑜 𝑟𝑒𝑝𝑟𝑒𝑠𝑒𝑛𝑡𝑎𝑑𝑜 𝑐𝑜𝑚𝑜 𝑚𝑎𝑡𝑟𝑖𝑧: “);
𝑓𝑜𝑟(𝑖𝑛𝑡 𝑖 = 0; 𝑖 < 𝑒𝑛𝐴𝑛𝑐ℎ𝑢𝑟𝑎. 𝑠𝑖𝑧𝑒(); 𝑖 + +){
𝑆𝑦𝑠𝑡𝑒𝑚. 𝑜𝑢𝑡. 𝑝𝑟𝑖𝑛𝑡(“” + 𝑒𝑛𝐴𝑛𝑐ℎ𝑢𝑟𝑎. 𝑔𝑒𝑡(𝑖) + ” “);
}
𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑒𝑛𝑃𝑟𝑜𝑓𝑢𝑛𝑑𝑖𝑑𝑎𝑑 = 𝑔. 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑(0);
𝑆𝑦𝑠𝑡𝑒𝑚. 𝑜𝑢𝑡. 𝑝𝑟𝑖𝑛𝑡𝑙𝑛(“”);
𝑆𝑦𝑠𝑡𝑒𝑚. 𝑜𝑢𝑡. 𝑝𝑟𝑖𝑛𝑡𝑙𝑛(“𝑅𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜 𝑒𝑛 𝑝𝑟𝑜𝑓𝑢𝑛𝑑𝑖𝑑𝑎𝑑 𝑑𝑒
𝑢𝑛 𝑔𝑟𝑎𝑓𝑜 𝑟𝑒𝑝𝑟𝑒𝑠𝑒𝑛𝑡𝑎𝑑𝑜 𝑐𝑜𝑚𝑜 𝑚𝑎𝑡𝑟𝑖𝑧: “);
𝑓𝑜𝑟(𝑖𝑛𝑡 𝑖 = 0; 𝑖 < 𝑒𝑛𝑃𝑟𝑜𝑓𝑢𝑛𝑑𝑖𝑑𝑎𝑑. 𝑠𝑖𝑧𝑒(); 𝑖 + +){
𝑆𝑦𝑠𝑡𝑒𝑚. 𝑜𝑢𝑡. 𝑝𝑟𝑖𝑛𝑡(“” + 𝑒𝑛𝑃𝑟𝑜𝑓𝑢𝑛𝑑𝑖𝑑𝑎𝑑. 𝑔𝑒𝑡(𝑖) + ” “);
}
}
}

3. Conclusión

4. Recomendación

Tema 4  El algoritmo del camino más corto (algoritmos de Dijkstra y Floyd)

69
TEMA 5 ÁRBOL DE EXPANSIÓN MININA (ALGORITMOS DE KRUSKAL
Y PRIM)

Introducción

Árbol de expansión

Un árbol de expansión es un árbol compuesto por todos los vértices y algunas


(posiblemente todas) de las aristas. Al ser creado un árbol no existirán ciclos, además
debe existir una ruta entre cada par de vértices.

Un grafo puede tener muchos árboles de expansión, veamos un ejemplo con el siguiente
grafo:

Se observa que el grafo dado posee 3 árboles de expansión, dichos arboles cumplen con
las propiedades antes mencionadas como son unir todos los vértices usando algunas
aristas.

1. Objetivo

Aprender los métodos o algoritmos que existen para un árbol de expansión mínima y
definición del mismo.

2. Procedimiento o desarrollo

70
- Árbol de expansión mínima

El árbol de expansión mínima es apropiado para problemas en los cuales la redundancia


es expansiva, o el flujo a lo largo de los arcos se considera instantáneo.

El problema surge cuando todos los nodos de una red deben conectarse entre ellos sin
formar un ciclo.

La aplicación de estos problemas de optimización se ubica en las redes de comunicación


eléctrica, telefónica, carretera, ferroviaria, aérea, marítima, hidráulica o de gas, etc. donde
los nodos representan puntos de consumo eléctrico, teléfonos, aeropuertos, computadoras
y los arcos podrían ser de alta tensión, cable de fibra óptica, rutas aéreas, agua, gas, entre
otros.

También se le conoce como árbol generador mínimo, es una red conexa y ponderada que
se refiere a utilizar los arcos de la red para llegar a todos los nodos de esta, de manera tal
que se minimiza la longitud total. Para su solución se emplean los algoritmos de Prim y
Kruskal. (Nieto, 2012, pág. 2)

El árbol de expansión mínima es apropiado para problemas en los cuales la redundancia


es expansiva, o el flujo a lo largo de los arcos se considera instantáneo.

Este problema se refiere a utilizar las ramas o arcos de la red para llegar a todos los nodos
de la red, de manera tal que se minimiza la longitud total. (Bustos, 2011)

- Algoritmo Kruskal

Este algoritmo es de tipo “voraz” o “greedy”. Como se quiere construir un árbol generador
de peso mínimo la estrategia será ir añadiendo aristas de mínimo peso hasta conseguir un
árbol generador. En cada paso, incorporación de una nueva arista, se debe comprobar que
no se forme ningún ciclo con las aristas previamente introducidas.

- Union-Find (Disjoint-Set)

Union Find es una estructura de datos que modela una colección de conjuntos disjuntos
(disjoint-sets) y está basado en 2 operaciones:

- Find(A): Determina a cual conjunto pertenece el elemento A. Esta operación


puede ser usada para determinar si 2 elementos están o no en el mismo conjunto.

71
- Union(A, B): Une todo el conjunto al que pertenece A con todo el conjunto al que
pertenece B, dando como resultado un nuevo conjunto basado en los elementos
tanto de A como de B.

Estas operaciones me servirán para la implementación del algoritmo de Kruskal o


problemas que involucran particionamiento como encontrar las componentes conexas en
un grafo.

- Función - Como Trabaja

Primeramente ordenaremos las aristas del grafo por su peso de menor a mayor. Mediante
la técnica greedy Kruskal intentara unir cada arista siempre y cuando no se forme un ciclo,
ello se realizará mediante Union-Find. Como hemos ordenado las aristas por peso
comenzaremos con la arista de menor peso, si los vértices que contienen dicha arista no
están en la misma componente conexa entonces los unimos para formar una sola
componente mediante Union(x, y), para revisar si están o no en la misma componente
conexa usamos la función SameComponent(x, y) al hacer esto estamos evitando que se
creen ciclos y que la arista que une dos vértices siempre sea la mínima posible.

- Funcionamiento del Algoritmo de Krustal

- Se selecciona, de entre todas las aristas restantes, la de menor peso siempre que
no cree ningún ciclo.
- Se repite el paso 1 hasta que se hayan seleccionado |V| - 1 aristas.

Nota: Siendo V el número de vértices.

- Ejemplo de Ejecución

72
Grafo Descripción

Este es el grafo inicial. Los números indican el peso


de las aristas. Se elige de manera aleatoria uno de los
vértices que será el vértice de partida. N este caso se
ha elegido el vértice D.

Se selecciona, de entre todas las aristas restantes, la


de menor siempre que no cree ningún ciclo. Las
aristas de menor peso son las aristas AD y CE (5). Se
ha seleccionado de manera aleatoria la arista AD.

Se selecciona, de entre todas las aristas restantes, la


de menor siempre que no cree ningún ciclo. Ésta es
la arista CE.

Seleccionamos DF, con peso 6, que es la siguiente


arista de menor peso que no forma ciclos.

73
De las aristas restantes, las de menor peso son las
aristas AB y BE, de peso 7. AB se elige
aleatoriamente, y se añade al conjunto de las aristas
seleccionadas. De este modo, la arista DB no puede
ser seleccionada ya que formaría el ciclo ADB. Por
tanto la marcamos en rojo.

Siguiendo el proceso seleccionamos la arista BE con


peso 7. Además marcamos en rojo las aristas BC,
DE y FE ya que formarían los ciclos BCE, DEBA,
FEBAD respectivamente.

Por último se selecciona la arista EG de peso


9. Como han sido seleccionadas un número de aristas
igual al número de vértices menos uno, el proceso ha
terminado. Se ha obtenido el árbol de expansión
mínima con un peso de 39.

Ejercicio - Código Java

74
75
- Algoritmo Prim

Algoritmo de Prim es un algoritmo perteneciente a la teoría de los grafos para encontrar


un árbol recubridor mínimo en un grafo conexo, no dirigido y cuyas aristas están
etiquetadas.

En otras palabras, el algoritmo encuentra un subconjunto de aristas que forman un árbol


con todos los vértices, donde el peso total de todas las aristas en el árbol es el mínimo
posible. Si el grafo no es conexo, entonces el algoritmo encontrará el árbol recubridor

76
mínimo para uno de los componentes conexos que forman dicho grafo no conexo.
(Cormen, Leiserson, Rivest, & Stein, 2001)

- Función - Como Trabaja

El algoritmo incrementa continuamente el tamaño de un árbol, comenzando por un vértice


inicial al que se le van agregando sucesivamente vértices cuya distancia a los anteriores
es mínima. Esto significa que en cada paso, las aristas a considerar son aquellas que
inciden en vértices que ya pertenecen al árbol.

El árbol recubierto mínimo está completamente construido cuando no quedan más


vértices por agregar.

Requisitos para utilizar el Algoritmo de Prim

- Ser un grafo conexo


- Ser un grafo sin ciclos
- Tener todos los arcos etiquetados

Funcionamiento del Algoritmo de Prim

- Se marca un vértice cualquiera. Será el vértice de partida.


- Se selecciona la arista de menor peso incidente en el vértice seleccionado
anteriormente y se selecciona el otro vértice en el que incide dicha arista.
- Repetir el paso 2 siempre que la arista elegida enlace un vértice seleccionado y
otro que no lo esté. Es decir, siempre que la arista elegida no cree ningún ciclo.
- El árbol de expansión mínima será encontrado cuando hayan sido seleccionados
todos los vértices del grafo.

77
Ejemplo de Ejecución

Grafo Descripción

Este es el grafo inicial. Los números indican el peso


de las aristas. Se elige de manera aleatoria uno de
los vértices que será el vértice de partida. En este
caso se ha elegido el vértice D.

Se selecciona la arista de menor peso de entre todos


los incidentes en el vértice D, siempre que la arista
seleccionada no cree ningún ciclo. En este caso es la
arista AD.

Ahora se selecciona la arista de menor peso de entre


todos los incidentes en los vértices D y A, siempre
que la arista seleccionada no cree ningún ciclo. En
este caso es la arista DF.

Se selecciona la arista de menor peso de entre todos


los incidentes en los vértices D, A y F, siempre que
la arista seleccionada no cree ningún ciclo. En este
caso es la arista AB. Llegado a este punto, la arista
DB no podrá ser seleccionada, ya que formaría el
ciclo ABD.

78
Se selecciona la arista de menor peso de entre todos
los incidentes en los vértices D, A, F y B, siempre
que la arista seleccionada no cree ningún ciclo. En
este caso es la arista BE. Llegado a este punto, las
aristas DE y EF no podrán ser seleccionadas, ya que
formarían los ciclos ABED y ABEFD
respectivamente.

Se selecciona la arista de menor peso de entre todos


los incidentes en los vértices D, A, F, B y E, siempre
que la arista seleccionada no cree ningún ciclo. En
este caso es la arista EC. Llegado a este punto, la
arista BC no podrá ser seleccionada, ya que formaría
el ciclo BEC.

Solo que disponible el vértice G, por lo tanto se


selecciona la arista de menor peso que incide en
dicho vértice. Es la arista EG. Como todos los
vértices ya han sido seleccionados el proceso ha
terminado. Se ha obtenido el árbol de expansión
mínima con un peso de 39.

3. Conclusiones

- Un modelo de árbol de expansión mínima es muy utilizado para la resolución de


muchos problemas comerciales como la de conexión de tubería, cableado entre
otros.
- Una de las grandes diferencias entre el modelo de red de árbol de expansión
mínima con respecto a otros modelos de redes es que tiene un inicio pero no un
final, puesto que en este modelo todos los nodos son un destino.

79
4. Recomendaciones

Entender de forma más clara cada método o algoritmo para la solución del modelo de
árbol de expansión mínima.

TEMA 6  ORDENAMIENTO TOPOLÓGICO

Introducción

La ordenación topológica mediante algoritmos de grafos es una utilidad que facilita la


toma de decisiones. Es uno de los algoritmos más conocidos de grafos, el cual se emplea
para hallar un orden en una lista de todos los nodos del grafo (dirigido acíclico) de tal
forma que sea visitado antes que sus predecesores (padres)

Es un sistema de ordenamiento de un grafo acíclico (no tiene ciclos). Consiste en


organizar de forma lineal/lista (ascendente/descendente), una serie de vértices en
desorden, primero se debe de empezar de un "vértice padre" (sin predecesores), y después
visitar a sus vecinos, después de que haya visitado a todos sus vecinos, pasa a analizar
otro vértice, identifica sus vecinos, y así recursivamente, hasta que haya visitado a todos
los vértices. “En pocas palabras no se visitará un vértice, hasta que todos sus predecesores
hayan sido visitados”. (Aguilar, 2017)

1. Objetivo

Analizar el ordenamiento topológico en la materia de análisis de algoritmos para su


aplicación en diferentes ejercicios.

2. Procedimiento o desarrollo

ORDENAMIENTO TOPOLOGICO: CÓDIGO JAVA

80
Resultados

3. Conclusiones

Con lo estudiado antes podemos concluir que una ordenación topológica de un grafo
acíclico G dirigido es una ordenación lineal de todos los nodos de G que conserva la unión
entre vértices del grafo G original. La condición que el grafo no contenga ciclos es
importante, ya que no se puede obtener ordenación topológica de grafos que contengan
ciclos.

El ordenamiento topológico es importante para el aprendizaje de algoritmos de


ordenación ya que a través de este se puede tomar decisiones de manera más clara y
precisa, además que brinda cierta facilidad cuando se realizan ordenamientos.

4. Recomendaciones

Este algoritmo presenta una cierta dificultad por eso es importante que se investigue más
sobre este tema para tener más claro lo que se va a realizar y cuando se puede utilizar este
tipo de ordenamiento.

De igual forma se debe poner en práctica este ejercicio cuando se crea conveniente para
no olvidar lo aprendido.

81
Unidad 4

Quicksort

TEMA 1  BÚSQUEDA SECUENCIAL Y BINARIA

Introducción

Búsqueda secuencial.
La búsqueda secuencial, también se le conoce como búsqueda lineal.
Supongamos una colección de registros organizados como una lista lineal. El algoritmo
básico de búsqueda secuencial consiste en empezar al inicio de la lista e ir a través de
cada registro hasta encontrar la clave indicada (k) o hasta el final de la lista.
Este método consiste en recorrer el arreglo o vector elemento a elemento e ir comparando
con el valor buscado (clave). Se empieza con la primera casilla del vector y se observa
una casilla tras otra hasta que se encuentre el elemento buscado o se han visto todas las
casillas. El resultado de la búsqueda es un solo valor, y será la posición del elemento
buscado o cero.
Este tipo de búsqueda compara cada elemento del vector con el valor a encontrar hasta
que este se consiga o se termine de leer el vector completo.
Sintaxis:
𝑓𝑜𝑟(𝑖𝑛𝑡 𝑒𝑙𝑒𝑚 = 0; 𝑒𝑙𝑒𝑚 <= 𝑡𝑎𝑚 − 1; 𝑒𝑙𝑒𝑚 + +){
𝑖𝑓(𝑛𝑢𝑚𝑒𝑟𝑜𝑠[𝑒𝑙𝑒𝑚] == 𝑛𝑢𝑚){
𝑒𝑛𝑐𝑜𝑛𝑡𝑟𝑎𝑑𝑜 = 𝑡𝑟𝑢𝑒;
}
}

Búsqueda Binaria.
La búsqueda binaria es el método, donde si el arreglo o vector está bien ordenado, se
reduce sucesivamente la operación eliminando repetidas veces la mitad de la lista restante.
El proceso comienza comparando el elemento central del arreglo con el elemento
buscado. Si ambos coinciden finaliza la búsqueda. Si no ocurre así, el elemento buscado
será mayor o menor en sentido estricto que el elemento central del arreglo. Si el elemento
buscado es mayor se procede a hacer búsqueda binaria en el subarray superior, si el

82
elemento buscado es menor que el contenido de la casilla central, se debe cambiar el
segmento a considerar al segmento que está a la izquierda de tal sitio central.
Es un método que se basa en la división sucesiva del espacio ocupado por el vector en
sucesivas mitades, hasta encontrar el elemento buscado.
Sintaxis:
𝑤ℎ𝑖𝑙𝑒(𝑖𝑛𝑓 <= 𝑠𝑢𝑝){
𝑐𝑒𝑛𝑡𝑟𝑜 = (𝑠𝑢𝑝 + 𝑖𝑛𝑓)/2;
𝑖𝑓(𝑣𝑒𝑐𝑡𝑜𝑟[𝑐𝑒𝑛𝑡𝑟𝑜] == 𝑑𝑎𝑡𝑜) 𝑟𝑒𝑡𝑢𝑟𝑛 𝑐𝑒𝑛𝑡𝑟𝑜;
𝑒𝑙𝑠𝑒 𝑖𝑓(𝑑𝑎𝑡𝑜 < 𝑣𝑒𝑐𝑡𝑜𝑟 [𝑐𝑒𝑛𝑡𝑟𝑜] ){
𝑠𝑢𝑝 = 𝑐𝑒𝑛𝑡𝑟𝑜 − 1;
}
𝑒𝑙𝑠𝑒 {
𝑖𝑛𝑓 = 𝑐𝑒𝑛𝑡𝑟𝑜 + 1;
}
}
Diferencias entre ambos métodos.
En el caso del método de búsqueda binaria, los arreglos deben estar únicamente
ordenados, como se planteó anteriormente, por su parte el método de búsqueda secuencial
o lineal, puede emplearse tanto en arreglos pequeños, como en aquellos que no están
ordenados.
En segundo orden, podemos ver que el método de búsqueda binaria, es el método más
eficiente para encontrar elementos en un arreglo ordenado, lo contrario sucede con el
método de búsqueda secuencial ya que este es muy lento, pero si los datos no están en
orden es el único método que puede emplearse para hacer las búsquedas.
1. Objetivo

Verificar el funcionamiento de los métodos de búsqueda y adaptar su sintaxis a la


programación.

2. Procedimiento o desarrollo

83
Búsqueda Secuencial

84
Búsqueda Binaria

3. Conclusión

Con este tipo de métodos de búsqueda se puede mejorar la precisión al momento de


hacer una búsqueda en el programa.

4. Recomendación

Se recomienda identificar los métodos búsqueda y asi implementarlos en el código a


usar.

85
TEMA 2  ALGORITMOS CUADRÁTICOS DE ORDENAMIENTO
(SELECCIÓN, INSERCIÓN)

TEMA 3  ALGORITMOS DE TIPO O (LOGN) (QUICKSORT, HEAPSORT,


MERGESORT)

TEMA 4 TABLAS DE (HASH) INCLUYENDO ESTRATEGIAS DE


SOLUCIÓN PARA COLISIONES.

Introducción

Tablas Hash

Una tabla hash, matriz asociativa, mapa hash, tabla de dispersión o tabla fragmentada es

una estructura de datos que asocia llaves o claves con valores. La operación principal que

soporta de manera eficiente es la búsqueda: permite el acceso a los elementos (teléfono y

dirección, por ejemplo) almacenados a partir de una clave generada (usando el nombre o

número de cuenta, por ejemplo). Funciona transformando la clave con una función hash

en un hash, un número que identifica la posición (casilla ocubeta) donde la tabla hash

localiza el valor deseado.

Un ejemplo práctico para ilustrar que es una tabla hash es el siguiente: Se necesita

organizar los periódicos que llegan diariamente de tal forma que se puedan ubicar de

86
forma rápida, entonces se hace de la siguiente forma - se hace una gran caja para guardar

todos los periódicos (una tabla), y se divide en 31 contenedores (ahora es una "hash table"

o tabla fragmentada), y la clave para guardar los periódicos es el día de publicación

(índice). Cuando se requiere buscar un periódico se busca por el día que fue publicado y

así se sabe en que zócalo (bucket) está. Varios periódicos quedarán guardados en el

mismo zócalo (es decir colisionan al ser almacenados), lo que implica buscar en la sub-

lista que se guarda en cada zócalo. De esta forma se reduce el tamaño de las búsquedas

de O(n) a O(log(n)).

1. Objetivo

Conocer el funcionamiento de las tablas de hash en la programación en la materia de

análisis de algoritmos.

2. Procedimiento y desarrollo

Desarrollo

Las tablas hash se suelen implementar sobre vectores de una dimensión, aunque se pueden

hacer implementaciones multi-dimensionales basadas en varias claves. Como en el caso

de los arrays, las tablas hash proveen tiempo constante de búsqueda promedio O(1),1 sin

importar el número de elementos en la tabla. Sin embargo, en casos particularmente malos

el tiempo de búsqueda puede llegar a O(n), es decir, en función del número de elementos.

Comparada con otras estructuras de arrays asociadas, las tablas hash son más útiles

cuando se almacenan grandes cantidades de información.

Las tablas hash almacenan la información en posiciones pseudo-aleatorias, así que el

acceso ordenado a su contenido es bastante lento. Otras estructuras como árboles binarios

87
auto-balanceables tienen un tiempo promedio de búsqueda mayor (tiempo de búsqueda

O(log n)), pero la información está ordenada en todo momento.

Funcionamiento

Las operaciones básicas implementadas en las tablas hash son:

 inserción (llave, valor)

 búsqueda (llave) que devuelve valor

La mayoría de las implementaciones también incluyen borrar(llave). También se pueden

ofrecer funciones como iteración en la tabla, crecimiento y vaciado. Algunas tablas hash

permiten almacenar múltiples valores bajo la misma clave.

Para usar una tabla hash se necesita:

 Una estructura de acceso directo (normalmente un array).

 Una estructura de datos con una clave

Una función resumen (hash) cuyo dominio sea el espacio de claves y su imagen (o rango)

los números naturales.

88
Inserción

Para almacenar un elemento en la tabla hash se ha de convertir su clave a un número. Esto

se consigue aplicando la función resumen (hash) a la clave del elemento.

El resultado de la función resumen ha de mapearse al espacio de direcciones del vector

que se emplea como soporte, lo cual se consigue con la función módulo. Tras este paso

se obtiene un índice válido para la tabla.

El elemento se almacena en la posición de la tabla obtenida en el paso anterior.

- Si en la posición de la tabla ya había otro elemento, se ha producido una colisión.

Este problema se puede solucionar asociando una lista a cada posición de la tabla,

aplicando otra función o buscando el siguiente elemento libre. Estas posibilidades

han de considerarse a la hora de recuperar los datos.

Búsqueda

Para recuperar los datos, es necesario únicamente conocer la clave del elemento, a la cual

se le aplica la función resumen.

El valor obtenido se mapea al espacio de direcciones de la tabla.

- Si el elemento existente en la posición indicada en el paso anterior tiene la misma

clave que la empleada en la búsqueda, entonces es el deseado. Si la clave es

distinta, se ha de buscar el elemento según la técnica empleada para resolver el

problema de las colisiones al almacenar el elemento.

Funciones Hash más usadas:

1. Hash de División:

89
Dado un diccionario D, se fija un número m >= |D| (m mayor o igual al tamaño del

diccionario) y que sea primo no cercano a potencia de 2 o de 10. Siendo k la clave a

buscar y h(k) la función hash, se tiene h(k)=k%m (Resto de la división k/m).

2. Hash de Multiplicación

Si por alguna razón, se necesita una tabla hash con tantos elementos o punteros como una

potencia de 2 o de 10, será mejor usar una función hash de multiplicación, independiente

del tamaño de la tabla. Se escoge un tamaño de tabla m >= |D| (m mayor o igual al tamaño

del diccionario) y un cierto número irracional φ (normalmente se usa 1+5^(1/2)/2 o 1-

5^(1/2)/2). De este modo se define h(k)= Suelo(m*Parte fraccionaria(k*φ)).

Resolución de colisiones

Si dos llaves generan un hash apuntando al mismo índice, los registros correspondientes

no pueden ser almacenados en la misma posición. En estos casos, cuando una casilla ya

está ocupada, debemos encontrar otra ubicación donde almacenar el nuevo registro, y

hacerlo de tal manera que podamos encontrarlo cuando se requiera.

Para dar una idea de la importancia de una buena estrategia de resolución de colisiones,

considerarse el siguiente resultado, derivado de la paradoja de las fechas de nacimiento.

Aun cuando supongamos que el resultado de nuestra función hash genera índices

aleatorios distribuidos uniformemente en todo el vector, e incluso para vectores de 1

millón de entradas, hay un 95% de posibilidades de que al menos una colisión ocurra

antes de alcanzar los 2.500 registros.

Hay varias técnicas de resolución de colisiones, pero las más populares son

encadenamiento y direccionamiento abierto.

Direccionamiento Cerrado, Encadenamiento separado o Hashing abierto

90
En la técnica más simple de encadenamiento, cada casilla en el array referencia una lista

de los registros insertados que colisionan en la misma casilla. La inserción consiste en

encontrar la casilla correcta y agregar al final de la lista correspondiente. El borrado

consiste en buscar y quitar de la lista.

La técnica de encadenamiento tiene ventajas sobre direccionamiento abierto. Primero el

borrado es simple y segundo el crecimiento de la tabla puede ser pospuesto durante mucho

más tiempo dado que el rendimiento disminuye mucho más lentamente incluso cuando

todas las casillas ya están ocupadas. De hecho, muchas tablas hash encadenadas pueden

no requerir crecimiento nunca, dado que la degradación de rendimiento es lineal en la

medida que se va llenando la tabla. Por ejemplo, una tabla hash encadenada con dos veces

el número de elementos recomendados, será dos veces más lenta en promedio que la

misma tabla a su capacidad recomendada.

Las tablas hash encadenadas heredan las desventajas de las listas ligadas. Cuando se

almacenan cantidades de información pequeñas, el gasto extra de las listas ligadas puede

ser significativo. También los viajes a través de las listas tienen un rendimiento de caché

muy pobre.

Otras estructuras de datos pueden ser utilizadas para el encadenamiento en lugar de las

listas ligadas. Al usarárboles auto-balanceables, por ejemplo, el tiempo teórico del peor

de los casos disminuye de O(n) a O(log n). Sin embargo, dado que se supone que cada

lista debe ser pequeña, esta estrategia es normalmente ineficiente a menos que la tabla

hash sea diseñada para correr a máxima capacidad o existan índices de colisión

particularmente grandes. También se pueden utilizar vectores dinámicos para disminuir

el espacio extra requerido y mejorar el rendimiento del caché cuando los registros son

pequeños.

91
Direccionamiento abierto o Hashing cerrado

Las tablas hash de direccionamiento abierto pueden almacenar los registros directamente

en el array. Las colisiones se resuelven mediante un sondeo del array, en el que se buscan

diferentes localidades del array (secuencia de sondeo) hasta que el registro es encontrado

o se llega a una casilla vacía, indicando que no existe esa llave en la table.

Las secuencias de sondeo más socorridas incluyen:

- sondeo lineal

En el que el intervalo entre cada intento es constante (frecuentemente 1).

- sondeo cuadrático

En el que el intervalo entre los intentos aumenta linealmente (por lo que los índices son

descritos por una función cuadrática), y

- doble hasheo

En el que el intervalo entre intentos es constante para cada registro, pero es calculado por

otra función hash.

El sondeo lineal ofrece el mejor rendimiento del caché, pero es más sensible al aglomera

miento, en tanto que el doble hasheo tiene pobre rendimiento en el caché pero elimina el

problema de aglomera miento. El sondeo cuadrático se sitúa en medio. El doble hasheo

también puede requerir más cálculos que las otras formas de sondeo.

Una influencia crítica en el rendimiento de una tabla hash de direccionamiento abierto es

el porcentaje de casillas usadas en el array. Conforme el array se acerca al 100% de su

capacidad, el número de saltos requeridos por el sondeo puede aumentar

considerablemente. Una vez que se llena la tabla, los algoritmos de sondeo pueden incluso

92
caer en un círculo sin fin. Incluso utilizando buenas funciones hash, el límite aceptable

de capacidad es normalmente 80%. Con funciones hash pobremente diseñadas el

rendimiento puede degradarse incluso con poca información, al provocar aglomera

miento significativo. No se sabe a ciencia cierta qué provoca que las funciones hash

generen aglomera miento, y es muy fácil escribir una función hash que, sin querer,

provoque un nivel muy elevado de aglomera miento. (Méndez, 2001)

Ejemplo

- Implementación en pseudocódigo

El pseudocódigo que sigue es una implementación de una tabla hash de direccionamiento

abierto con sondeo lineal para resolución de colisiones y progresión sencilla, una solución

común que funciona correctamente si la función hash es apropiada.

93
registro par { llave, valor }
var vector de pares casilla[0..numcasillas-1]

function buscacasilla(llave) {
i := hash(llave) módulo de numcasillas
loop {
if casilla[i] esta libre or casilla[i].llave = llave
return i
i := (i + 1) módulo de numcasillas
}
}

94
function busqueda(llave)
i := buscacasilla(llave)
if casilla[i] está ocupada // llave está en la tabla
return casilla[i].valor
else // llave no está en la tabla
return no encontrada

function asignar(llave, valor) {


i := buscacasilla(llave)
if casilla[i] está ocupada
casilla[i].valor := valor
else {
if tabla casi llena {
hacer tabla más grande (nota 1)
i := buscacasilla(llave)
}
casilla[i].llave := llave
casilla[i].valor := valor
}
}

3. Conclusiones

Se puede concluir que las tablas de hash en la programación son una matriz asociativa
estructurada de datos que asocia llaves o claves con valores.

Se concluye que las tablas de hash las funciones más usadas son hash de división y hash
de multiplicación.

Se puede concluir sobre las tablas que debe de existir dos condiciones para existan una
tabla de hash que son: una estructura de acceso directo (normalmente un array), y una
estructura de datos con una clave.

4. Recomendaciones

Se recomienda para utilizar las tablas de hash tener los conocimientos básicos de
programación específicamente en el tema de matrices.

Se recomienda definir y escribir de manera y adecuada tanto números como caracteres en


el seudocódigo en el entorno de programación.

95
Se recomienda dimensionar correctamente el tamaño de las matrices para poder
almacenar los datos requeridos en el programa.

TEMA 5 ÁRBOLES DE BÚSQUEDA BINARIA

Introducción

Los arboles de búsqueda binaria son un método de búsqueda simple, dinámico y eficiente

considerado como uno de los fundamentales en Ciencia de la Computación. De toda la

terminología sobre árboles, tan sólo recordar que la propiedad que define un árbol binario

es que cada nodo tiene a lo más un hijo a la izquierda y uno a la derecha. Para construir

los algoritmos consideraremos que cada nodo contiene un registro con un valor clave a

través del cual efectuaremos las búsquedas.

1. Objetivo

Conocer la estructura de un árbol binario de búsqueda y sus principales propiedades,

operaciones que se pueden realizar con los arboles de búsqueda binaria.

2. Procedimiento o desarrollo

Árboles de búsqueda binaria

La propiedad que define un árbol binario es que cada nodo tiene a lo más un hijo a la

izquierda y uno a la derecha. Para construir los algoritmos se debe considerar que cada

nodo contiene un registro con un valor clave a través del cual efectuaremos las búsquedas.

En un caso general ese tipo estará compuesto por dos: una clave indicando el campo por

el cual se realiza la ordenación y una información asociada a dicha clave o visto de otra

forma, una información que puede ser compuesta en la cual existe definido un orden.

96
Según (Soto, 2015), afirma que: “Un árbol binario de búsqueda(ABB) es un árbol binario

con la propiedad de que todos los elementos almacenados en el subárbol izquierdo de

cualquier nodo x son menores que el elemento almacenado en x ,y todos los elementos

almacenados en el subárbol derecho de x son mayores que el elemento almacenado en x.”

Estructura de un árbol binario

Ilustración 16 Estructura de un árbol binario

Un árbol binario está compuesto por:

La raíz o nodo padre que tiene a su derecha al nodo con su número menor y a su

izquierda al nodo con su número mayor como se muestra en la figura anterior. La raíz

puede tener desde cero hasta dos nodos accesibles desde ella.

Nodos hijos al igual que el nodo padre tienen a su derecha al nodo con su número menor

y a su izquierda al nodo con su número mayor como se muestra en la figura anterior.

Una trayectoria del nodo ni al nodo nk, es una secuencia de nodos desde ni hasta nk, tal

que ni es el padre de ni+1. Existe un solo enlace o vínculo entre un padre y sus hijos.

Largo de una trayectoria: es el número de enlaces en la trayectoria. Una trayectoria de

k nodos tiene largo k-1.

97
Alto de un nodo: largo de la trayectoria más larga de ese nodo a una hoja.

Profundidad de un nodo: es el largo de la trayectoria de la raíz a ese nodo.

Para cada nodo de un árbol binario de búsqueda debe cumplirse la propiedad:

Las claves de los nodos del subárbol izquierdo deben ser menores que la clave de la raíz.

Las claves de los nodos del subárbol derecho deben ser mayores que la clave de la raíz.

Buscar un elemento en árbol de búsqueda binaria

 Partiendo siempre del nodo raíz, el modo de buscar un elemento se define de

forma recursiva.

 Si el árbol está vacío, terminamos la búsqueda: el elemento no está en el árbol.

 Si el valor del nodo raíz es igual que el del elemento que buscamos, terminamos

la búsqueda con éxito.

 Si el valor del nodo raíz es mayor que el elemento que buscamos, continuaremos

la búsqueda en el árbol izquierdo.

 Si el valor del nodo raíz es menor que el elemento que buscamos, continuaremos

la búsqueda en el árbol derecho.

 El valor de retorno de una función de búsqueda 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 búsqueda. Si el elemento está

en el árbol no lo insertaremos. Si no lo está, lo insertaremos a continuación del último

nodo visitado.

98
Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raíz

actual. El valor inicial para ese puntero es NULL.

 Padre = NULL

 nodo = Raiz

 Bucle: mientras actual no sea un árbol vacío o hasta que se encuentre el elemento.

Si el valor del nodo raíz es mayor que el elemento que buscamos, continuaremos la

búsqueda en el árbol izquierdo: Padre=nodo, nodo=nodo->izquierdo.

Si el valor del nodo raíz es menor que el elemento que buscamos, continuaremos la

búsqueda 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 vacío, por lo tanto, el nuevo árbol sólo contendrá el

nuevo elemento, que será la raíz 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 también nos basamos en el algoritmo de búsqueda. Si el elemento

no está en el árbol no lo podremos borrar. Si está, hay dos casos posibles:

Se trata de un nodo hoja: en ese caso lo borraremos directamente.

99
Se trata de un nodo rama: en ese caso no podemos eliminarlo, puesto que perderíamos

todos los elementos del árbol de que el nodo actual es padre. En su lugar buscamos el

nodo más a la izquierda del subárbol derecho, o el más a la derecha del subárbol izquierdo

e intercambiamos sus valores. A continuación, eliminamos el nodo hoja.

Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raíz

actual. El valor inicial para ese puntero es NULL.

Padre = NULL

Si el árbol está vacío: el elemento no está en el árbol, por lo tanto, salimos sin eliminar

ningún elemento.

Si el valor del nodo raíz es igual que el del elemento que buscamos, estamos ante uno de

los siguientes casos:

El nodo raíz es un nodo hoja:

Si 'Padre' es NULL, el nodo raíz es el único del árbol, por lo tanto, el puntero al árbol

debe ser NULL.

Si raíz es la rama derecha de 'Padre', hacemos que esa rama apunte a NULL.

Si raíz es la rama izquierda de 'Padre', hacemos que esa rama apunte a NULL.

Eliminamos el nodo, y salimos.

El nodo no es un nodo hoja:

Buscamos el 'nodo' más a la izquierda del árbol derecho de raíz o el más a la derecha del

árbol izquierdo. Hay que tener en cuenta que puede que sólo exista uno de esos árboles.

Al mismo tiempo, actualizamos 'Padre' para que apunte al padre de 'nodo'.

Intercambiamos los elementos de los nodos raíz y 'nodo'.

10
0
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 raíz es mayor que el elemento que buscamos, continuaremos la

búsqueda en el árbol izquierdo.

Si el valor del nodo raíz es menor que el elemento que buscamos, continuaremos la

búsqueda en el árbol derecho.

Cálculos de complejidad o altura en árboles

Árbol completo

Se denomina árbol completo, a aquél que tiene presentes todas las hojas en el menor nivel.

La raíz es de nivel cero, los hijos de la raíz están en nivel 1; y así sucesivamente.

Deduciremos, de manera inductiva la altura de las hojas en función del número de nodos.

El caso más simple de un árbol completo tiene tres nodos, un nivel y altura dos. Hemos

modificado levemente la definición de altura, como el número de nodos que deben ser

revisados desde la raíz a las hojas, ya que la complejidad de los algoritmos dependerá de

esta variable.

Ilustración 17: Árbol completo de nivel 3

10
1
Árboles incompletos con un nivel de desbalance

Se ilustran los tres casos de árboles, de nivel dos, con un nivel de desbalance, para n= 4,

5 y 6. Un árbol con 3 nodos es completo en caso de aceptarse sólo un nivel de desbalance.

Lo mismo puede decirse de un árbol con 7 nodos y que tenga un nivel de desbalance.

Ilustración 18: Árboles incompletos de nivel 2

Signatura del TAD de los árboles binarios de búsqueda

Según (Jiménez, 2014) afirma que:

𝒗𝒂𝒄𝒊𝒐 ∶ : 𝐴𝐵𝐵

𝒊𝒏𝒔𝒆𝒓𝒕𝒂 ∶ : (𝑂𝑟𝑑 𝑎, 𝑆ℎ𝑜𝑤 𝑎) => 𝑎 −> 𝐴𝐵𝐵 𝑎 −> 𝐴𝐵𝐵 𝑎

𝒆𝒍𝒊𝒎𝒊𝒏𝒂 ∶ : (𝑂𝑟𝑑 𝑎, 𝑆ℎ𝑜𝑤 𝑎) => 𝑎 −> 𝐴𝐵𝐵 𝑎 −> 𝐴𝐵𝐵 𝑎

𝒄𝒓𝒆𝒂 ∶ : (𝑂𝑟𝑑 𝑎, 𝑆ℎ𝑜𝑤 𝑎) => [𝑎] −> 𝐴𝐵𝐵 𝑎

𝑚𝑒𝑛𝑜𝑟 ∶ : 𝑂𝑟𝑑 𝑎 => 𝐴𝐵𝐵 𝑎 −> 𝑎

𝒆𝒍𝒆𝒎𝒆𝒏𝒕𝒐𝒔 ∶ : (𝑂𝑟𝑑 𝑎, 𝑆ℎ𝑜𝑤 𝑎) => 𝐴𝐵𝐵 𝑎 −> [𝑎]

𝒑𝒆𝒓𝒕𝒆𝒏𝒆𝒄𝒆 ∶ : (𝑂𝑟𝑑 𝑎, 𝑆ℎ𝑜𝑤 𝑎) => 𝑎 −> 𝐴𝐵𝐵 𝑎 −> 𝐵𝑜𝑜𝑙

𝒗𝒂𝒍𝒊𝒅𝒐 ∶ : (𝑂𝑟𝑑 𝑎, 𝑆ℎ𝑜𝑤 𝑎) => 𝐴𝐵𝐵 𝑎 −> 𝐵𝑜𝑜𝑙

Descripción de las operaciones:

 Vacio es el ABB vacío.

 (pertenece v a) se verifica si v es el valor de algún nodo del ABB a.

10
2
 (inserta v a) es el árbol obtenido añadiendo el valor v al ABB a, si no es uno de

sus valores.

 (crea vs) es el ABB cuyos valores son vs.

 (elementos a) es la lista de los valores de los nodos del ABB en el recorrido

inorden.

 (elimina v a) es el ABB obtenido eliminando el valor v del ABB a.

 (menor a) es el mínimo valor del ABB a.

 (valido a) se verifica si a es un ABB correcto.

3. Conclusiones

Se concluye que los árboles de búsqueda binaria tienen mucha importancia ya que

son un método de búsqueda simple, dinámica y eficiente, un árbol como estructura

de datos nos permite almacenar una cantidad significativa de datos de forma

ordenada. Un árbol se representa con un conjunto de nodos entrelazados entre sí por

medio de ramas, debemos tener en cuenta que el nodo base es único, y se le denomina

raíz. En un árbol un padre puede tener varios hijos, pero un hijo solo puede tener un

padre. Desde la raíz se puede llegar a cualquier nodo progresando por las ramas y

atravesando los sucesivos niveles estableciendo así un camino.

10
3
Unidad 5

Medianas y selección

TEMA 1  CONCEPTO DE GRAFOS, GRAFOS DIRIGIDOS Y GRAFOS NO


DIRIGIDOS

Introducción

Con teoría de grafos se pueden resolver diversos problemas como por ejemplo la síntesis
de circuitos secuenciales, contadores o sistemas de apertura. Se utiliza para diferentes
áreas por ejemplo, Dibujo computacional, en todas las áreas de Ingeniería.
Según (Gutiérrez, 2010) : Los grafos se utilizan también para modelar trayectos como el
de una línea de autobús a través de las calles de una ciudad, en el que se pueden obtener
caminos óptimos para el trayecto aplicando diversos algoritmos como puede ser el
algoritmo de Floyd.
Una importante aplicación de la teoría de grafos es en el campo de la informática, ya que
ha servido para la resolución de importantes y complejos algoritmos. Un claro ejemplo
es el Algoritmo de Dijkstra, utilizado para la determinación del camino más corto en el
recorrido de un grafo con determinados pesos en sus vértices.
Dentro de este campo, un grafo es considerado un tipo de dato abstracto TAD.

1. Objetivo

Investigar conceptos sobre grafos en informática y sus tipos para su implementación


en programación.

2. Procedimiento o desarrollo

10
4
En matemáticas y en ciencias de la computación, la teoría de grafos, estudia las
propiedades de los grafos. Un grafo es un conjunto, no vacío, de objetos llamados vértices
(o nodos) y una selección de pares de vértices, llamados aristas (edges en inglés) que
pueden ser orientados o no. Típicamente, un grafo se representa mediante una serie de
puntos (los vértices) conectados por líneas (las aristas).

Los grafos son estructuras que constan de vértices o nodos y de aristas o arcos
que conectan los vértices entre sí.

Un grafo G consiste en dos cosas:


1. Un conjunto V de elementos llamados nodos (o puntos o vértices)
2. Un conjunto E de aristas tales que cada arista e de E está identificada por un
único (desordenado) par de [u, v] de nodos de V, denotado por e = [u, v].
A veces denotamos un grafo G por G (V, E).

Suponiendo que e = [u, v]. Entonces los nodos u y v se llaman extremos de e y u


y v se dice que son nodos adyacentes o vecinos.
El grado de un nodo u, escrito grad (u) es el número de aristas que contienen a u. Si grad
(u)=0 es decir si u no pertenece a ninguna arista decimos que es un nodo aislado.

10
5
Por ejemplo, para el siguiente grafo el conjunto de nodos (o vértices) es {A, B, C, D, E,
F, G, H} y el conjunto de arcos (o aristas) es {(A, B), (A, C), (A, D), (C, D), (C, F), (E,
G), (A, A)}

Grafos dirigidos

Un grafo dirigido (o dígrafo) G consiste de un conjunto de vértices y un conjunto de


arcos E. A los vértices se les llama también nodos o puntos y a los arcos aristas dirigidas
o líneas dirigidas (). Un arco es un par ordenado de vértices (v, w) donde v es la cola y w
la cabeza del arco. Un arco (v, w) se expresa también como v→ w y se dibuja como:

Se dice que un arco v → w va de v a w y que w es adyacente a v.


Los vértices de un dígrafo pueden usarse para representar objetos, y los arcos relaciones
entre los objetos.

Representaciones de Grafos dirigidos

Se puede representar un dígrafo G=(V,E) llamada lista de adyacencia. La lista de


adyacencia de un vértice i es una lista, en algún orden, de todos los vértices adyacentes a
i. Se puede representar G mediante un array HEAD donde HEAD[i] es un puntero a la
lista de adyacencia del vértice i.

10
6
Ejemplo: A continuación se muestra un dígrafo y su representación usando la lista
de adyacencia. Se ha usado una lista enlazada simple.

La representación mediante lista de adyacencia requiere una memoria


proporcional al número de vértices más el número de arcos. Se usa cuando el número de
arcos es mucho menor a 𝑛2 .La desventaja es que podemos tomar n tiempo O(n) para
determinar si hay un arco del vértice i al j.

Si se espera que el grafo permanezca fijo (pocos o ningún cambio en la lista de


adyacencia) puede usarse HEAD[i] como un cursor de un array ADJ, donde ADJ
[HEAD[i]] contiene los vértices adyacentes a i, hasta que se encuentre un final de lista
(puede ser un 0).

Ejemplo: Para el siguiente dígrafo se muestra otra representación de la lista de


adyacencia (uso de arrays).

10
7
Grafo No dirigido

Un grafo no dirigido es aquel en el que todas sus aristas son bidireccionales.


La relación sobre V es simétrica. Las aristas se representan como pares no ordenados
{u,v}, u,v Є V y u ≠ v. (Mostaccio & Pérez, 2011)

Representaciones de Grafos No dirigidos


La matriz de adyacencia para el grafo G es una matriz A de dimensión n x n de
elementos booleanos en la que:
A[i, j] = verdad, si y sólo si existe una arista en G que va del vértice i al vértice j
A[i, j] = falso, en caso contrario

En un grafo no dirigido, la matriz de adyacencia es simétrica y los elementos de


su diagonal son todos falsos.

10
8
3. Conclusiones

Con la investigación realizada se puede decir que los grafos son importantes en cuanto a
la estructura de datos y su implementación tiene tantas aplicaciones como el dibujo
computacional y las diferentes áreas en el que este se utiliza.

4. Recomendaciones

Se recomienda entender bien los tipos de grafos que existen ya que existe una variedad y
estos tienen diversas propiedades.

TEMA 2  UTILIZACIÓN DE LOS GRAFOS, MEDIDA DE LA E CIENCIA.


EN TIEMPO Y ESPACIO

TEMA 3 MATRICES DE ADYACENCIA, MATRICES DE ADYACENCIA


ETIQUETADA, LISTAS ADYACENCIA

TEMA 4 implementaciones de grafos usando matrices de adyacencia,


implementación de grafos usando listas de adyacencia, inserción, búsqueda y
eliminación de nodos y aristas

Introducción

Un grafo dirigido G consiste en un conjunto de vértices V y un conjunto de arcos o aristas


A. Los vertice se denominan también nodos o puntos.
Un arco, es un par ordenado de vértices(V,W) donde V es el vértice inicial y W es el
vértice terminal del arco. Un arco se expresa como: V-->W y se representa de la siguiente
manera:

1. Objetivo.

 Entender el manejo de los grafos con sus diferentes métodos.

10
9
2. Procedimiento o desarrollo

- Implementación de Grafos usando Matrices de Adyacencia

Para un grafo con |V|∣V∣ vértices, una matriz de adyacencia es una matriz de |V| \times
|V|∣V∣×∣V∣ de ceros y unos, donde la entrada en el renglón ii y la columna jj es 1 si y solo
si la arista (i, j)(i,j) está en el grafo. Si quieres indicar un peso de la arista, ponlo en la
entrada del renglón ii, columna jj y reserva un valor especial (tal vez null) para indicar
una arista ausente. Aquí está la matriz de adyacencia para el grafo de la red social:

En JavaScript, representamos esta matriz como:

[ [0, 1, 0, 0, 0, 0, 1, 0, 1, 0],
[1, 0, 0, 0, 1, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 1, 0],
[0, 1, 1, 1, 0, 1, 0, 0, 0, 1],
[0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 1, 0, 0, 1, 0, 0] ]
Con una matriz de adyacencia, podemos averiguar si una arista está presente en un tiempo
constante, solo buscando la entrada correspondiente en la matriz. Por ejemplo, si la matriz

11
0
de adyacencia se llama graph, entonces podemos consultar si la arista (i, j)(i,j) se
encuentra en el grafo al mirar graph[i][j]. ¿Entonces cuál es la desventaja de una matriz
de adyacencia? Dos cosas, en realidad. En primer lugar, ocupa un
espacio \Theta(V^2)Θ(V2), incluso si el grafo es disperso: relativamente pocas aristas. En
otras palabras, para un grafo disperso, la matriz de adyacencia es en su mayoría 0s, y
utilizamos mucho espacio para representar solo algunas aristas. En segundo lugar, si
quieres averiguar cuáles vértices son adyacentes a un vértice dado ii, tienes que mirar en
todas las entradas |V|∣V∣ en el renglón ii, incluso si solo un pequeño número de vértices
son adyacentes al vértice ii.

Para un grafo no dirigido, la matriz de adyacencia es simétrica: la entrada del renglón ii,
columna jj es 1 si y solo si la entrada del renglón jj, columna ii es 1. Para un grafo
dirigido, la matriz de adyacencia no necesita ser simétrica. (Cormen, s.f.)

- Implementación de Grafos usando Listas de Adyacencia

Representar un grafo con listas de adyacencia combina las matrices de adyacencia con las
listas de aristas. Para cada vértice ii, almacena un arreglo de los vértices adyacentes a él.
Típicamente tenemos un arreglo de |V|∣V∣ listas de adyacencia, una lista de adyacencia
por vértice. Aquí está una representación de una lista de adyacencia del grafo de la red
social:

En JavaScript, representamos estas listas de adyacencia como:

[ [1, 6, 8],
[0, 4, 6, 9],
[4, 6],

11
1
[4, 5, 8],
[1, 2, 3, 5, 9],
[3, 4],
[0, 1, 2],
[8, 9],
[0, 3, 7],
[1, 4, 7] ]
Los números del vértice en una lista de adyacencia no están obligados a aparecer en
ningún orden en particular, aunque a menudo es conveniente enumerarlos en orden
ascendente, como en este ejemplo.

Podemos llegar a la lista de adyacencia de cada vértice en un tiempo constante, porque


solo tenemos que indexar en un arreglo. Para averiguar si una arista (i, j)(i,j) está presente
en el grafo, vamos a la lista de adyacencia de ii en un tiempo constante y luego
buscamos jj en la lista de adyacencia de ii. ¿Cuánto tarda eso en el peor de los casos? La
respuesta es \Theta(d)Θ(d), donde dd es el grado del vértice ii, porque eso es qué tan larga
es la lista de adyacencia de ii. El grado del vértice ii puede ser tan alto como |V|-
1∣V∣−1 (si ii es adyacente a todos los demás |V|-1∣V∣−1 vértices) o tan bajo como 0
(si ii está aislado, sin aristas incidentes). En un grafo no dirigido, el vértice jj está en la
lista de adyacencia del vértice ii si y solo si ii está en la lista de adyacencia de jj. Si el
grafo está ponderado, entonces cada elemento en cada lista de adyacencia es un arreglo
de dos elementos o un objeto, que da el número de vértice y el peso de la arista.

Puedes usar un bucle for para iterar sobre los vértices en una lista de adyacencia. Por
ejemplo, supón que tienes una representación de una lista de adyacencia de un grafo en
la variable graph, de modo que graph[i] es un arreglo que contiene los vecinos del
vértice ii. Entonces, para llamar una función doStuff en cada vértice adyacente al
vértice ii, podrías utilizar el siguiente código JavaScript:

𝑓𝑜𝑟 (𝑣𝑎𝑟 𝑗 = 0; 𝑗 < 𝑔𝑟𝑎𝑝ℎ[𝑖]. 𝑙𝑒𝑛𝑔𝑡ℎ; 𝑗 + +) {


𝑑𝑜𝑆𝑡𝑢𝑓𝑓(𝑔𝑟𝑎𝑝ℎ[𝑖][𝑗]);
}

11
2
Si la notación de doble subíndice te confunde, puedes pensarlo de esta manera:

𝑣𝑎𝑟 𝑣𝑒𝑟𝑡𝑒𝑥 = 𝑔𝑟𝑎𝑝ℎ[𝑖];


𝑓𝑜𝑟 (𝑣𝑎𝑟 𝑗 = 0; 𝑗 < 𝑣𝑒𝑟𝑡𝑒𝑥. 𝑙𝑒𝑛𝑔𝑡ℎ; 𝑗 + +) {
𝑑𝑜𝑆𝑡𝑢𝑓𝑓(𝑣𝑒𝑟𝑡𝑒𝑥[𝑗]);
}
¿Cuánto espacio ocupan las listas de adyacencia? Tenemos |V|∣V∣ listas, y aunque cada
lista podría tener hasta |V|-1∣V∣−1 vértices, las listas de adyacencia para un grafo no
dirigido contienen 2|E|2∣E∣ elementos en total. ¿Por qué 2|E|2∣E∣? Cada arista (i,
j)(i,j) aparece exactamente dos veces en las listas de adyacencia, una vez en la lista de ii y
una vez en la lista de jj, y hay |E|∣E∣ aristas. Para un grafo dirigido, las listas de adyacencia
contienen un total de |E|∣E∣ elementos, un elemento por cada arista dirigida. (Cormen,
s.f.)

- Inserción, Búsqueda y Eliminación de nodos y aristas

- Algoritmo de inserción
mensaje(valor a insertar ?)
lee(valor_a_insertar)
si top<>NIL entonces
p<--top
mientras p(la)<>NIL haz
p<--p(la)
new(q)
lee(q(dato))
p(la)<--q
q(la)<--NIL
mensaje(Hay vértices adyacentes?)
lee(respuesta)
si respuesta=si entonces
mensaje(Cuantos vértices?)
lee(número_vértices)
desde i=1 hasta número_vértices haz
new(p)
lee(p(dato))

11
3
q(ld)<--p
q<--q(ld)
en caso contrario
mensaje(no existe lista)

- Algoritmo de búsqueda
mensaje(vértice a buscar)
lee(vértice_a_buscar)
p<--top
repite
si p(dato)=vértice_a_buscar entonces
repite
p<--p(ld)
escribe(p(dato))
hasta p(ld)=NIL
en caso contrario
p<--(la)
hasta p=NIL

- Algoritmo de borrado
mensaje(vértice a borrar ?)
lee(vértice_a_borrar)
p≪--top
r<--p
q<--p
sw<--falso
repite
si p(dato)=vértice_a_borrar entonces
si p=top entonces
top<--top(la)
r<--top
sw<--verdadero
en caso contrario

11
4
r(la)<--p(la)
repite
p<--p(ld)
dispose(q)
q<--p
hasta p=NIL
si sw=verdadero entonces
p<--r
q<--p
en caso contrario
p<--r(la)
q<--p
en caso contrario
r<--p
repite
q<--p(ld)
si q(dato)=vértice_a_borrar entonces
p(ld)<--q(ld)
dispose(q)
p<--p
en caso contrario
p<--p(ld)
hasta p=NIL

3. Conclusiones.

Se concluye que los métodos de listas y matrices adyacentes son esenciales para los
vértices de un grafo o árbol.

4. Recomendaciones.

Se recomienda reforzar estos temas en clase y practicas más fáciles y completas.

11
5
TEMA 5  ALGORITMOS DE BÚSQUEDA EN GRAFOS

Bibliografía

Aguilar, B. (7 de Mayo de 2017). Slideshare. Obtenido de Slideshare:


https://es.slideshare.net/BryanAguilarYaguana/algoritmos-de-dijkstra-warshall-
ordenacin-topolgica

Aguilar, L. (2008). Fundamentos de programación. Algoritmos y Estructura de Datos. En L.


Aguilar, Fundamentos de programación. Algoritmos y Estructura de Datos. Madrid,
España.

Balderrama, C. (2012). Metodología de la Programación I. En C. Balderrama, Metodología de la


Programación I. Oruro, Bolivia. Obtenido de
https://mimateriaenlinea.unid.edu.mx/dts_cursos_mdl/lic/IC/EA/AM/06/Algoritmos.p
df

Bustos, E. (2011). angelfire. Obtenido de angelfire:


http://www.angelfire.com/planet/invo_ago_2006/clase8_2.pdf

Cormen, T. (s.f.). khanacademy. Obtenido de khanacademy:


https://es.khanacademy.org/computing/computer-science/algorithms/graph-
representation/a/representing-graphs

Cormen, T., Leiserson, C., Rivest, R., & Stein, C. (2001). Introduction to Algorithms. McGraw-
Hill.

Gutiérrez, X. F. (2010). Estructuras de datos: especificación, diseño e implementación.


Ediciones UPC.

Hernández, E. G. (2014). Programación Java. Obtenido de Programación Java:


http://puntocomnoesunlenguaje.blogspot.com/2017/11/ejercicios-resueltos-de-
bucles-anidados-java.html

Ivan, D. A. (Febrero de 2013). Algoritmo Bactracking Recursivo. Obtenido de Algoritmo


Bactracking Recursivo:
http://www.academia.edu/4607412/Algoritmo_de_Backtracking_Recursivo_y_no_Rec
ursivo_para_la_Resoluci%C3%B3n_de_un_Laberinto_y_su_Aplicaci%C3%B3n_en_SDL

Jiménez, A. (21 de Octubre de 2014). Universidad de Sevilla. Obtenido de El TAD de las árboles
binarios de búsqueda: https://www.cs.us.es/~jalonso/cursos/i1m/temas/tema-
19.html

Lazaro, J. (s.f.). Algoritmia y Complejidad. Obtenido de Algoritmia y Complejidad:


ftp://www.cc.uah.es/pub/Alumnos/G_Ing_Informatica/Algoritmia_y_Complejidad/ant
eriores/Apuntes/08_Backtracking.pdf

11
6
Méndez, J. (01 de 09 de 2001). Milenium. Obtenido de
https://www.informaticamilenium.com.mx/es/articulos/internet/48-como-buscar-
informacion-en-internet.html

Mostaccio, C., & Pérez, G. (2011). Grafos. Obtenido de Grafos:


http://163.10.22.82/OAS/estructuras_de_grafos/index.html

Nektezer. (4 de 3 de 2011). estructuradedatosjp. Obtenido de estructuradedatosjp:


http://estructuradedatosjp.blogspot.com/2015/11/pilas-y-colas-en-java.html

Nieto, A. (20 de Octubre de 2012). SlideShare. Obtenido de SlideShare:


https://es.slideshare.net/adncstell/53-arbol-de-expansin-minima-algoritmo-de-prim

Palma, S. (26 de Abril de 2014). Biblia del Programador. Obtenido de


https://www.bibliadelprogramador.com/2014/04/algoritmos-de-busqueda-en-
anchura-bfs-y.html

Peñafiel, J. (10 de agosto de 2013). Programando Ando. Obtenido de


https://juanset19.wordpress.com/2013/08/10/recorrido-en-anchura-y-en-
profundidad-de-un-grafo-representado-por-una-matriz/

Quero, E. (2003). Sistemas Operativos y Lenguajes de Programaciòn. En E. Quero, Sistemas


Operativos y Lenguajes de Programaciòn. Madrid, España. Obtenido de
https://books.google.com.ec/books?id=iuaUPNi6JmEC&pg=PA130&dq=interpretes+y+
compiladores+programacion&hl=es&sa=X&ved=0ahUKEwi8gunKy9PfAhWRneAKHeLb
DyAQ6AEINTAC#v=onepage&q=interpretes%20y%20compiladores%20programacion&
f=false

rmurillo95. (1 de junio de 2010). monografias.com.

Rodriguez, P. (10 de marzo de 2015). Grafos. Obtenido de


https://rvargass.wordpress.com/unidad-iii-recorrido-de-grafos/recorrido-de-grafos/

Soto, A. G. (2015). Árboles Binarios de Busqueda . Granada.

Zapata, D. (16 de 7 de 2010). www.ciberaula.com. Obtenido de www.ciberaula.com:


http://www.ciberaula.com/articulo/colas_en_java/

11
7

Potrebbero piacerti anche