Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
CARRERA DE COMPUTACIÓ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”.
MISIÓN
VISIÓN
2
UNIVERSIDAD POLITÉCNICA ESTATAL DEL CARCHI
SILABO
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:
2. DATOS DE LA ASIGNATURA
3
3. CONSTRUCCIÓN DEL CONOCIMIENTO
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
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
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.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
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
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.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
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
8
3.1 N° DE LA UNIDAD: 5 3.2 NOMBRE DE LA UNIDAD: Medianas y selección 3.3 N° DE HORAS: 33
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
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.
12
Unidad 1
Notaciones asintóticas
Introducción
Algoritmo
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
Ejemplos:
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:
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:
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)
Algunas reglas:
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.
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:
Inconvenientes:
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
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
3. Conclusiones
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
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
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
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.
Ej. De ordenamientos:
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).
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)
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.
2. Algoritmos de intercambio:
3. Algoritmos de selección:
4. Algoritmos de enumeración:
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.
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)
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 3: [𝐶𝑜𝑚𝑝𝑎𝑟𝑎 𝑣 𝑐𝑜𝑛 𝑙𝑜𝑠 𝑎𝑛𝑡𝑒𝑟𝑖𝑜𝑟𝑒𝑠] 𝑊ℎ𝑖𝑙𝑒 𝑎[𝑗 − 1] > 𝑣 𝐴𝑁𝐷 𝑗 > 1 𝑑𝑜
Paso 4: [𝑅𝑒𝑐𝑜𝑟𝑟𝑒 𝑙𝑜𝑠 𝑑𝑎𝑡𝑜𝑠 𝑚𝑎𝑦𝑜𝑟𝑒𝑠] 𝑆𝑒𝑡 𝑎[𝑗] < − 𝑎[𝑗 − 1],
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)
𝑎 = [′𝑎′, ′𝑎′, ′𝑒′, ′𝑒′, ′𝑔′, ′𝑖′, ′𝑙′, ′𝑚′, ′𝑛′, ′𝑜′, ′𝑝′, ′𝑟′, ′𝑠′, ′𝑡′, ′𝑥′]
MÉTODO DE SELECCIÓN.
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: 𝑎 =
[′𝑎′, ′𝑎′, ′𝑜′, ′𝑟′, ′𝑡′, ′𝑖′, ′𝑛′, ′𝑔′, ′𝑒′, ′𝑥′, ′𝑠′, ′𝑚′, ′𝑝′, ′𝑙′, ′𝑒′].
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:
MÉTODO BURBUJA.
Paso 4: [Si a[j-1] es mayor que el que le sigue] 𝐼𝑓 𝑎[𝑗 − 1] < 𝑎[𝑗] 𝑡ℎ𝑒𝑛
25
2. Peor caso n(n-1)/2
3. Promedio O(n2)
MÉTODO DE SHELL.
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.
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.
𝑐𝑜𝑛𝑠𝑡
𝑀𝐴𝑋𝐼𝑁𝐶 = _____;
𝑣𝑎𝑟
26
𝑏𝑒𝑔𝑖𝑛
𝑓𝑜𝑟 𝑝 ∶
= 𝑘 + 1 𝑡𝑜 𝑀𝐴𝑋𝑅𝐸𝐺 𝑑𝑜 𝑏𝑒𝑔𝑖𝑛 /
∗ 𝑖𝑛𝑠𝑒𝑟𝑐𝑖ó𝑛 𝑑𝑖𝑟𝑒𝑐𝑡𝑎 𝑝𝑎𝑟𝑎 𝑒𝑙 𝑔𝑟𝑢𝑝𝑜 𝑞𝑢𝑒 𝑠𝑒 𝑒𝑛𝑐𝑢𝑒𝑛𝑡𝑟𝑎 𝑐𝑎𝑑𝑎 𝐾 𝑝𝑜𝑠𝑖𝑐𝑖𝑜𝑛𝑒𝑠 ∗/
𝑛𝑢𝑚 ∶= 𝑟𝑒𝑔[𝑝];
𝑗 ∶= 𝑝 − 𝑘;
𝑟𝑒𝑔[𝑗 + 𝑘] ∶= 𝑟𝑒𝑔[𝑗];
𝑗 ∶= 𝑗 − 𝑘;
𝑒𝑛𝑑;
𝑟𝑒𝑔[𝑗 + 𝑘] ∶= 𝑛𝑢𝑚;
𝑒𝑛𝑑
𝑒𝑛𝑑
𝑒𝑛𝑑;
Ejemplo:
2 3 0,1,4,2,3,5,6 (2,0)
3 3 0,1,4,2,3,5,6 Ninguno
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
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
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
2. Procedimiento o desarrollo
Ejemplo
/∗
∗/
𝑝𝑎𝑐𝑘𝑎𝑔𝑒 𝑓𝑖𝑏𝑜𝑛𝑎𝑐𝑐𝑖_𝑟𝑒𝑐𝑢𝑟𝑠𝑖𝑣𝑜;
/∗∗
∗ @𝑎𝑢𝑡ℎ𝑜𝑟 𝑢𝑠𝑢𝑎𝑟𝑖𝑜
∗/
29
𝑖𝑓(𝑛𝑢𝑚𝑒𝑟𝑜 == 1 || 𝑛𝑢𝑚𝑒𝑟𝑜 == 2) 𝑟𝑒𝑡𝑢𝑟𝑛 1;
𝑒𝑙𝑠𝑒
/∗∗
∗/
3. Conclusión
4. Recomendación
Se recomienda realizar ejercicios para tener más claro el tema de iteración por medio del
análisis de algoritmos.
30
Unidad 2
Ecuaciones de recurrencia
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
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
1. Objetivo
Aprender el funcionamiento de los métodos de las pilas y las colas en java y en general
2. Procedimiento o desarrollo
PILAS
La pila es una secuencia de elementos del mismo tipo en la que el acceso a la misma se
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
Las pilas son muy útiles en varios escenarios de programación. Dos de los más comunes
son:
otro método, el comportamiento LIFO de la pila asegura que la instrucción return del
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
El interfaz en Java que define esta clase de objetos y sus métodos son los siguientes:
Pila.java
PilaArray.java
33
Ilustración 5- PilaArray Implementación
siguiente ejemplo creamos una pila con capacidad para 125 elementos
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
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
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.
35
PilaEnlazada.java
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
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
36
El mecanismo que sigue el método primero es similar al visto en el pop, aunque se
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
Cola.java
ColaEnlazada.java
37
Ilustración 10-Cola enlazada
Vemos como la clase Cola contiene dos campos, cola y cabecera que apuntan al principio
utilizaremos la cola.
La operación encolar crea un nodo cuyo sucesor es nulo. Esto es porque añadimos al final
38
Para eliminar (desencolar) y para consultar (cabecera) se utiliza el campo cabecero. Se
3. Conclusiones
acceso a sus elementos es de tipo LIFO (del inglés Last In First Out, último en entrar,
4. Recomendaciones
Identificar los estados de los servicios y administrarlos de manera adecuada caso contrario
39
TEMA 3 FUNCIONES MATEMÁTICAS RECURSIVAS, FUNCIONES
RECURSIVAS SIMPLES
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
Divide y vencerás
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
41
Como divide y vencerás crea por lo menos dos subproblemas, un algoritmo de divide y
vencerás hace muchas 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
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
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.
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:
Problemas de Optimización:
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.
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
adecuadas hasta llegar a un objetivo. De esta forma genera todas las secuenciadas de
4. Recomendaciones
45
Unidad 3
Dividir y conquistar
Introducción
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
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.
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:
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.
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:
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){
𝑡𝑟𝑦{
𝐺𝑟𝑎𝑓𝑜 𝑔𝑓 = 𝑛𝑒𝑤 𝐺𝑟𝑎𝑓𝑜("" + 𝐼𝑛𝑡𝑒𝑔𝑒𝑟. 𝑝𝑎𝑟𝑠𝑒𝐼𝑛𝑡(𝑣𝑎𝑙𝑜𝑟. 𝑔𝑒𝑡𝑇𝑒𝑥𝑡()));
𝑝𝑑. 𝑔𝑒𝑡𝑉𝑔𝑟𝑎𝑓𝑜𝑠(). 𝑎𝑑𝑑(𝑔𝑓);
𝑝𝑑. 𝑟𝑒𝑝𝑎𝑖𝑛𝑡();
𝑟𝑒𝑝𝑎𝑖𝑛𝑡();
𝑚𝑎𝑥 + +;
}𝑐𝑎𝑡𝑐ℎ(𝑁𝑢𝑚𝑏𝑒𝑟𝐹𝑜𝑟𝑚𝑎𝑡𝐸𝑥𝑐𝑒𝑝𝑡𝑖𝑜𝑛 𝑛𝑒){
𝐽𝑂𝑝𝑡𝑖𝑜𝑛𝑃𝑎𝑛𝑒. 𝑠ℎ𝑜𝑤𝑀𝑒𝑠𝑠𝑎𝑔𝑒𝐷𝑖𝑎𝑙𝑜𝑔(𝑛𝑢𝑙𝑙, "𝐷𝑖𝑔𝑖𝑡𝑒 𝑢𝑛 𝑛𝑢𝑚𝑒𝑟𝑜 𝑣𝑎𝑙𝑖𝑑𝑜");
}
}
}
});
51
𝑝𝑑𝑎𝑡𝑜𝑠. 𝑎𝑑𝑑(𝑣𝑎𝑙𝑜𝑟);
𝑝𝑑𝑎𝑡𝑜𝑠. 𝑎𝑑𝑑(𝑎𝑔𝑟𝑒𝑔𝑎𝑟);
𝑎𝑑𝑑(𝑝𝑑𝑎𝑡𝑜𝑠, 𝐵𝑜𝑟𝑑𝑒𝑟𝐿𝑎𝑦𝑜𝑢𝑡. 𝑆𝑂𝑈𝑇𝐻);
}
CLASE PANEL DE CONTROL
𝑖𝑛𝑡 𝑥 = 150;
𝑖𝑛𝑡 𝑦 = 150;
𝑖𝑛𝑡 𝑎𝑛𝑐ℎ𝑜 = 30;
𝑖𝑛𝑡 𝑎𝑙𝑡𝑜 = 30;
𝑝𝑢𝑏𝑙𝑖𝑐 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑥𝑣𝑠;
𝑝𝑢𝑏𝑙𝑖𝑐 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑦𝑣𝑠;
𝑝𝑢𝑏𝑙𝑖𝑐 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐺𝑟𝑎𝑓𝑜 > 𝑣𝑔𝑟𝑎𝑓𝑜𝑠;
𝑖𝑛𝑡 𝑖𝑛𝑑𝑖𝑐𝑒 = 0;
𝑝𝑢𝑏𝑙𝑖𝑐 𝑃𝑎𝑛𝑒𝑙𝐷𝑖𝑏𝑢𝑗𝑜(){
𝑣𝑔𝑟𝑎𝑓𝑜𝑠 = 𝑛𝑒𝑤 𝑉𝑒𝑐𝑡𝑜𝑟();
𝑥𝑣𝑠 = 𝑛𝑒𝑤 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑦𝑣𝑠 = 𝑛𝑒𝑤 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑠𝑒𝑡𝐷𝑜𝑢𝑏𝑙𝑒𝐵𝑢𝑓𝑓𝑒𝑟𝑒𝑑(𝑡𝑟𝑢𝑒);
52
}
53
𝑔. 𝑓𝑖𝑙𝑙𝑂𝑣𝑎𝑙(𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑗), 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑗), 𝑎𝑛𝑐ℎ𝑜, 𝑎𝑙𝑡𝑜);
𝑔. 𝑠𝑒𝑡𝐶𝑜𝑙𝑜𝑟(𝐶𝑜𝑙𝑜𝑟. 𝐵𝐿𝐴𝐶𝐾);
𝑔. 𝑑𝑟𝑎𝑤𝑂𝑣𝑎𝑙(𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑗), 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑗), 𝑎𝑛𝑐ℎ𝑜, 𝑎𝑙𝑡𝑜);
𝑔. 𝑑𝑟𝑎𝑤𝑆𝑡𝑟𝑖𝑛𝑔("" + 𝑣𝑔𝑟𝑎𝑓𝑜𝑠. 𝑔𝑒𝑡(𝑗). 𝑜𝑏𝑡𝑒𝑛𝑒𝑟𝐷𝑎𝑡𝑜(), 𝑥𝑣𝑠. 𝑔𝑒𝑡(𝑗) + ((𝑎𝑛𝑐ℎ𝑜/2)
− 3), 𝑦𝑣𝑠. 𝑔𝑒𝑡(𝑗) + ((𝑎𝑙𝑡𝑜/2) + 3));
}
}
}
𝑝𝑢𝑏𝑙𝑖𝑐 𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐺𝑟𝑎𝑓𝑜 > 𝑔𝑒𝑡𝑉𝑔𝑟𝑎𝑓𝑜𝑠() {
𝑟𝑒𝑡𝑢𝑟𝑛 𝑣𝑔𝑟𝑎𝑓𝑜𝑠;
}
𝑝𝑢𝑏𝑙𝑖𝑐 𝑣𝑜𝑖𝑑 𝑠𝑒𝑡𝑉𝑔𝑟𝑎𝑓𝑜𝑠(𝑉𝑒𝑐𝑡𝑜𝑟 < 𝐺𝑟𝑎𝑓𝑜 > 𝑣𝑔𝑟𝑎𝑓𝑜𝑠) {
𝑡ℎ𝑖𝑠. 𝑣𝑔𝑟𝑎𝑓𝑜𝑠 = 𝑣𝑔𝑟𝑎𝑓𝑜𝑠;
}
}
CLASE GRAFO
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.
4. Recomendación
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.
2. Procedimiento o desarrollo
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)
RECORRIDOS DE GRAFOS
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.
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)
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)
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.
𝑤ℎ𝑖𝑙𝑒(! 𝑞. 𝑒𝑚𝑝𝑡𝑦())
𝑆𝑡𝑎𝑡𝑒 𝑠𝑡 = 𝑞. 𝑓𝑟𝑜𝑛𝑡();
𝑞. 𝑝𝑜𝑝();
𝑖𝑓 (𝑠𝑡. 𝑛𝑜𝑑𝑒 == 𝑛𝑜𝑑𝑜){
𝑝𝑟𝑖𝑛𝑡𝑓("′%𝑑′𝑛", 𝑛𝑜𝑑𝑜);
𝑟𝑒𝑡𝑢𝑟𝑛;
}𝑒𝑙𝑠𝑒 𝑝𝑟𝑖𝑛𝑡𝑓("%𝑑 ", 𝑠𝑡. 𝑛𝑜𝑑𝑒);
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.
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.
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)
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.
/∗∗
∗ 𝐶𝑙𝑎𝑠𝑒 𝐺𝑟𝑎𝑓𝑜
∗/
𝑝𝑢𝑏𝑙𝑖𝑐 𝑐𝑙𝑎𝑠𝑠 𝐺𝑟𝑎𝑓𝑜 {
𝑝𝑢𝑏𝑙𝑖𝑐 𝐺𝑟𝑎𝑓𝑜() {
}
66
𝑝𝑢𝑏𝑙𝑖𝑐 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝐴𝑛𝑐ℎ𝑢𝑟𝑎(𝑖𝑛𝑡 𝑛𝑜𝑑𝑜𝐼) {
𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠 = 𝑛𝑒𝑤 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝐴𝑛𝑐ℎ𝑢𝑟𝑎[𝑛𝑜𝑑𝑜𝐼] = 𝑡𝑟𝑢𝑒;
𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑐𝑜𝑙𝑎 = 𝑛𝑒𝑤 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠. 𝑎𝑑𝑑(𝑛𝑜𝑑𝑜𝐼);
𝑐𝑜𝑙𝑎. 𝑎𝑑𝑑(𝑛𝑜𝑑𝑜𝐼);
67
𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠 = 𝑛𝑒𝑤 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑[𝑛𝑜𝑑𝑜𝐼] = 𝑡𝑟𝑢𝑒;
𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > 𝑐𝑜𝑙𝑎 = 𝑛𝑒𝑤 𝐴𝑟𝑟𝑎𝑦𝐿𝑖𝑠𝑡 < 𝐼𝑛𝑡𝑒𝑔𝑒𝑟 > ();
𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠. 𝑎𝑑𝑑(𝑛𝑜𝑑𝑜𝐼);
𝑐𝑜𝑙𝑎. 𝑎𝑑𝑑(𝑛𝑜𝑑𝑜𝐼);
𝑤ℎ𝑖𝑙𝑒 (! 𝑐𝑜𝑙𝑎. 𝑖𝑠𝐸𝑚𝑝𝑡𝑦()) {
𝑖𝑛𝑡 𝑗 = 𝑐𝑜𝑙𝑎. 𝑟𝑒𝑚𝑜𝑣𝑒(0);
𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠. 𝑎𝑑𝑑𝐴𝑙𝑙(𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑(𝑖));
𝑣𝑖𝑠𝑖𝑡𝑖𝑎𝑑𝑜𝑃𝑟𝑜𝑓𝑢𝑛𝑖𝑑𝑎𝑑[𝑖] = 𝑡𝑟𝑢𝑒;
}
}
}
𝑟𝑒𝑡𝑢𝑟𝑛 𝑟𝑒𝑐𝑜𝑟𝑟𝑖𝑑𝑜𝑠;
}
}
68
Para probar los métodos se ejecuta el siguiente código:
/∗∗
∗/
𝑝𝑢𝑏𝑙𝑖𝑐 𝑠𝑡𝑎𝑡𝑖𝑐 𝑣𝑜𝑖𝑑 𝑚𝑎𝑖𝑛(𝑆𝑡𝑟𝑖𝑛𝑔[] 𝑎𝑟𝑔𝑠) {
3. Conclusión
4. Recomendación
69
TEMA 5 ÁRBOL DE EXPANSIÓN MININA (ALGORITMOS DE KRUSKAL
Y PRIM)
Introducción
Árbol de expansión
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 problema surge cuando todos los nodos de una red deben conectarse entre ellos sin
formar un ciclo.
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)
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:
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.
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.
- 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.
- Ejemplo de Ejecución
72
Grafo Descripción
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.
74
75
- Algoritmo Prim
76
mínimo para uno de los componentes conexos que forman dicho grafo no conexo.
(Cormen, Leiserson, Rivest, & Stein, 2001)
77
Ejemplo de Ejecución
Grafo Descripción
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.
3. Conclusiones
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.
Introducción
1. Objetivo
2. Procedimiento o desarrollo
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.
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
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
2. Procedimiento o desarrollo
83
Búsqueda Secuencial
84
Búsqueda Binaria
3. Conclusión
4. Recomendación
85
TEMA 2 ALGORITMOS CUADRÁTICOS DE ORDENAMIENTO
(SELECCIÓN, INSERCIÓN)
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
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
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"
(í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
análisis de algoritmos.
2. Procedimiento y desarrollo
Desarrollo
Las tablas hash se suelen implementar sobre vectores de una dimensión, aunque se pueden
de los arrays, las tablas hash proveen tiempo constante de búsqueda promedio O(1),1 sin
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
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
Funcionamiento
ofrecer funciones como iteración en la tabla, crecimiento y vaciado. Algunas tablas hash
Una función resumen (hash) cuyo dominio sea el espacio de claves y su imagen (o rango)
88
Inserción
que se emplea como soporte, lo cual se consigue con la función módulo. Tras este paso
Este problema se puede solucionar asociando una lista a cada posición de la tabla,
Búsqueda
Para recuperar los datos, es necesario únicamente conocer la clave del elemento, a la cual
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
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
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
Para dar una idea de la importancia de una buena estrategia de resolución de colisiones,
Aun cuando supongamos que el resultado de nuestra función hash genera índices
millón de entradas, hay un 95% de posibilidades de que al menos una colisión ocurra
Hay varias técnicas de resolución de colisiones, pero las más populares son
90
En la técnica más simple de encadenamiento, cada casilla en el array referencia una lista
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
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
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
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.
- sondeo lineal
- sondeo cuadrático
En el que el intervalo entre los intentos aumenta linealmente (por lo que los índices son
- doble hasheo
En el que el intervalo entre intentos es constante para cada registro, pero es calculado por
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
también puede requerir más cálculos que las otras formas de sondeo.
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
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,
Ejemplo
- Implementación en pseudocódigo
abierto con sondeo lineal para resolución de colisiones y progresión sencilla, una solución
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
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.
95
Se recomienda dimensionar correctamente el tamaño de las matrices para poder
almacenar los datos requeridos en el programa.
Introducción
Los arboles de búsqueda binaria son un método de búsqueda simple, dinámico y eficiente
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
1. Objetivo
2. Procedimiento o desarrollo
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
cualquier nodo x son menores que el elemento almacenado en x ,y todos los elementos
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
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.
97
Alto de un nodo: largo de la trayectoria más larga de ese nodo a una hoja.
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.
forma recursiva.
Si el valor del nodo raíz es igual que el del elemento que buscamos, terminamos
Si el valor del nodo raíz es mayor que el elemento que buscamos, continuaremos
Si el valor del nodo raíz es menor que el elemento que buscamos, continuaremos
Insertar un elemento
nodo visitado.
98
Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raíz
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
Si el valor del nodo raíz es menor que el elemento que buscamos, continuaremos la
Si Padre es NULL, el árbol estaba vacío, por lo tanto, el nuevo árbol sólo contendrá el
Borrar un elemento
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
Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raíz
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
Si 'Padre' es NULL, el nodo raíz es el único del árbol, por lo tanto, el puntero al árbol
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.
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.
10
0
Borramos el nodo 'nodo'. Esto significa volver a (1), ya que puede suceder que 'nodo' no
Si el valor del nodo raíz es mayor que el elemento que buscamos, continuaremos la
Si el valor del nodo raíz es menor que el elemento que buscamos, continuaremos la
Á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.
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,
Lo mismo puede decirse de un árbol con 7 nodos y que tenga un nivel de desbalance.
𝒗𝒂𝒄𝒊𝒐 ∶ : 𝐴𝐵𝐵
10
2
(inserta v a) es el árbol obtenido añadiendo el valor v al ABB a, si no es uno de
sus valores.
inorden.
3. Conclusiones
Se concluye que los árboles de búsqueda binaria tienen mucha importancia ya que
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
10
3
Unidad 5
Medianas y selección
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
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í.
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
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.
10
7
Grafo No dirigido
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.
Introducción
1. Objetivo.
10
9
2. Procedimiento o desarrollo
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:
[ [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.)
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:
[ [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.
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:
11
2
Si la notación de doble subíndice te confunde, puedes pensarlo de esta manera:
- 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.
11
5
TEMA 5 ALGORITMOS DE BÚSQUEDA EN GRAFOS
Bibliografía
Cormen, T., Leiserson, C., Rivest, R., & Stein, C. (2001). Introduction to Algorithms. McGraw-
Hill.
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
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
11
7