Documentos de Académico
Documentos de Profesional
Documentos de Cultura
COMPETENCIA
Unidad de Aprendizaje
Unidad de Aprendizaje 1 Algoritmia
PRESENTACIÓN Y CONTEXTUALIZACIÓN
COMPETENCIA
Conoce e identifica la terminología para construir y resolver algoritmos con las
estructuras de datos más adecuadas.
CAPACIDADES
• Analiza y critica la importancia de la algorítmica y la estructura de datos dentro del mundo
actual.
• Diferencia los distintos casos de uso y fundamentos de programación. Comprende la
diferencia entre las diferentes estructuras condicionales.
• Diferencia los distintos casos de uso y fundamentos de programación. Comprende la
diferencia entre las estructuras repetitivas.
• Analiza y critica las técnicas de estudio de las estructuras de datos.
Página 4 de 111
Algoritmia Unidad de Aprendizaje 1
ACTITUDES
Página 5 de 111
Unidad de Aprendizaje 1 Algoritmia
Algoritmos
Un computador es capaz de realizar “sólo” determinadas acciones sencillas, tales como sumar,
comparar o transferir datos, pero los problemas que normalmente interesa resolver son más
complejos. Para resolver un problema real es necesario, en primer lugar,
encontrar un método de resolución y, posteriormente, determinar la sucesión
de acciones sencillas (susceptibles de ser ejecutadas por un computador) en
que se descompone dicho método. No todos los métodos de solución de un
problema pueden ser puestos es práctica en un computador.
Para que un procedimiento pueda ser implantado en un computador
debe ser:
• Preciso: estar compuesto de pasos bien definidos (no
ambiguos) y ordenados.
• Definido: si se sigue dos veces, se obtiene el mismo
resultado cada vez.
• Finito: tener un número finito de pasos.
Un procedimiento o método para resolver un problema que cumpla los requisitos anteriores se
dice que es un algoritmo. Se puede dar por tanto la siguiente definición:
Un algoritmo es un método para resolver un problema mediante una secuencia de pasos
bien definidos, ordenados y finitos.
Para que se pueda ejecutar el algoritmo es
preciso, además, que se disponga de las
“herramientas” adecuadas para llevar a cabo cada
uno de los pasos. Si no es así, estos deberán, a su
vez, ser descompuestos en una secuencia
(algoritmo) de pasos más simples que sí se
puedan llevar a cabo.
Un programa de computador es una sucesión de
´ordenes que describen un algoritmo, escritas de
forma que puedan ser entendidas por el
computador.
En un algoritmo (y por tanto en un programa) se distinguen las
siguientes acciones:
• Entrada: es la información de partida que necesita
el algoritmo para arrancar.
• Proceso: es el conjunto de todas las operaciones a
realizar.
• Salida: son los resultados obtenidos.
Página 6 de 111
Algoritmia Unidad de Aprendizaje 1
¿Qué es un algoritmo?
Algoritmo
En aritmética y programación informática, conjunto
ordenado de instrucciones sistemáticas que permite
hallar la solución de un problema específico: el
algoritmo que se emplea para hallar las raíces
cuadradas; un programa informático es un conjunto
de secuencias de instrucciones elementales en
forma de algoritmo La palabra algoritmo se deriva
de la traducción al latín de la palabra árabe
Alkhowarizmi, nombre de un matemático y
astrónomo árabe que escribió un tratado sobre la
manipulación de números y ecuaciones en el siglo
IX. Son un conjunto de operaciones que se utilizan para resolver problemas específicos. En estas
instrucciones se indica la secuencia de operaciones que se deben realizar para que partiendo de los datos
de entada se pueda obtener el resultado buscado.
Los algoritmos son utilizados en el mundo de la ciencia para la resolución metódica de problemas. Los
algoritmos no siempre están escritos de una forma que conduce al programa más efectivo en términos
de requisitos de tiempo o almacenamiento.
Las principales características que debe tener un buen algoritmo son:
• Debe tener un punto particular de inicio.
• Debe ser completamente definido y no
debe permitir dobles interpretaciones.
• Debe ser general, es decir, soportar la
mayoría de las variantes que se puedan
presentar en la definición del problema.
• Debe ser finito en tamaño y tiempo de
ejecución.
• Debe ser legible, claro y fácil de
interpretar y entender.
TIPOS DE ALGORITMOS
• Cualitativos: son aquellos en los que se
describen los pasos utilizando palabras. Son
todos aquellos pasos o instrucciones descritos
por medio de palabras que sirven para llegar
a la obtención de una respuesta o solución de
un problema cualquier
• Cuantitativos: son aquellos en los que se
utilizan cálculos numéricos para definir los
pasos del proceso. Son aquellos pasos o
instrucciones que involucran cálculos
numéricos para llegar a un resultado
satisfactorio.
Página 7 de 111
Unidad de Aprendizaje 1 Algoritmia
• Ciencias de la Computación.
• Matemáticas.
• Ciencias Sociales.
• Ciencias Políticas.
Lenguajes algorítmicos
Características de un algoritmo
• Finito: Si se sigue un algoritmo, se debe terminar en un número finito de pasos.
• Definible: Un algoritmo debe ser preciso e indicar el orden de realización de cada paso. Si se
sigue un algoritmo dos veces, se debe obtener el mismo resultado cada vez.
• Entradas: El algoritmo debe tener cero o más entradas, es decir cantidades dadas antes de
empezar.
Página 8 de 111
Algoritmia Unidad de Aprendizaje 1
• Salidas: el algoritmo tiene una o más salidas en relación con las entradas.
Para que la labor de programación sea una tarea fácil debemos seguir una metodología la cual
comprende los siguientes pasos:
a) Definición del problema (Enunciado)
b) Definición de la solución (Análisis del problema)
c) Diseño del algoritmo
d) Desarrollo del problema (Codificación)
e) Depuración y pruebas (Ejecución – Evaluación de Resultados)
f) Documentación
Ejemplo:
OBJETIVO DEL PROBLEMA: CALCULAR EL ÁREA DE UN RECTÁNGULO
Entrada de Datos Proceso Resultado o Salida
Altura (h)
a=b*h área (a)
Base (b)
Tipos de algoritmo
Algoritmos secuenciales
Es aquélla en la que una acción (instrucción)
sigue a otra en secuencia. Las tareas se suceden
de tal modo que la salida de una es la entrada de
la siguiente y así sucesivamente hasta el fin del
proceso. La estructura secuencial tiene una
entrada y una salida. Su representación gráfica
es la siguiente:
Algoritmos condicionales
En los lenguajes de programación es común el
uso de condicionales que sirven para denotar
diferentes alternativas que pueden llevarse a
cabo dado el valor de una expresión lógica, el
cual siempre será verdadero o falso. La forma
general que tiene un condicional (una pregunta)
es la siguiente: SI (expresión lógica verdadera)
instrucciones que se realizan si la expresión
lógica es verdadera EN CASO CONTRARIO
instrucciones que se realizan si la expresión
lógica es falsa
Página 10 de 111
Algoritmia Unidad de Aprendizaje 1
Pseudocódigo
Una de las mejores formas de aprender a programar es empezar por los diagramas de flujo y el
pseudocódigo. Ambos facilitan al estudiante su inmersión en la resolución de problemas mediante
algoritmos.
El pseudocódigo es una forma de expresar los
distintos pasos que va a realizar un programa, de
la forma más parecida a un lenguaje de
programación. Su principal función es la de
representar por pasos la solución a un problema
o algoritmo, de la forma más detallada posible,
utilizando un lenguaje cercano al de
programación. El pseudocódigo no puede
ejecutarse en un computador ya que entonces
dejaría de ser pseudocódigo, como su propio
nombre indica, se trata de un código falso
(pseudo = falso), es un código escrito para que lo entienda el ser humano y no la máquina.
Aprender a escribir pseudocódigo para la resolución de un problema permite hacer mucho más sencilla
su programación en un lenguaje convencional, por lo que, si estás interesado en comenzar tu formación
como programador y no tienes conocimientos previos, resulta muy recomendable y conveniente
formarse en pseudocódigo antes de empezar a estudiar cualquier lenguaje de programación
Diagrama de flujo
Un diagrama de flujo es una representación gráfica de un proceso. Cada paso del proceso es
representado por un símbolo diferente que contiene una breve descripción de la etapa de
proceso. Los símbolos gráficos del flujo del proceso están unidos entre sí con flechas que
indican la dirección de flujo del proceso.
Página 11 de 111
Unidad de Aprendizaje 1 Algoritmia
Página 12 de 111
Algoritmia Unidad de Aprendizaje 1
Pseudocódigo:
Es un lenguaje de especificación (descripción) de algoritmos.
Generalmente se escribe en el idioma natural del usuario, es muy semejante al código fuente de
un programa.
Se considera un primer borrador, dado que el pseudocódigo tiene que traducirse posteriormente
a un lenguaje de programación. El pseudocódigo no puede ser ejecutado por el computador.
Ejemplo de un Pseudicódigo: (Para el desarrollo del Caso propuesto)
Proceso de Datos
a=b*h;
Salida de Información
System.out.println("El área es: " + a);
}
}
Página 13 de 111
Unidad de Aprendizaje 1 Algoritmia
Depuración Y Prueba
Consiste en la ejecución, depuración y solución de errores. Los errores que podrían presentarse
pueden ser:
Errores de Sintaxis: Son errores de escritura de código, el
compilador no los puede interpretar y por lo tanto cuando
ejecutamos el programa los señala como un error indicándose la
línea y elemento desconocidos, mientras no arreglemos todos estos
errores el programa no podrá ejecutarse.
Documentación
Página 14 de 111
Algoritmia Unidad de Aprendizaje 1
Las estructuras condicionales comparan una variable contra otro(s) valor(es), para que, en base
al resultado de esta comparación, se siga un curso de acción dentro del programa. Cabe
mencionar que la comparación se puede hacer contra otra variable o contra una constante, según
se necesite. Existen dos tipos básicos, las simples y las múltiples.
Página 15 de 111
Unidad de Aprendizaje 1 Algoritmia
Página 16 de 111
Algoritmia Unidad de Aprendizaje 1
Su representación en el pseudocódigo
Su representación en la codificación
EJEMPLOS
Construir un algoritmo tal, que dado como dato la
calificación de un alumno en un examen, escriba
DEFINICIÓN DEL PROBLEMA
El mismo enunciado.
ANÁLISIS DEL PROBLEMA
Salidas: mensaje de aprobado si se cumple la
condición.
Entradas: calificación
Datos adicionales: un alumno aprueba si la
calificación es mayor o igual que 7.
Sección de declaraciones:
Var Real: Cal
Donde Cal = calificación “Aprobado” en caso que esa
calificación fuese mayor o igual que 13
Página 17 de 111
Unidad de Aprendizaje 1 Algoritmia
Ejemplo
Las estructuras selectivas simples o condicionales están compuesta únicamente de una sola
condición si es verdadera ejecutara la acción o acciones si la condición es falsa no hará nada.
if (condición) entre paréntesis esta la condición
que se debe evaluar acción (si la condición entre
paréntesis es verdadera se ejecutara la acción o
acciones, porque, puede estar conformado por
varias acciones)
end
Antes de mostrar el ejemplo vamos a explicar algunos comandos que vamos a utilizar:
# => este comando nos permite poner un comentario, puede ser a principio de línea o en
cualquier posición de ella.
puts => este comando nos permite imprimir cualquier texto en pantalla, puede ser el resultado
de una operación o un texto escrito entre comillas.
Ejemplo
edad = 19 # asignamos un valor a la variable edad
if (edad > 17)
puts “Es mayor de edad”
end
Si ejecutamos el programa que hemos desarrollado el resultado serio: Es mayor de edad, porque,
la condición que esta entre paréntesis es verdadera, porque, edad que tiene asignado 19 es mayor
a 17, en cambio, si el valor asignado a la variable edad fuera menor a 18, no mostraría ningún
resultado.
Página 18 de 111
Algoritmia Unidad de Aprendizaje 1
Su representación en el pseudocódigo
Su representación en la codificación
Página 19 de 111
Unidad de Aprendizaje 1 Algoritmia
Ejemplos
Página 20 de 111
Algoritmia Unidad de Aprendizaje 1
Su representación en el pseudocódigo
Su representación en la codificación
Página 21 de 111
Unidad de Aprendizaje 1 Algoritmia
El mismo caso anterior se puede representar de un modo más simplificado usando el elseif:
//Condición inicial
If monto>=1000
{ d=monto*0.30; }
else if (monto<1000 &&monto>=500)
//Segunda condición sino se cumple el anterior
{ d=monto*0.20; }
else If (monto<500 &&monto>=200)
//Tercera condición sino se cumplen las anteriores
{ d=monto*0.10; }
Else
//En el caso de cumplirse ninguna de las anteriores
{ d=0; }
Ejemplos
Página 22 de 111
Algoritmia Unidad de Aprendizaje 1
Su representación en el pseudocódigo
Su representación en la codificación
Página 23 de 111
Unidad de Aprendizaje 1 Algoritmia
Ejemplos
EJEMPLO: Realizar un algoritmo que lea el número que representa el día de la semana y diga que día
es, teniendo en cuenta lunes=1, martes 2…, domingo=7
Página 24 de 111
Algoritmia Unidad de Aprendizaje 1
Programación Modular
Uno de los métodos más conocidos para resolver un problema es dividirlo en problemas más
pequeños, llamados subproblemas. De esta manera, en lugar de resolver una tarea compleja y
tediosa, resolvemos otras más sencillas y a partir
de ellas llegamos a la solución. Esta técnica se
usa mucho en programación ya que programar no
es más que resolver problemas, y se le suele
llamar diseño descendente, metodología del
divide y vencerás o programación top-down.
Es evidente que, si esta metodología nos lleva a
tratar con subproblemas, entonces también
tengamos la necesidad de poder crear y trabajar
con subprogramas para resolverlos. A estos
subprogramas se les suele llamar módulos, de ahí viene el nombre de programación modular.
Los subproblemas o módulos se diseñan con subprogramas, que a su vez se clasifican en
procedimientos y funciones. Los procedimientos y las funciones son unidades de programas
diseñados para ejecutar una tarea específica. El proceso de
descomposición de un problema en módulos se conoce
como modulación y a la programación relativa a ellos,
programación modular.
Al aplicar la programación modular, un problema
complejo debe ser dividido en varios subproblemas más
simples, y estos a su vez en otros subproblemas más
simples. Esto debe hacerse hasta obtener subproblemas lo
suficientemente simples como para poder ser resueltos
fácilmente con algún lenguaje de programación. Esta
técnica se llama refinamiento sucesivo, divide y vencerás
o análisis descendente (Top-Down).
Un 'módulo' es cada una de las partes de un programa que resuelve uno de los subproblemas en
que se divide el problema complejo original. Cada uno de estos módulos tiene una tarea bien
definida y algunos necesitan de otros para poder operar. En caso de que un módulo necesite de
otro, puede comunicarse con éste mediante una interfaz de comunicación que también debe
estar bien definida.
Si bien un módulo puede entenderse como una parte de un programa en cualquiera de sus
formas y variados contextos, en la práctica se los suele tomar como sinónimos de
procedimientos y funciones. Pero no necesaria ni estrictamente un módulo es una función o un
procedimiento, ya que el mismo puede contener muchos de ellos. No debe confundirse el
término "módulo" (en el sentido de programación modular) con términos como "función" o
"procedimiento", propios del lenguaje que lo soporte.
Página 25 de 111
Unidad de Aprendizaje 1 Algoritmia
Pseudocódigo
Página 26 de 111
Algoritmia Unidad de Aprendizaje 1
Donde:
• V es una variable de control
• VI es el valor inicial
• VF es el valor final
• INC es el incremento
Pseudocódigo
Para V<---VI hasta VF incremento 1 Hacer
Bloque de instrucciones
Fin_para
Si es verdadera, se vuelve a ejecutar el bloque de instrucciones.
Y así sucesivamente, hasta que, la condición sea falsa.
Es usado cuando se conoce de antemano, el número de veces que debe repetirse una instrucción
o conjunto de ellas
Tipos de variables:
Cuando se diseñan algoritmos que incluyen estructuras de control repetitivas, existen ciertas
variables que cumplen una función específica en cada iteración del ciclo, las más comunes son:
Variables contadoras: Se usan para contar, por lo tanto, debe ser de tipo entero. Una variable
contadora se incrementa o decrementa en un valor constante en un valor constante con cada
iteración del ciclo.
Variable acumuladora: su función es almacenar valores numéricos que generalmente se suman
o multiplican en cada iteración. Por lo tanto, esta variable debe ser de tipo real.
Variable bandera: Es utilizada dentro de la condición de un ciclo, para determinar cuándo un
círculo se sigue iterando o cuando no. De esta forma una variable bandera debe ser de tipo
booleano o entero.
Ejemplo: Escriba un algoritmo (diagrama de flujo, pseudocódigo) tal que dado como datos N
números enteros, obtenga el número de ceros que hay entre estos números.
Página 27 de 111
Unidad de Aprendizaje 1 Algoritmia
Pseudocódigo
(El programa cuenta cuántos ceros hay en un grupo de N números enteros.
Inicio
cuecer<--0, l<--1, N<--0 (Declarar variables)
Leer N
Para l desde 1 hasta N
Leer num
si num<=0 entonces
hacer cuecer<-- cueces+1
Fin_si
Fin_para
Escribir cuecer
Fin
Página 28 de 111
Algoritmia Unidad de Aprendizaje 1
Página 29 de 111
Unidad de Aprendizaje 1 Algoritmia
Algoritmo
Diagrama de flujo
Página 30 de 111
Algoritmia Unidad de Aprendizaje 1
Este tipo de estructura es utilizada cuando se necesita la estructura repetitiva, mas no se conoce
con exactitud la cantidad de iteraciones del bucle, pues la cantidad de repeticiones dependerá
de si se sigue cumpliendo la condición principal del bucle.
Contadores y Acumuladores.
Contadores
Los procesos repetitivos son la base del uso de los
computadores. En estos procesos se necesita normalmente
contar los sucesos o acciones internas del bucle. Una
manera de controlar un bucle es mediante un contador. Un
contador es una variable cuyo valor se incrementa o
decrece en una cantidad constante en cada iteración.
La construcción de un contador es una de las técnicas más
comunes en la realización de diagramas de flujo. Es una
variable en la memoria que se incrementará en una unidad
cada vez que se ejecute el proceso. El contador se utiliza
para llevar la cuenta de determinadas acciones que se
pueden solicitar durante la resolución de un problema. En
las instrucciones de preparación se realiza la inicialización
del contador o contadores. La inicialización consiste en
poner el valor inicial de la variable que representa al
contador. Generalmente se inicializa con el valor 0.
Página 31 de 111
Unidad de Aprendizaje 1 Algoritmia
Acumulador
Un acumulador o totalizador es una variable cuya misión es almacenar cantidades variables
resultantes de sumas sucesivas. Realiza la misma función que un contador, con la diferencia de
que el incremento o decremento de cada suma es variable en lugar de constante, como en el
caso del contador. Se representa por la instrucción S=S+N, donde N es una variable y no una
constante.
Un acumulador es una variable en la memoria cuya misión es almacenar cantidades variables.
Se utiliza para efectuar sumas sucesivas. La principal diferencia con el contador es que el
incremento o decremento de cada suma es variable en lugar de constante como en el caso del
contador.
Página 32 de 111
Algoritmia Unidad de Aprendizaje 1
Definición.
Una función recursiva es una función que se llama a si misma. Esto es, dentro del cuerpo de la
función se incluyen llamadas a la propia función. Esta estrategia es una alternativa al uso de
bucles. Una solución recursiva es, normalmente, menos
eficiente que una solución basada en bucles. Esto se debe a
las operaciones auxiliares que llevan consigo las llamadas a
las funciones. Cuando un programa llama a una función que
llama a otra, la cual llama a otra y así sucesivamente, las
variables y valores de los parámetros de cada llamada a cada
función se guardan en la pila o stack, junto con la dirección
de la siguiente línea de código a ejecutar una vez finalizada
la ejecución de la función invocada. Esta pila va creciendo a
medida que se llama a más funciones y decrece cuando cada
función termina. Si una función se llama a si misma
recursivamente un número muy grande de veces existe el
riesgo de que se agote la memoria de la pila, causando la
terminación brusca del programa.
A pesar de todos estos inconvenientes, en muchas
circunstancias el uso de la recursividad permite a los programadores especificar soluciones
naturales y sencillas que sin emplear esta técnica serían mucho más complejas de resolver. Esto
convierte a la recursión en una potente herramienta de la programación. Sin embargo, por sus
inconvenientes, debe emplearse con cautela.
La mayoría de los lenguajes de programación dan soporte a la recursión permitiendo a una
función llamarse a sí misma desde el texto del programa. Los lenguajes imperativos definen las
estructuras de loops como while y for que son usadas para
realizar tareas repetitivas. Algunos lenguajes de
programación funcionales no definen estructuras de loops,
sino que posibilitan la recursión llamando código de forma
repetitiva. La teoría de la computabilidad ha demostrado que
estos dos tipos de lenguajes son matemáticamente
equivalentes, es decir que pueden resolver los mismos tipos
de problemas, aunque los lenguajes funcionales carezcan de
las típicas estructuras while y for.
Es una técnica utilizada en programación que nos permite que
un bloque de instrucciones se ejecute un cierto número de
veces (el que nosotros determinemos). A veces es algo
complicado de entender, pero no os preocupéis. Cuando
veamos los ejemplos estará clarísimo. En Java, como en otros
muchos lenguajes, los métodos pueden llamarse a sí mismos. Gracias a esto, podemos utilizar
a nuestro favor la recursividad en lugar de la iteración para resolver determinados tipos de
problemas.
Página 33 de 111
Unidad de Aprendizaje 1 Algoritmia
Ejemplo sencillo
Vamos a ver un pequeño ejemplo que no hace absolutamente nada. Es un método cuyo único
objetivo es llamarse a sí mismo:
void cuentaRegresiva () {
cuentaRegresiva();
}
Si ejecutáis esto, os va a dar un error en la pila (mítico StackOverflow Error, Biblia de los
programadores).
Como véis, he llamado al método cuentaRegresiva porque vamos a mostrar por pantalla la
cuenta atrás de un número que nosotros pasemos como parámetro a la función. Por ejemplo,
para hacer la cuenta atrás de 10 sin recursividad, haríamos:
for( int i = 10; i >= 0; i--) {
System.out.println(i);
}
Ahora, para hacerlo de manera recursiva, tendríamos que pasar como parámetro un número.
Además, tras imprimir ese número, llamaremos a la misma función con el número actual
restando uno:
void cuentaRegresiva(int numero) {
System.out.println(numero);
cuentaRegresiva(numero - 1);
}
Es lo que os he comentado arriba. Llamamos a la función con un 10. Imprimimos el 10 y
llamamos a la función con un 9. Imprimimos el 9 y llamamos a la función con un 8. Así hasta
el fin de los días. Digo hasta el fin de los días porque os va a saltar error si ejecutáis esto así
directamente:
public class Recursividad {
Página 34 de 111
Algoritmia Unidad de Aprendizaje 1
Problema: llamada infinita. Para ello, lo que tenemos que hacer es que cuando el número sea
0, deje de llamar a la función. Para eso, metemos una estructura condicional de toda la vida.
Gracias al condicional, dejará de ejecutarse a partir de 0:
void cuentaRegresiva(int numero) {
System.out.println(numero);
if(numero > 0) {
cuentaRegresiva(numero - 1);
}
}
Factorial
Calcular la factorial de un número con recursividad es el típico ejemplo para explicar este
método de programación. Recordad que la factorial de un número es multiplicar dicho número
por todos sus anteriores hasta llegar a 1. Se representa con una exclamación. Por ejemplo:
5! = 54321 = 120 El recorrer los números hacia atrás ya lo tenemos hecho. Ahora lo que queda
es multiplicar ese número por su anterior, y así sucesivamente:
int factorial(int n) {
if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
Si ya queréis simplificarlo al máximo y dejar a vuestros amigos con la boca abierta, haced esto:
int factorial(int n) {
return (n == 0) ? 1 : n * factorial(n - 1);
}
Espero que os haya servido el tutorial para aprender algo más sobre programación. Recordad
que esto está hecho en Java, pero vale para otros lenguajes.
Cómo funcionan los algoritmos recursivos
Un algoritmo recursivo es un algoritmo que expresa la solución de un problema en términos de
una llamada a sí mismo. La llamada a sí mismo se conoce como llamada recursiva o recurrente.
Generalmente, si la primera llamada al
subprograma se plantea sobre un problema de
tamaño u orden N, cada nueva ejecución
recurrente del mismo se planteará sobre
problemas, de igual naturaleza que el original,
pero de un tamaño menor que N. De esta
forma, al ir reduciendo progresivamente la
complejidad del problema que resolver, llegará
un momento en que su resolución sea más o
menos trivial (o, al menos, suficientemente
Página 35 de 111
Unidad de Aprendizaje 1 Algoritmia
manejable como para resolverlo de forma no recursiva). En esa situación diremos que estamos
ante un caso base de la recursividad.
Las claves para construir un subprograma recurrente son:
Cada llamada recurrente se debería definir sobre un
problema de menor complejidad (algo más fácil de
resolver).
Ha de existir al menos un caso base para evitar que la
recurrencia sea infinita.
Es frecuente que los algoritmos recurrentes sean más
ineficientes en tiempo que los iterativos, aunque suelen ser
mucho más breves en espacio.
Un método frecuente para simplificar es dividir un problema en
problemas derivados de menor tamaño del mismo tipo. Esto se
conoce como dialecting. Como técnica de programación se
denomina divide y vencerás y es pieza fundamental para el diseño de
muchos algoritmos de importancia, así como parte esencial de la
programación dinámica.
Virtualmente todos los lenguajes de programación modernos permiten la
especificación directa de funciones y subrutinas recursivas. Cuando se
llama una función de este tipo, el ordenador, para la mayoría de los lenguajes en casi todas las
arquitecturas basadas en una pila (stack) o en la implementación del lenguaje, lleva la cuenta
de las distintas instancias de la función, en numerosas arquitecturas
mediante el uso de un call stack, aunque no de forma exclusiva. A la
inversa, toda función recursiva puede transformarse en una función
iterativa usando un stack.
La mayoría (aunque no todas) de las funciones y subrutinas que
pueden ser evaluadas por un ordenador, pueden expresarse en
términos de una función recursiva (sin tener que utilizar una
iteración pura); a la inversa, cualquier función recursiva puede
expresarse en términos de una iteración pura, dado que la
recursión es, de por sí, también iterativa. Para evaluar una función
por medio de la recursión, tiene que definirse como una función
de sí misma (¡ej. el factor n! = n * (n - 1)! , donde 0! se define
como 1). Resulta evidente que no todas las evaluaciones de
funciones se prestan a un acercamiento recursivo. Por lo general,
todas las funciones finitas pueden describirse directamente de
forma recursiva; las funciones infinitas (ej. las series de e = 1/1!
+ 2/2! + 3/3!...) necesitan un criterio extra para detenerse, ej. el
número de iteraciones, o el número de dígitos significativos, en caso contrario una iteración
recursiva resultaría en un bucle infinito.
A modo de ilustración: Si se encuentra una palabra desconocida en un libro, el lector puede
anotar la página actual en un papel y ponerlo en una pila (hasta entonces vacía). El lector
consulta la palabra en otro artículo y, de nuevo, descubre otra palabra desconocida, la anota y
la pone en la pila, y así sucesivamente. Llega un momento que el lector lee un artículo que
donde todas las palabras son conocidas. El lector retorna entonces a la última página y continua
la lectura desde ahí, y así hasta que se retira la última nota de la pila retornando entonces al
libro original. Este modus operandi es recursivo.
Página 36 de 111
Algoritmia Unidad de Aprendizaje 1
Algunos lenguajes diseñados para programación lógica y programación funcional ofrecen la
recursión como el único medio de repetición directa disponible para el programador. Estos
lenguajes suelen conseguir que la recursión de cola sea tan eficiente como la iteración,
permitiendo a los programadores expresar otras estructuras repetitivas (tales como map y for
de scheme) en términos de recursión.
La recursión está profundamente anclada en la teoría de computación, con la equivalencia
teórica de función micro recursiva y máquinas de Turing en la cimentación de ideas sobre la
universalidad del ordenador moderno.
Programación recursiva
Crear una subrutina recursiva requiere principalmente la definición de un "caso base", y
entonces definir reglas para subdividir casos más complejos en el caso base. Para una subrutina
recursiva es esencial que, con cada llamada recursiva, el problema se reduzca de forma que al
final llegue al caso base.
Algunos expertos clasifican la recursión como "generativa" o bien "estructural". La distinción
se hace según de donde provengan los datos con los que trabaja la subrutina. Si los datos
proceden de una estructura de datos similar a una lista, entonces la subrutina es
"estructuralmente recursiva"; en caso contrario, es "generativamente recursiva".
Muchos algoritmos populares generan una nueva cantidad de datos a partir de los datos
aportados y recurren a partir de ahí. HTDP (How To Design Programs), al español, "Cómo
diseñar programas", se refiere a esta variante como recursión generativa. Ejemplos de recursión
generativa incluyen: máximo común divisor, quicksort, búsqueda binaria, mergesort, Método
de Newton, fractals e integración adaptiva.
Página 37 de 111
Unidad de Aprendizaje 1 Algoritmia
Una relación recurrente es una ecuación que relaciona términos posteriores en la secuencia con
términos previos.
Esta función factorial también puede describirse sin usar recursión haciendo uso de típicas
estructuras de bucle que se encuentran en lenguajes de programación imperativos:
Página 38 de 111
Algoritmia Unidad de Aprendizaje 1
El lenguaje de programación scheme es, sin embargo, un lenguaje de programación funcional
y no define estructuras de loops de cualquier tipo. Se basa únicamente en la recursión para
ejecutar todo tipo de loops. Dado que scheme es recursivo de cola, se puede definir una
subrutina recursiva que implementa la subrutina factorial como un proceso iterativo, es decir,
usa espacio constante, pero tiempo lineal.
Fibonacci
Otra popular secuencia recursiva es el Número de Fibonacci. Los primeros elementos de la
secuencia son: 0, 1, 1, 2, 3, 5, 8, 13, 21...
Este algoritmo de Fibonacci es especialmente malo pues cada vez que se ejecuta la función,
realizará dos llamadas a la función a sí misma, cada una de las cuales hará a la vez dos llamadas
más y así sucesivamente hasta que terminen en 0 o en 1. El ejemplo se denomina "recursión de
árbol", y sus requisitos de tiempo crecen de forma exponencial y los de espacio de forma lineal.
Página 39 de 111
Unidad de Aprendizaje 1 Algoritmia
Relación recursiva del máximo común denominador, donde x\% y x\% y expresa el resto de la
división entera x/y
Página 40 de 111
Algoritmia Unidad de Aprendizaje 1
Nótese que el algoritmo "recursivo" mostrado arriba es, de hecho, únicamente de cola recursiva,
lo que significa que es equivalente a un algoritmo iterativo. En el ejemplo siguiente se muestra
el mismo algoritmo usando explícitamente iteración. No acumula una cadena de operaciones
deferred, sino que su estado es, más bien, mantenido completamente en las variables x e y. Su
"number of steps grows the as the logarithm of the numbers involved.", al español "número de
pasos crece a medida que lo hace el logaritmo de los números involucrados.
El algoritmo iterativo requiere una variable temporal, e incluso supuesto el conocimiento del
Algoritmo de Euclides es más difícil de entender el proceso a simple vista, aunque los dos
algoritmos son muy similares en sus pasos.
Torres de Hanói
Para una detallada discusión de la descripción de este problema, de su historia y de su solución,
consúltese el artículo principal. El problema, puesto de forma simple, es el siguiente: Dadas
pilas, una con un conjunto de N discos de tamaño creciente, determina el mínimo (óptimo)
número de pasos que lleva mover todos los discos desde su posición inicial a otra pila sin
colocar un disco de mayor tamaño sobre uno de menor tamaño.
Ejemplos de implementación:
Página 41 de 111
Unidad de Aprendizaje 1 Algoritmia
Aunque no todas las funciones recursivas tienen una solución explícita, la secuencia de la Torre
de Hanói puede reducirse a una fórmula explícita.
Búsqueda binaria
El algoritmo de búsqueda binaria es un método de búsqueda de un dato en un vector de datos
ordenado dividiendo el vector en dos tras cada pasada. El truco es escoger un punto cerca del
centro del vector, comparar en ese punto el dato con el dato buscado para responder entonces a
una de las siguientes 3 condiciones: se encuentra el dato buscado, el dato en el punto medio es
mayor que el valor buscado o el dato en el punto medio es menor que el valor buscado.
Se usa recursión en este algoritmo porque tras cada pasada se crea un nuevo vector dividiendo
en original en dos. La subrutina de búsqueda binaria se llama entonces de forma recursiva, cada
vez con un vector de menor tamaño. El tamaño del vector se ajusta normalmente cambiando el
índice inicial y final. El algoritmo muestra un orden logaritmo de crecimiento porque divide
esencialmente el dominio del problema en dos tras cada pasada.
Página 42 de 111
Algoritmia Unidad de Aprendizaje 1
Método de caja.
Los dos métodos más importantes para cifrar un mensaje son el de transposición y el de sustitución.
En el primero las letras del mensaje original permanecen intactas y lo que se cambia es el orden en
el que estas aparecen. En cambio, en el método de sustitución las letras son reemplazadas por
números, letras o signos cualesquiera, dejando el
orden original de las letras intacto. Este último método
también se conoce como codificación. Ambos
métodos pueden ser utilizados en un mismo sistema
de cifrado, una o varias veces, con el fin de hacer más
difícil el descifrado.
En este tema vamos a aprender a utilizar un sencillo
método de transposición conocido como el "método de las cajas” y que fue utilizado hasta finales de
la Segunda Guerra Mundial por los servicios de inteligencia de diferentes países.
Como en todo sistema de encriptación, tanto el que envía el mensaje, como el que lo recibe, deben
conocer la "clave".
En este método la clave consiste, en una palabra. Vamos a describir su funcionamiento mediante un
ejemplo práctico.
Página 43 de 111
Unidad de Aprendizaje 1 Algoritmia
Ejemplo
Supongamos que la clave secreta es "sangakoo" y que el mensaje que queremos enviar es
EL PRÓXIMO LUNES HAY EXAMEN DE MATEMÁTICAS.
Lo primero que debemos hacer es abrir una tabla y escribir en la primera fila la palabra clave.
S A N G A K O O
A continuación, debemos numerar las letras según el orden en que aparecen en el alfabeto.
S A N G A K O O
8 1 5 3 2 4 6 7
Si la letra aparece repetida le ponemos números consecutivos. Por ejemplo, la A es la primera letra,
pero como hay dos, le ponemos a la primera un 1 y a la segunda un 2. La siguiente letra del alfabeto
que aparece es la G, luego la K y así sucesivamente.
A continuación, en la siguiente fila, escribimos el mensaje que queremos enviar, todo seguido, sin
espacios.
S A N G A K O O
8 1 5 3 2 4 6 7
e l p r o x i m
o l u n e s h a
y e x a m e n d
e m a t e m a t
i c a s
Página 44 de 111
Algoritmia Unidad de Aprendizaje 1
Ahora ya tenemos construida la caja que nos va a servir para codificar el mensaje. Lo que debemos
hacer ahora es escribir todos los grupos de letras que aparecen bajo cada número. Y hacerlo
ordenadamente. Empezamos por el grupo que está debajo del 1
llemc
luego la que está debajo del 2
oeme
y así hasta completar todas las columnas. El texto cifrado completo sería pues:
llemc oeme rnats xsem puxaa ihha madt eoyei
Veamos ahora un ejemplo de descifrado.
Ejemplo
Supongamos que el mensaje que recibimos es
ELDAA AILT SDAE TOACR HVOR
y la palabra clave
PATIO
Para descifrar el mensaje primero colocamos la palabra clave en la primera fila de la tabla.
P A T I O
P A T I O
4 1 5 2 3
Página 45 de 111
Unidad de Aprendizaje 1 Algoritmia
P A T I O
4 1 5 2 3
T E H A S
O L V I D
A D O L A
C A R T E
R A
Ahora ya tenemos descifrado el mensaje. Está escrito en las filas:
Página 46 de 111
Algoritmia Unidad de Aprendizaje 1
RESUMEN UNIDAD 1
Página 47 de 111
Unidad de Aprendizaje 1 Algoritmia
dentro del mientras), después se evalúa de nuevo la expresión booleana. Este proceso se repite
una y otra vez mientras la condición sea verdadera.
Los procesos repetitivos son la base del uso de los computadores. En estos procesos se necesita
normalmente contar los sucesos o acciones internas del bucle. Una manera de controlar un bucle
es mediante un contador. Un contador es una variable cuyo valor se incrementa o decrece en
una cantidad constante en cada iteración.
Un acumulador o totalizador es una variable cuya misión es almacenar cantidades variables
resultantes de sumas sucesivas. Realiza la misma función que un contador, con la diferencia de
que el incremento o decremento de cada suma es variable en lugar de constante, como en el
caso del contador. Se representa por la instrucción S=S+N, donde N es una variable y no una
constante.
Una función recursiva es una función que se llama a sí misma. Esto es, dentro del cuerpo de la
función se incluyen llamadas a la propia función. Esta estrategia es una alternativa al uso de
bucles. Un algoritmo recursivo es un algoritmo que expresa la solución de un problema en
términos de una llamada a sí mismo. La llamada a sí mismo se conoce como llamada recursiva
o recurrente. Crear una subrutina recursiva requiere principalmente la definición de un "caso
base", y entonces definir reglas para subdividir casos más complejos en el caso base. Para una
subrutina recursiva es esencial que, con cada llamada recursiva, el problema se reduzca de
forma que al final llegue al caso base.
El Método de caja, es un método de encriptamiento, de ahí son dos métodos más importantes
para cifrar un mensaje son el de transposición y el de sustitución. En el primero las letras del
mensaje original permanecen intactas y lo que se cambia es el orden en el que estas aparecen.
En cambio, en el método de sustitución las letras son reemplazadas por números, letras o signos
cualesquiera, dejando el orden original de las letras intacto. Este último método también se
conoce como codificación. Ambos métodos pueden ser utilizados en un mismo sistema de
cifrado, una o varias veces, con el fin de hacer más difícil el descifrado.
Lecturas Recomendadas
• http://www.edu4java.com/es/conceptos/que-es-un-algoritmo-que-es-un-programa.html
• https://es.wikibooks.org/wiki/Fundamentos_de_programaci%C3%B3n/Algoritmos_y_
programas
• http://biolab.uspceu.com/aotero/recursos/docencia/TEMA%207.pdf
• https://picandocodigo.net/2008/recursividad-en-programacion/
Página 48 de 111
PRESENTACIÓN Y CONTEXTUALIZACIÓN
Cuando hablamos de programación, la estructura de datos está representada por una forma
determinada que tenemos de organizar los datos de un equipo informático para que podamos
utilizarlos de la manera más efectiva posible. Dependiendo del tipo de aplicación o recurso que
vayamos a usar requeriremos una estructura de datos independiente y distinta a las demás, dado
que cada una encaja en el contexto de forma determinada y con una serie de objetivos. Con
estas estructuras tenemos la posibilidad de administrar todo tipo de datos sin ningún tipo de
obstáculo, algo que en la actualidad se usa en la red para poder llevar a cabo, por ejemplo, los
sistemas de indexado de contenidos. Y también juegan un papel clave en la creación de los
mejores algoritmos, así como en su uso con lenguajes de programación que se benefician de
ellas. Piensa en ellas como una forma de representar información. Así como usamos una
variable de tipo array para representar un número finito de elementos, podemos representar una
lista en una estructura de datos de tipo lista enlazada, esta estructura puede ser creada por
nosotros o provista por una librería. Las estructuras de datos no solo representan la información,
también tienen un comportamiento interno, y se rige por ciertas reglas/restricciones dadas por
la forma en que esta construida internamente. Las estructuras de datos nos permiten resolver un
problema de manera más sencilla gracias a que las reglas que las rigen nunca cambian, así que
puedes asumir que ciertas cosas son siempre ciertas. Adicionalmente son dinámicas, si usas
Estructura De Datos
lenguajes de programación como Java, sabrás que necesitas definir el tamaño de los arrays antes
de ser usados. Usando una estructura de datos, puedes hacer “un array” de tamaño
indeterminado.
COMPETENCIA
Construye algoritmos para resolver problemas basados en estructuras de datos estáticas.
CAPACIDADES
• Aplica las operaciones de suma, promedio, valor máximo y mínimo de los valores cargados
en el arreglo unidimensional.
• Identifica y desarrolla habilidades básicas para la recolección de datos. Insertar, Modificar,
Eliminar y Buscar elementos dentro de un arreglo.
• Identifica y desarrolla habilidades complejas para unir dos arreglos unidimensionales.
• Desarrolla soluciones utilizando recursividad y reconoce las ventajas y desventajas de su
uso.
ACTITUDES
• Desarrolla una actitud emprendedora mediante la toma de iniciativas.
• Actúa con responsabilidad personal, al cumplir con los horarios establecidos.
• Respeto a las normas de convivencia.
• Cumple con la presentación de los trabajos encomendados de manera individual y en equipo.
La Unidad de Aprendizaje 02: Estructura De Datos
Comprende el desarrollo de los siguientes temas:
Definición
Cuando hablamos de programación, la estructura de datos está representada por una forma
determinada, que tenemos de organizar los datos de un equipo informático para que podamos
utilizarlos de la manera más efectiva posible. Dependiendo del tipo de
aplicación o recurso que vayamos a usar requeriremos una estructura
de datos independiente y distinta a las demás, dado que cada una
encaja en el contexto de forma determinada y con una serie de
objetivos.
Con estas estructuras tenemos la posibilidad de administrar todo tipo
de datos sin ningún tipo de obstáculo, algo que en la actualidad
se usa en la red para poder llevar a cabo, por ejemplo, los
sistemas de indexado de contenidos. Y también juegan un
papel clave en la creación de los mejores algoritmos, así
como en su uso con lenguajes de programación que se
benefician de ellas.
Dependiendo de su finalidad hay distintos tipos de estructura de datos que pueden utilizarse y
que aportan unas características determinadas en cada uno de los casos.
Uno de los tipos más utilizados es el registro, un tipo de estructura que reúne datos que han sido
agregados. Con este tipo de estructura lo que hacemos es unificar un valor con otra serie de
valores relacionados formando una secuencia.
También existe el vector, que concentra elementos dando lugar a una estructura ordenada y
relacionada. Sus datos coinciden en formar parte de un tipo concreto y en estar colocados en un
orden determinado. Para una mejor facilidad de uso se aplican palabras de memoria que ayudan
a su organización, mientras que también hay que tener en cuenta que es factible que los arreglos
puedan sufrir cambios de tamaño. De forma derivada el vector asociativo permite que sean
eliminados pares nombre-valor dependiendo de las exigencias del programador y del contexto.
Otro tipo de estructura es la que está representada por la unión, en la cual se
unen distintos datos, pero diferenciándose del registro debido a que solo se
da cobijo a un valor determinado. En el caso de requerir un campo añadido
dentro del registro, se utiliza el término de tipo variante.
La flexibilidad de las estructuras de datos permite su aprovechamiento
de formas muy variadas. Un buen reflejo de ello lo aporta el grafo, que
se trata de una versión en la cual los datos están conectados debido a
la presencia de nodos. Y todos estos nodos no solo disponen de un
valor determinado que les ha sido asignado, sino que cuentan con
vínculos con otros de los nodos. La facilidad en la comunicación de
estos nodos abre muchas posibilidades y es por lo que se usan en la
representación de redes. También lo facilita que a la hora de crear esta estructura se puedan
definir puntos de inicio y de final mediante la elección de nodos exactos con los que se da la
oportunidad de marcar la dirección a seguir en el proceso de trabajo.
Hay una variante específica que recibe el nombre de árbol y que se representa porque el camino
parte de un punto inicial que deriva hacia todos los demás nodos. Este tipo de grafo
no da la oportunidad de crear ciclos y también se puede agrupar en conjunto, lo
que da lugar al término bosque.
Su relación con los lenguajes, comprender la utilidad de la estructura de datos
está relacionado con saber también qué tipo de relación tienen con los lenguajes
de programación. En este sentido hay que dejar totalmente de lado los
lenguajes de bajo nivel, dado que no tienen soporte para estas estructuras.
Los que sí la tienen son los lenguajes de alto nivel, además de algunas
excepciones que no resultan trascendentes. Una buena demostración de
este tipo de relación entre estructuras y lenguaje la podemos ver en dos
lenguajes muy específicos que se utilizan en la actualidad y que siguen
siendo de gran rendimiento: Pascal y C. Este tipo de soporte siempre ha ayudado a los
programadores y con el paso del tiempo las propias plataformas que acompañan a los lenguajes
modernos han ido dando soporte a estas estructuras de manera interna, permitiendo así que
sigan presentes para aprovecharlas en sus respectivos contextos.
¿Por qué son útiles las estructuras de datos?
Lo primero que debemos tener claro es la definición de “estructura de datos” y que a partir de
esta definición parten otros conceptos y tipos. Que las estructuras de datos se estudian como
conceptos sobre programación, y no sobre un lenguaje de programación en específico, por lo
que cada lenguaje puede tener diferentes implementaciones de estructuras de datos.
Una “estructura de datos” es una colección de valores, la relación que existe
entre estos valores y las operaciones que podemos hacer sobre ellos; en pocas
palabras se refiere a cómo los datos están organizados y cómo se pueden
administrar. Una estructura de datos describe el formato en que los valores
van a ser almacenados, cómo van a ser accedidos y modificados,
pudiendo así existir una gran cantidad de estructuras de datos.
Lo que hace específica a una estructura de datos es el tipo de problema
que resuelve. Algunas veces necesitaremos una estructura muy simple
que sólo permita almacenar 10 números enteros consecutivamente sin importar que se repitan
y que podamos acceder a estos números por medio de un índice, porque nuestro problema a
resolver está basado en 10 números enteros solamente. O tal vez nos interese almacenar N
cantidad de números enteros y que se puedan ordenar al momento de insertar uno nuevo, por lo
que necesitaremos una estructura más flexible.
Las estructuras de datos son útiles porque siempre manipularemos datos, y si los datos están
organizados, esta tarea será mucho más fácil.
Considera el siguiente problema:
¿De qué forma puedo saber si una palabra tiene exactamente las mismas letras que otra palabra?
o, dicho de otra forma, ¿cómo saber si una palabra es una permutación de otra palabra?
Si queremos resolver este problema con papel y
lápiz, basta con escribir las palabras y
visualmente identificar si ambas palabras tienen
las mismas letras, una forma rápida es contar
mentalmente el número de cada tipo de letra en
ambas palabras y si tienen el mismo número
entonces si es una permutación.
Pero si quisiéramos resolverlo mediante programación tenemos que decirle a la computadora
como saber que es una palabra y decirle cómo debe comparar las palabras de la misma forma
en que lo resolvimos en papel y lápiz, ¿Se te ocurre alguna forma?
Qué tal si pensamos en las palabras como una estructura de casillas de letras secuenciales (array
ó arreglo) donde cada letra representa una casilla en esta estructura. A cada casilla le damos un
índice con el cual podemos acceder a ella para saber qué letra tiene contenida, esto le indicará
a la computadora cómo reconocer una palabra.
0 1 2 3 0 1 2 3
C A S A S A C A
Ahora, para resolver el problema debemos saber cómo comparar las palabras y sus letras, lo
primero que podemos evaluar es el length ó longitud de la palabra, o
sea, cuántos caracteres tiene; si las palabras tienen diferente número
de caracteres entonces no tiene sentido comparar más, ya sabemos
que NO tendrán exactamente las mismas letras. Lo siguiente será
contar las letras por tipo de letra. En el ejemplo anterior de las
palabras “casa” y “saca” contamos las letras mentalmente, pero
las escribimos en el papel con una estructura muy específica,
cada letra que encontramos se asocia al número que
contamos; entonces, ¿habrá alguna estructura de datos que
me ayude a asociar las letras con el número que
contamos?, la respuesta es sí. Podemos pensar en esta
asociación como una estructura de tipo key-value (llave-
valor) llamada dictionary ó diccionario, donde la letra es
la llave y su valor asociado es el número contado;
además, en esta estructura no debemos repetir la llave
porque de lo contrario tendremos letras repetidas y no
podremos contar, es por eso que la estructura dictionary es distinta al array, ya que en el array
si podemos repetir letras, pero en esta otra estructura no deberíamos permitirlo ya que eso sería
lo que nos permita resolver el problema de contar.
Los Array muestran algunas ventajas con respecto a otras estructuras, como, por ejemplo:
Al tener un espacio contiguo en memoria cada index de cada elemento del array apunta
directamente a una dirección de memoria, de esta forma podemos acceder arbitrariamente a los
datos de forma instantánea puesto que sabemos la
dirección de memoria exacta. Esto deriva en un
acceso de tiempo constante dado por los index.
Los Array son puramente datos lo que significa
que no es necesario desperdiciar espacio en
memoria almacenando información extra que
ayude a la localización de sus elementos como es
el caso de las estructuras enlazadas, los Array
tienen eficiencia de espacio.
Localidad de memoria, es común que en la
programación los datos de una estructura sean
iterados (o recorridos) y los arráis son buenos para
esto ya que exhiben excelente localización de
memoria, permitiéndonos aprovechar la alta velocidad de la caché en computadoras modernas.
La gran desventaja de los Arrays es que no podemos ajustar
su tamaño a la mitad de la ejecución de un programa, pero ¿y
qué tal si creamos uno nuevo con la nueva dimensión
deseada?; esto sería bueno si supiéramos el tamaño que
deseamos todo el tiempo, pero si no lo sabemos sólo tenemos
2 opciones: crear una array lo suficientemente grande para
almacenar nuestros datos, pero esto deriva en un desperdicio
de memoria totalmente innecesario, o podemos crear un
nuevo array, doblar el tamaño de éste cada vez que se
necesite crecer y copiar los datos del array anterior al nuevo
array, hacer esto tiene el mismo nivel de complejidad que si
tuviéramos un array único suficientemente grande, pero con
la ventaja de que sólo va a crecer cuándo sea necesario,
evitando así desperdiciar memoria. Es pues que de esta forma podemos alargar un array en
tiempo de ejecución, a este concepto se le conoce como dynamic arrays ó arreglos dinámicos.
Los Arrays son la base de muchos otros tipos de estructuras de datos
como acabamos de ver con los arreglos dinámicos.
Otra estructura muy común que nos ayuda a representar datos reales
son las llamadas matrices o tablas que no son más que Arrays de
múltiples dimensiones. Pensemos, si un arreglo es una colección
consecutiva de valores, se puede decir que son de tipo lineal en una
dimensión plana o unidimensionales, si quisiéramos formar una
matriz o tabla (matrix o table) podríamos crear un array
bidimensional, lo que quiere decir que tendremos que localizar a un
elemento por su index [i , j], o bien su ubicación lineal a la derecha y
hacia abajo como en un plano cartesiano con dimensiones xy
asemejando a una tabla, o podríamos crear un array tridimensional, agregando una dimensión
más de “fondo”, que haría que localizáramos a un elemento en su index [i, j, k], en plano
cartesiano como xyz. Además, existe una tercera clasificación conocida como jagged arrays o
matrices dentadas como se ve en la siguiente imagen, donde vemos un arreglo de tipo
bidimensional, pero con la diferencia de que una de sus dimensiones no es rectangular, sino que
puede tener distintos tamaños formando así una matriz dentada.
Puedo decir que este es un resumen sobre los Arrays, uno que sin duda nos ayudará a identificar
de forma más rápida el tipo de “array” que necesitamos usar.
Como se observa en la imagen, tenemos una secuencia de valores enlazados por pointers
llamados nodos, que están representados por un cuadro vacío y una flecha. El cuadro vacío
representa el valor con la dirección de memoria a donde está apuntando el valor que contiene,
de modo que: el valor 12 está enlazado por medio de un pointer que guarda la ubicación del
siguiente valor en la secuencia que es el 19 y este a su vez guarda la ubicación al valor 37.
Cuando hablemos de estructuras enlazadas debemos siempre pensar en que además de
almacenar el valor que deseamos, debemos tener un espacio extra donde debemos almacenar la
dirección de memoria del siguiente valor.
Después de una breve introducción a los pointers podemos pasar a la estructura más común de
las estructuras enlazadas que son las linked lists o listas enlazadas.
Ejemplos
Declarar y crear un array, para declarar un array se escribe
tipo_de_dato[] nombre_del_array;
Para declarar un array de enteros escribimos
int[] numeros;
Para crear un array de 4 número enteros escribimos
numeros=new int[4];
La declaración y la creación del array se puede
hacer en una misma línea.
int[] numeros =new int[4];
Inicializar y usar los elementos del array, para inicializar el array de 4 enteros escribimos
numeros[0]=2;
numeros[1]=-4;
numeros[2]=15;
numeros[3]=-25;
Y podríamos representar a una lista enlazada que almacena int’s por medio del siguiente
diagrama:
La lista también tendrá un atributo largo, del tipo long (o int, si se quiere), que representará la
cantidad de elementos en ella.
Implementación
Para implementar una lista simple enlazada, se define una clase Nodo, la cual indica el tipo de
los objetos guardados en los nodos de la lista. Para este caso se asume que los elementos son
String (puede ser cualquier tipo). También es posible definir nodos que puedan guardar tipos
arbitrarios de elementos.
Dada la clase Nodo, se puede definir una clase, ListaSimple, definiendo la lista enlazada actual.
Esta clase guarda una referencia al nodo cabeza y una variable va contando el número total de
nodos.
/** Nodo de una lista simple enlazada de cadenas. */
public class Nodo {
private String elemento; // Los elementos son cadenas de caracteres
private Nodo sig;
Método añadir ()
Para añadir un nodo a la lista, primero creamos un nodo, al que llamaremos nuevoNodo, que
contenga al Cliente entregados por el argumento, al que llamaremos nuevoCliente.
Luego conectamos a nuevoNodo con el último nodo de la lista. Para referirnos a éste, creamos
un puntero, al que llamaremos puntero, al primer nodo y avanzamos hasta el último por medio
de la instrucción puntero = puntero.siguiente como fue explicado anteriormente.
Ahora que puntero apunta al último nodo de la lista, y, además, ahora puntero.siguiente tiene
un valor igual a null, haremos que puntero.siguiente tome el valor nuevoNodo, es decir,
puntero.siguiente = nuevoNodo.
Gráficamente:
Método buscar ()
Para encontrar un Cliente en la lista, debemos buscarlo por medio de su atributo único: elRUT.
Es decir, crearemos un puntero con el que recorreremos la lista, comparando el RUT
especificado con el RUT de cada Client, hasta encontrar una coincidencia. Para esto, tendremos
que usar una instrucción como ésta:
Gráficamente
Método remover ()
Para eliminar un nodo de la lista, primero debemos ubicar el nodo anterior éste, es decir,
puntero.siguiente será el nodo a eliminar. Ahora, simplemente dejamos sin puntero al nodo
diciendo: puntero.siguiente = puntero.siguiente.siguiente, para que el Recolector de Basura de
Java lo recoja y sea eliminado.
Gráficamente:
Pilas y colas
Contenedores
Las estructuras de tipo contenedor se caracterizan principalmente por la forma particular de
recuperación ordenada de datos que soportan, y en los dos tipos principales de contenedores
(stack y queue) el orden de recuperación depende del orden de inserción.
Stack
Un stack o pila, soporta la
recuperación ordenada de datos
last-in, first-out (LIFO) o bien: el
último dato en entrar, el primer
dato en salir. De la misma forma en
que se hace en una pila de platos
limpios, si necesitamos un plato
limpio vamos a la pila y tomamos
el primero de la pila, que en
realidad fue el último plato que
agregamos a ella. Las pilas son
estructuras que encontramos de
muchas formas en el mundo real,
siempre que podamos apilar algún
objeto como libros, cazuelas,
películas o la forma en la que
metemos latas de refresco en el
refrigerador.
Tomando en cuenta lo anterior podemos pensar que si usamos un stack es porque
probablemente el orden de la recuperación de datos no nos importa tanto, simplemente
queremos apilarlos y desapiolarlos, por lo que las operaciones fundamentales en un stack son
push y pop para poner y obtener datos de la pila.
Con push() insertamos un elemento en el tope de la pila, y con pop() retornamos y removemos
el elemento en el tope de la pila, como se ve en la imagen.
Queue
Una queue o cola, soporta la recuperación ordenada de datos first-in, first-out (FIFO) o bien: el
primer dato en entrar, es el primer dato en salir. Justo como una cola en el banco cuando vamos
a realizar alguna operación con nuestra
cuenta bancaria, si todos los asistentes
están ocupados se genera una cola
donde el primero que llegó será el
primero en ser atendido y el resto
esperamos en la cola. Este tipo de
estructuras se utiliza mucho en el
control de tiempos de espera de servicios, tiempos de ejecución en un CPU, de conexión de red,
o en el mundo real en una cola para las tortillas, para entrar en una avenida rápida, etc.
En este tipo de estructura el orden sí importa, pues siempre el primero de la cola debe ser el
primero en ser atendido y el resto de forma ordenada esperan su turno. Las operaciones de esta
estructura son: enqueue y dequeue para encolar y desencolar (poner y obtener de la cola).
De modo que enqueue() inserta un elemento al final de la cola, y dequeue() retorna y remueve
el primer elemento de la cola.
Árboles y grafos
En este contexto árboles y grafos se refiere a estructuras de datos que permiten organizar y
mantener información en un
computador. Esta forma se inspira
una forma de organizar información
con lápiz y papel usando nodos y
flechas entre los nodos (a esas flechas
también se les llama arcos, a los
nodos también se les llama vértices).
Los grafos y árboles en papel son
apropiados por ejemplo para capturar
sólo una parte de la información de
objetos, situaciones y otros tipos de
información. En un computador
además de permitir organizar
información, resultan estructuras útiles para resolver ciertos tipos de problema (por ejemplo,
pueden emplearse árboles AVL para mantener información ordenada de forma eficiente).
ARBOLES
El árbol es una estructura de datos fundamental en la informática, muy utilizada en todos sus
campos, porque se adapta a la representación natural de informaciones homogéneas
organizadas y de una gran comodidad y
rapidez de manipulación.
Otra definición de árbol es como tipo de
grafo cíclico, conexo y no dirigido.
Las estructuras tipo árbol se usan
principalmente para representar datos
con una relación jerárquica entre sus
elementos, como son árboles
genealógicos, tablas, etc.
La definición de un árbol implica una
estructura recursiva. Esto es, la definición del árbol se refiere a otros árboles. Un árbol con
ningún nodo es un árbol nulo; no tiene raíz.
Una estructura vacía o un elemento o clave de información (nodo) más un numero finito de
estructuras tipo árbol, disjuntos, llamados subárboles. Si dicho número de estructuras es inferior
o igual a dos, se tiene un árbol binario.
Es, por tanto, una estructura no secuencial.
Terminología y representación de un árbol en general
La representación y terminología de los árboles se realiza con las típicas notaciones de las
relaciones familiares en los árboles genealógicos: padre, hijo, hermano, ascendente,
descendiente, etc.
• RAIZ: Todos los árboles que no están vacíos tienen un único nodo raíz. Todos los
demás elementos o nodos derivan o descienden de él. El nodo Raíz no tiene Padre es
decir no es hijo de ningún elemento
• PADRE: X es padre de Y sí y solo sí el nodo X apunta a Y. También se dice que X es
antecesor de Y.
• HIJO: X es hijo de Y, sí y solo sí el nodo X es apuntado por Y. También se dice que X
es descendiente directo de Y.
• HERMANO: Dos nodos serán hermanos si son descendientes directos de un mismo
nodo.
• HOJA. Se le llama hoja o Terminal a aquellos nodos que no tienen ramificaciones
(hijos).
• NODO. Son los Vértices o elementos del Árbol.
• NODO INTERIOR. Es un nodo que no es raíz ni Terminal.
• GRADO. Es el número de descendientes directos de un determinado nodo.
• GRADO DEL ARBOL Es el máximo grado de todos los nodos del árbol.
• NIVEL. Es el número de arcos que deben ser recorridos para llegar a un determinado
nodo. Por definición la raíz tiene nivel 1.
• ALTURA. Es el máximo número de niveles de todos los nodos del árbol. Equivale al
nivel más alto de los nodos más 1.
• PESO. Es el número de nodos terminales del árbol
• LONGITUD DE CAMINO. Es el número de arcos que deben ser recorridos para llegar
desde la raíz al nodo X. Por definición la raíz tiene longitud de camino 1, y sus
descendientes directos longitud de camino 2 y así sucesivamente.
También se podría decir que un árbol
binario se define como un conjunto finito
de elementos llamados nodos. En estos
casos se puede usar terminología de
relaciones familiares para descubrir las
relaciones entre los nodos de un árbol; y
que un árbol puede ser implementado
fácilmente en una computadora.
Es bueno hacer énfasis en esto ya que se
puede saber mucho sobre lo que tiene que
ver con los árboles; entre las cosas que
podemos mencionar se encuentra la raíz, los nodos de un árbol y la diferencia entre nodos
sucesores y nodos terminales, como se muestran en el contenido del trabajo.
Tipos de árboles
• Árbol binario
En ciencias de la computación, un árbol binario es una estructura de datos en la cual cada
nodo siempre tiene un hijo izquierdo y un hijo derecho. No pueden tener más de dos hijos
(de ahí el nombre "binario"). Si algún hijo tiene como referencia a null, es decir que no
almacena ningún dato, entonces este es llamado un nodo externo. En el caso contrario el hijo
es llamado un nodo interno. Usos comunes de los árboles binarios son los árboles binarios
de búsqueda, los montículos binarios y Codificación de Huffman.
Tipos de árboles binarios
• Un árbol binario es un árbol con raíz en el que cada nodo tiene como máximo dos hijos.
• Un árbol binario lleno es un árbol en el que cada nodo tiene cero o dos hijos.
• Un árbol binario perfecto es un árbol binario lleno en el que todas las hojas (vértices
con cero hijos) están a la misma profundidad (distancia desde la raíz, también llamada
altura).
A veces un árbol binario perfecto es denominado árbol binario completo. Otros definen un
árbol binario completo como un árbol binario lleno en el que todas las hojas están a
profundidad n o n-1, para alguna n.
Un árbol binario es un árbol en el que ningún nodo puede tener más de dos subárboles. En
un árbol binario cada nodo puede tener cero, uno o dos hijos (subárboles). Se conoce el
nodo de la izquierda como hijo izquierdo y el nodo de la derecha como hijo derecho.
• Árbol binario de búsqueda autobalanceable
En ciencias de la computación, un árbol binario de búsqueda autobalanceable o equilibrado
es un árbol binario de búsqueda que intenta mantener su altura, o el número de niveles de
nodos bajo la raíz, tan pequeños como sea posible
en todo momento, automáticamente. Esto es
importante, ya que muchas operaciones en un
árbol de búsqueda binaria tardan un tiempo
proporcional a la altura del árbol, y los árboles
binarios de búsqueda ordinarios pueden tomar
alturas muy grandes en situaciones normales,
como cuando las claves son insertadas en orden. Mantener baja la altura se consigue
habitualmente realizando transformaciones en el árbol, como la rotación de árboles, en
momentos clave.
Tiempos para varias operaciones en términos del número de nodos en el árbol n:
• Operación Tiempo en cota superior asintótica
• Búsqueda O(log n)
• Inserción O(log n)
• Eliminación O(log n)
• Iteración en orden O(n)
Para algunas implementaciones estos tiempos son el
peor caso, mientras que para otras están amortizados.
Estructuras de datos populares que implementan este
tipo de árbol:
• Árbol AVL
• Árbol rojo-negro
• -Árbol-B
En las ciencias de la computación, los árboles-B ó B-árboles son estructuras de datos de árbol
que se encuentran comúnmente en las implementaciones de bases de datos y sistemas de
archivos. Los árboles B mantienen los datos ordenados y las inserciones y eliminaciones se
realizan en tiempo logarítmico amortizado.
Árbol es un árbol de búsqueda
Árbol es un árbol de búsqueda que puede estar vacío o aquel cuyos nodos pueden tener varios
hijos, existiendo una relación de orden entre ellos, tal como muestra el dibujo.
Un árbol-B de orden M (el máximo número de hijos que puede tener cada nodo) es un árbol
que satisface las siguientes propiedades:
1. Cada nodo tiene como máximo M hijos.
2. Cada nodo (excepto raíz y hojas) tiene como mínimo M/2 hijos.
3. La raíz tiene al menos 2 hijos si no es un nodo hoja.
4. Todos los nodos hoja aparecen al mismo nivel.
5. Un nodo no hoja con k hijos contiene k-1 elementos almacenados.
6. Los hijos que cuelgan de la raíz (r1, ···, rm) tienen que cumplir ciertas condiciones:
• El primero tiene valor menor que r1.
• El segundo tiene valor mayor que r1 y menor que r2, etc.
• El último hijo tiene valor mayor que rm.
• Árbol multicamino
Los árboles multicamino o árboles multirrama son estructuras de datos de tipo árbol usadas en
computación.
Un árbol multicamino posee un grado g mayor a dos, donde cada nodo de información del árbol
tiene un máximo de g hijos.
GRAFOS
Un grafo en el ámbito de las ciencias de la computación es una estructura de datos, en concreto
un tipo abstracto de datos (TAD), que consiste en un conjunto de nodo (también llamados
vértices) y un conjunto de arcos
(aristas) que establecen relaciones
entre los nodos. El concepto de grafo
TAD desciende directamente del
concepto matemático de grafo.
Informalmente se define como G =
(V, E), siendo los elementos de V los
vértices, y los elementos de E, las
aristas (edges en inglés).
Formalmente, un grafo, G, se define
como un par ordenado, G = (V, E),
donde V es un conjunto finito y E es
un conjunto que consta de dos
elementos de V.
De aquí se podría deducir que un
grafo es básicamente un objeto
geométrico, aunque en realidad sea
un objeto combinatorio, es decir, un
conjunto de puntos y un conjunto de líneas tomado de entre el conjunto de líneas que une cada
par de vértices. Por otro lado, y debido a su generalidad y a la gran diversidad
de formas que pueden usarse, resulta complejo tratar con todas las ideas
relacionadas con un grafo.
Para facilitar el estudio de este tipo de dato, a continuación, se
realizará un estudio de la teoría de grafos desde el
punto de vista de las ciencias de la computación.
Considerando que dicha teoría es compleja y amplia,
aquí sólo se realizará una introducción a la misma,
describiéndose el grafo como un tipo de dato y
mostrándose los problemas típicos y los algoritmos que
permiten solucionarlos usando un ordenador.
Los grafos son estructuras de datos no lineales que tienen una
naturaleza generalmente dinámica. Su estudio podría dividirse en
dos grandes bloques:
Grafos Dirigidos.
Grafos no Dirigidos (pueden
ser considerados un caso
particular de los anteriores).
Un ejemplo de grafo dirigido
lo constituye la red de aguas
de una ciudad ya que cada
tubería sólo admite que el
agua la recorra en un único
sentido. Por el contrario, la
red de carreteras de un país
representa en general un
grafo no dirigido, puesto que
una misma carretera puede
ser recorrida en ambos sentidos.
Algunos de los principales tipos de grafos son los que se muestran a continuación:
• Grafo regular: Aquel con el mismo grado en todos los vértices. Si ese grado es k lo
llamaremos k-regular.
• Grafo bipartito: Es aquel con cuyos vértices pueden formarse dos conjuntos disjuntos
de modo que no haya adyacencias entre vértices pertenecientes al mismo conjunto.
• Grafo completo: Aquel con una arista entre cada par de vértices. Un grafo completo con
n vértices se denota Kn.
• Un grafo bipartito regular: se denota Km,n donde m, n es el grado de cada conjunto
disjunto de vértices.
• Grafo nulo: Se dice que un grafo es nulo cuando los vértices que lo componen no están
conectados, esto es, que son vértices aislados.
• Grafos Isomorfos: Dos grafos son isomorfos cuando existe una correspondencia
biunívoca (uno a uno), entre sus vértices de tal forma que dos de estos quedan unidos
por una arista en común.
• Grafos Platónicos: Son los Grafos formados por los vértices y aristas de los cinco sólidos
regulares (Sólidos Platónicos), a saber, el tetraedro, el cubo, el octaedro, el dodecaedro
y el icosaedro.
Grafos Eulerianos.
Para definir un camino euleriano es importante definir un camino
euleriano primero. Un camino euleriano se define de la manera
más sencilla como un camino que contiene todos los arcos del
grafo. Teniendo esto definido podemos hablar de los grafos
eulerianos describiéndolos simplemente como aquel grafo que
contiene un camino euleriano.
Grafos Conexos.
Un grafo se puede definir como conexo si cualquier vértice V
pertenece al conjunto de vértices y es alcanzable por algún otro.
Otra definición que dejaría esto más claro sería: "un grafo conexo
es un grafo no dirigido de modo que para cualquier par de nodos
existe al menos un camino que los une".
Recorrido de un grafo.
Recorrer un grafo significa tratar de alcanzar todos los nodos que
estén relacionados con uno que llamaremos nodo de salida. Existen
básicamente dos técnicas para recorrer un grafo: el recorrido en
anchura; y el recorrido en profundidad.
• Recorrido en anchura: El recorrido en anchura supone
recorrer el grafo, a partir de un nodo dado, en niveles, es
decir, primero los que están a una distancia de un arco del
nodo de salida, después los que están a dos arcos de distancia,
y así sucesivamente hasta alcanzar todos los nodos a los que
se pudiese llegar desde el nodo salida.
• Recorrido en profundidad: el recorrido en profundidad trata
de buscar los caminos que parten desde el nodo de salida
hasta que ya no es posible avanzar más. Cuando ya no puede
avanzarse más sobre el camino elegido, se vuelve atrás en
busca de caminos alternativos, que no se estudiaron
previamente.
Representación de grafos en programas.
Hay tres maneras de representar un grafo en un programa: mediante matrices, mediante listas y
mediante matrices dispersas.
• Representación mediante matrices: La forma más fácil de guardar la información de los
nodos es mediante la utilización de un vector que indexe los nodos, de manera que los
arcos entre los nodos se pueden ver como relaciones entre los índices. Esta relación
entre índices se puede guardar en una matriz, que llamaremos de adyacencia.
• Representación mediante listas: En las listas de adyacencia lo que haremos será guardar
por cada nodo, además de la información que pueda contener el propio nodo, una lista
dinámica con los nodos a los que se puede acceder desde él. La información de los nodos
se puede guardar en un vector, al igual que antes, o en otra lista dinámica.
• Representación mediante matrices dispersas: Para evitar uno de los problemas que
teníamos con las listas de adyacencia, que era la dificultad de obtener las relaciones
inversas, podemos utilizar las matrices dispersas, que contienen tanta información como
las matrices de adyacencia, pero, en principio, no ocupan tanta memoria como las
matrices, ya que al igual que en las listas de adyacencia, sólo representaremos aquellos
enlaces que existen en el grafo.
Dígrafo (grafo dirigido).
A un grafo dirigido se le puede definir como un grafo que contiene
aristas dirigidas, como en el siguiente caso.
Aplicaciones de los dígrafos
Una de las aplicaciones más importantes es de hallar el camino más
corto hacia un destino, ya sea de una ciudad a otra, de unos
departamentos a otros, para el recorrido de árboles, sirve para la
representación de algoritmos, etc. Un ejemplo de esto es la tarea de freír
un huevo.
Grado de un grafo.
• Grado de incidencia positivo: El grado de incidencia positivo de
un nodonjes el número de arcos que tienen como nodo inicial
anj. Ejemplo: El grado de incidencia de 1 es igual a 3.
• Grado de incidencia negativo: El grado de incidencia negativo
de un nodonjes el número de arcos que terminan ennj. Ejemplo:
El grado de incidencia negativo de 1 es igual a 1.
• Grado de un nodo: Paradigrafoses el grado de incidencia
positivo menos el grado de incidencia negativo del nodo.
Ejemplo: El grado de 1 es igual a 3 –1 = 2, el grado del nodo 4
es 2 –2 = 0. Para grafos no dirigidos es el número de líneas
asociadas al nodo.
Ciclo de un grafo.
Ciclo: Es una cadena finita donde el nodo inicial de la cadena coincide con el nodo terminal de
la misma.
• Ciclo simple: Es el ciclo que a su vez es una cadena simple.
Estructuras no lineales: Grafos
Las estructuras de datos no lineales se caracterizan por no existir una relación de adyacencia,
entre sus elementos, es decir, un elemento puede estar relacionado con cero, uno o más
elementos.
La estructura no lineal de datos más general es el grafo donde sus nodos pueden relacionarse
de cualquier manera sin una relación de orden predefinida.
Estructuras no lineales: Grafos Entre las múltiples aplicaciones que tienen estas estructuras
podemos mencionar:
• Para modelar diversas situaciones tales como: sistemas de aeropuertos, flujo de tráfico,
y responder a preguntas como: ¿Qué tiempo es más corto?, ¿Cómo es más barato?, o
¿Qué camino es más corto?
• Los grafos también son utilizados para realizar planificación de actividades, tareas del
computador, planificar operaciones en lenguaje de máquinas para minimizar tiempo de
ejecución. ¿Qué tarea debo hacer primero?
• Para representar circuitos eléctricos, de aguas etc. y preguntar, están todas las
componentes conectadas.
CLASIFICACIÓN DE LA ESTRUCTURA DE DATOS
Introducción
Estructura de datos, pueden
organizarse en muchas formas
diferentes; el modelo matemático o
lógico de una organización
particular de datos recibe el nombre
de estructura de datos.
La elección de un modelo de datos
depende de dos cuestiones. Primero,
debe ser lo suficientemente
complejo para mostrarnos la
relación entre los datos y lo que
representan. Por el contrario, la
estructura debe ser lo suficiente
mente simple para que los datos
puedan ser procesados de forma
eficiente cuando sean necesario.
Clasificación de los datos simples
Todas las variables que se han considerado hasta el momento son de tipo simple. Una variable
de tipo simple consiste de una sola caja de memoria y sólo puede contener un valor cada vez.
Una variable de tipo estructurado consiste en toda una colección de casillas de memoria.
Los tipos de datos estudiados: entero, real, alfabético son considerados como datos de tipo
simple, puesto que una variable que se define con alguno de estos tipos sólo puede almacenar
un valor a la vez, es decir existe una relación de uno a uno entre la variable y el número de
elementos (valores) que es capaz de almacenar.
En cambio, un dato de tipo estructurado, como el arreglo, puede almacenar más de un elemento
(valor) a la vez, con la condición de que todos los elementos deben ser del mismo tipo, es decir,
que se puede tener un conjunto de datos enteros, reales, etc.
• Datos Numéricos: Permiten representar
valores escalares de forma numérica, esto
incluye a los números enteros y reales.
Estos tipos de datos permiten realizar
operaciones aritméticas comunes.
• Datos Lógicos: Son aquellos que solo
pueden tener dos valores (cierto o falso)
ya que representan el resultado de una
comparación entre otros datos
(numéricos o alfanuméricos).
Datos Alfanuméricos (String): Son una secuencia de caracteres alfanuméricos que permiten
representar valores identificables de forma descriptiva, esto incluye nombres de personas,
direcciones, etc. Es posible representar números como alfanuméricos, pero estos pierden su
propiedad matemática, es decir no es posible hacer operaciones con ellos. Este tipo de datos se
representan encerrados entre comillas.
• DEFINICION DE EXPRESIÓN: Las
expresiones son combinaciones de constantes,
variables, símbolos de operación, paréntesis y
nombres de funciones especiales.
• DEFINICION DE OPERADOR Y SUS TIPOS:
Operadores: Son elementos que relacionan de forma diferente, los valores de una o más
variables y/o constantes. Los operadores permiten manipular valores.
DEFINICIÓN DE CONSTANTE
Una constante es un dato numérico o alfanumérico que no cambia durante la ejecución del
programa.
DATOS ESTRUCTURADOS
Estructura de Datos es una colección de datos que se caracteriza por su organización y las
operaciones que se definen en ella. Los datos de tipo estándar pueden ser organizados en
diferentes estructuras de datos: estáticas y dinámicas.
Definición de operadores y sus tipos
• Relaciónales: Compara estos valores entre sí y esta
comparación produce un resultado de certeza o falsedad
(verdadero o falso).
• Lógicos: Operadores que se utiliza para establecer relaciones
entre valores lógicos.
Los operadores relaciónales comparan valores del mismo tipo
(numéricos o cadenas).
Operadores
Los operadores son símbolos que indican cómo se deben
manipular los operandos. Los operadores junto con los
operandos forman una expresión, que es una fórmula que
define el cálculo de un valor. Los operandos pueden ser
constantes, variables o llamadas a funciones, siempre que
éstas devuelvan algún valor. El compilador evalúa los
operadores, algunos de izquierda a derecha, otros de
derecha a izquierda, siguiendo un orden de precedencia.
Este orden se puede alterar utilizando paréntesis para forzar
al compilador a evaluar primero las partes que se deseen.
Operadores Aritméticos
OPERADOR PROPÓSITO
+ adición
- sustracción
* multiplicación
/ división
% resto de división entera
Otros dos operadores monarios interesantes son:
++ Que es el operador incremento, hace que su operando se incremente en uno.
-- Que es el operador decremento, hace que el operando se decremente en uno.
Operadores Lógicos y Relacionales:
OPERADOR PROPÓSITO
> mayor que
>= mayor o igual que
< menor que
<= menor o igual que
== igual
!= distinto
&& AND lógico
|| OR lógico
! NOT lógico
Operadores de asignación
Se utiliza el operador =, dentro de una asignación, para asignar valores a una variable. Tiene el
siguiente formato:
Operadores de Punteros
En temas posteriores entraremos más a fondo sobre ellos, ya que son una parte imprescindible
del lenguaje. De ellos sólo diremos que los operadores unitarios * y & se utilizan con punteros.
Cuando se evalúa el operador unitario &, se obtiene la dirección del operando. El operador *,
al evaluarse, devuelve el valor de la variable a la que apunta el operando; por lo tanto, el
operando debe ser un puntero.
Definición y clasificación de Variables.
Una variable estudia características de la población, objetos e instituciones, estas características
pueden ser sometidas a cambios y clasificarse en
diversos criterios.
Clasificaciones de las variables
• Cualitativas
• Cuantitativas
• Clasificaciones de las variables
• Clasificaciones de las variables
• Grafica de cómo se clasifican las variables
De acuerdo a su comportamiento en una investigación:
Clasificaciones de las variables
• Cualitativas
• Cuantitativas
Cualitativas
Se determinan por las cualidades o
atributos, verbigracia, colores (azul, verde,
naranja, rojo, amarillo, marrón, etc.),
tamaños (grandes, pequeños, altos, bajos).
Estas cualidades pueden distinguir a una
persona o cosa, las características podrán
distinguirse uno de otro, por lo que no
pueden ser medidas por cifras. Por lo
tanto, su modalidad no es numérica,
verbigracia, no pueden ser usadas en el
campo de las finanzas o en la economía.
Sin embargo, a estas cualidades se le
pueden atribuir números, o letras para
diferenciarlos o categorizarlos, como
prototipo tenemos, al sexo masculino el
número 1 y al femenino el número 2, de tal manera poder hacer algún análisis matemático.
Ejemplo:
• Sensibilidad de una persona.
• Color de piel
• Color de cabello
• Oficio u profesión de una persona.
• Carácter de una persona.
Las cualitativas se determinan por ser:
Nominales
No corresponden a ningún orden. Estas no son numéricas, ejemplo; amarillo, dorado, negro,
fucsia, además de, casado o soltero.
Ordinales: En están tampoco son representadas por números sin por orden. Por ejemplo, las
calificaciones de un examen si es aprobado o reprobado, sobresaliente, o no. Sonidos, débiles
o fuertes.
Cuantitativas
Son de carácter numérico, cifras finitas, como las fórmulas o algoritmos, además, son:
Discretas: Manejan los valores precisos, enteros; no obstante, para que así lo sea deben ser
valores infinitos. Ahora bien, estas variables son usadas comúnmente en experimentos.
Ejemplo:
• Edad
• Centímetros
• Talla
• Peso
• Número de quejas en una sala de
espera
• Numero de perritos en una cesta
• Cantidad de pollitos
Sería imposible decir que tiene 2,3 vasos, o 5,6 hijos, numero de hermanos 3,7, número de
personas en un aéreo puerto, 15076,9, o cantidad de alumnos en un aula, 20,6, por ejemplo.
Continuas
Cualquier valor real dentro de un intervalo. Su función es continua. En este caso si es posible
usar un valor medio como los decimales.
Ejemplo
• María mide 1.55 cm de alto.
• La velocidad de un motociclista.
• Las temperaturas.
• La hora
• Fecha de entrada o de salida.
Las medidas no son exactas, por lo que en las variables continuas se puede dar uso a los
decimales.
Una variable es una propiedad característica de la población en estudio, susceptible de tomar
diferentes valores, los cuales se pueden observar y medir.
Nominales: Son datos que corresponden a categorías que por su naturaleza no admiten un
orden. Por ejemplo: sexo
(masculino y femenino);
carrera de estudio:
economía, contabilidad,
administración, etc.
Ordinales: Son aquellos que
corresponden a
evaluaciones subjetivas que
se pueden ordenar o
jerarquizar. Por ejemplo: en
una competencia artística las posiciones de los ganadores se ordenan o
jerarquizan en primer lugar, segundo lugar, tercer lugar, cuarto lugar, etc.
Variables cuantitativas: son aquellas que tienen valor numérico como la edad, el precio de un
producto, ingresos anuales de un consumidor, etc.
Clasificación de la estructura de datos.
Una estructura de datos es una clase de datos
que se puede caracterizar por su organización
y operaciones definidas sobre ella. Algunas
veces a estas estructuras se les llama tipos de
datos.
En ellas encontramos las siguientes:
Estructuras lógicas de datos:
En un programa, cada variable pertenece a
alguna estructura de datos explícita o
implícitamente definida, la cual determina el
conjunto de operaciones válidas para ella. Las
estructuras de datos que se discuten aquí son
estructuras de datos lógicas. Cada estructura
de datos lógica puede tener varias
representaciones físicas diferentes para sus
almacenamientos
Estructuras primitivas y simples:
Son primitivas aquellas que no están compuestas por otras estructuras de datos, por ejemplo,
enteros, booleanos y caracteres. Otras estructuras de datos se pueden construir de una o más
primitivas. Las estructuras de datos simples que consideramos se construyen a partir de
estructuras primitivas y son: cadenas, arreglos y registros. A estas estructuras de datos las
respaldan muchos lenguajes de programación.
Actualización
Dentro de esta operación se encuentran las operaciones de eliminar, insertar y modificar datos.
Para realizar este tipo de operaciones se debe tomar en cuenta si el arreglo está o no ordenado.
Para arreglos ordenados los algoritmos de inserción, borrado y modificación son los siguientes:
1.- Insertar.
Si i< mensaje (arreglo contrario caso En arreglo[i]<--valor i<--i+1 entonces>
2.- Borrar.
Si N>=1 entonces
inicio
i<--1
encontrado<--falso
mientras i<=n y encontrado=falso
inicio
si arreglo[i]=valor_a_borrar entonces
inicio
encontrado<--verdadero
N<--N-1
para k desde i hasta N haz
arreglo[k]<--arreglo[k-1]
fin
en caso contrario
i<--i+1
fin
fin
Si encontrado=falso entonces
mensaje (valor no encontrado)
3.- Modificar.
Si N>=1 entonces
inicio
i<--1
encontrado<--falso
mientras i<=N y encontrado=false haz
inicio
Si arreglo[i]=valor entonces
arreglo[i]<--valor_nuevo
encontrado<--verdadero
En caso contrario
i<--i+1
fin
fin
Ordenaciones en arreglos
La importancia de mantener nuestros arreglos ordenados radica en que es mucho más rápido
tener acceso a un dato en un arreglo ordenado que en uno desordenado.
Existen muchos algoritmos para la ordenación de elementos en arreglos, enseguida veremos
algunos de ellos.
a) Selección Directa
Este método consiste en seleccionar el elemento más pequeño de nuestra lista para
colocarlo al inicio y así excluirlo de la lista.
Para ahorrar espacio, siempre que vayamos a colocar un elemento en su posición
correcta lo intercambiaremos por aquel que la esté ocupando en ese momento.
El algoritmo de selección directa es el siguiente:
i <- 1
mientras i<= N haz
min <-i
j <- i + 1
mientras j <= N haz
si arreglo[j] < [min] entonces
min <-j
j <- j + 1
intercambia(arreglo[min],arreglo[i])
i <- i +1
b) Ordenación por Burbuja
Es el método de ordenación más utilizado por su fácil comprensión y programación,
pero es importante señalar que es el más ineficiente de todos los métodos.
Este método consiste en llevar los elementos menores a la izquierda del arreglo ó los
mayores a la derecha del mismo. La idea básica del algoritmo es comparar pares de
elementos adyacentes e intercambiarlos entre sí hasta que todos se encuentren
ordenados.
i <- 1
mientras i < N haz
j <- N
mientras j > i haz
si arreglo[j] < arreglo[j-1] entonces
intercambia(arreglo[j],arreglo[j-1])
j<j-1
i <- i +1
c) Ordenación por Mezcla
Este algoritmo consiste en partir el arreglo por la mitad, ordenar la mitad izquierda,
ordenar la mitad derecha y mezclar las dos mitades ordenadas en un array ordenado.
Este último paso consiste en ir comparando pares sucesivos de elementos (uno de cada
mitad) y poniendo el valor más pequeño en el siguiente hueco.
Procedimiento mezclar(dat,izqp,izqu,derp,deru)
inicio
izqa <- izqp
dera <- derp
ind <- izqp
mientras (izqa <= izqu) y (dera <= deru) haz
si arreglo[izqa] < dat[dera] entonces
temporal[ind] <- arreglo[izqa]
izqa <- izqa + 1
en caso contrario
temporal[ind] <- arreglo[dera]
dera <- dera + 1
ind <- ind +1
mientras izqa <= izqu haz
temporal[ind] <- arreglo[izqa]
izqa <- izqa + 1
ind <- ind +1
mientras dera <= deru haz
temporal[ind] <=dat[dera]
dera <- dera + 1
ind <- ind + 1
para ind <- izqp hasta deru haz
arreglo[ind] <- temporal[ind]
fin
Búsquedas en arreglos
Una búsqueda es el proceso mediante el cual podemos localizar un elemento con un valor
específico dentro de un conjunto de datos. Terminamos con éxito la búsqueda cuando el
elemento es encontrado.
A continuación, veremos algunos de los algoritmos de búsqueda que existen.
a) Búsqueda Secuencial
A este método también se le conoce como búsqueda lineal y consiste en empezar al
inicio del conjunto de elementos, e ir atreves de ellos hasta encontrar el elemento
indicado o hasta llegar al final de arreglo.
Este es el método de búsqueda más lento, pero si nuestro arreglo se encuentra
completamente desordenado es el único que nos podrá ayudar a encontrar el dato que
buscamos.
ind <- 1
encontrado <- falso
mientras no encontrado y ind < N haz
si arreglo[ind] = valor_buscado entonces
encontrado <- verdadero
en caso contrario
ind <- ind +1
b) Búsqueda Binaria
Las condiciones que debe cumplir el arreglo para poder usar búsqueda binaria son que
el arreglo este ordenado y que se conozca el número de elementos.
Este método consiste en lo siguiente: comparar el elemento buscado con el elemento
situado en la mitad del arreglo, si tenemos suerte y los dos valores coinciden, en ese
momento la búsqueda termina. Pero como existe un alto porcentaje de que esto no
ocurra, repetiremos los pasos anteriores en la mitad inferior del arreglo si el elemento
que buscamos resulto menor que el de la mitad del arreglo, o en la mitad superior si el
elemento buscado fue mayor.
La búsqueda termina cuando encontramos el elemento o cuando el tamaño del arreglo a
examinar sea cero.
encontrado <- falso
primero <- 1
ultimo <- N
mientras primero <= ultimo y no encontrado haz
mitad <- (primero + ultimo)/2
si arreglo[mitad] = valor_buscado entonces
encntrado <- verdadero
en caso contrario
si arreglo[mitad] > valor_buscado entonces
ultimo <- mitad - 1
en caso contrario
primero <- mitad + 1
c) Búsqueda por Hash
La idea principal de este método consiste en aplicar una función que traduce el valor del
elemento buscado en un rango de direcciones relativas. Una desventaja importante de
este método es que puede ocasionar colisiones.
funcion hash (valor_buscado)
inicio
hash <- valor_buscado mod numero_primo
fin
inicio <- hash (valor)
il <- inicio
encontrado <- falso
repite
si arreglo[il] = valor entonces
encontrado <- verdadero
en caso contrario
il <- (il +1) mod N
hasta encontrado o il = inicio
Declaración de un arreglo
Funcionamiento
La declaración de un arreglo bidimensional es similar al de un arreglo unidimensional, así:
SINTAXIS EJEMPLO
tipoDato [ ][ ] nombre_variable; int [ ][ ] registroNotas;
tipoDato nombre_variable [ ][ ]; int registroNotas [ ][ ];
De esta forma lo que se logra es disponer de una variable, en los ejemplos registro Notas, en el
que se podrá almacenar un conjunto de valores. Para establecer la cantidad máxima de valores
que puede contener la estructura creada es necesario realizar la reserva de memoria o
instanciación utilizando la palabra reservada new. Esto puede hacerse a continuación de la
declaración, o en dos instrucciones diferentes, así:
SINTAXIS EJEMPLO
tipoDato [ ][ ] nombreVariable = new int [ ][ ] registroNotas = new int [4][5];
tipoDato [nFilas][nCol];
tipoDato [ ][ ] nombreVariable; nombreVariable = new tipoDato
[nFilas][nCol];
int registroNotas [4][5]; registroNotas = new int [4][5];
Esto último puede aplicarse a cualquiera de las declaraciones revisadas. Donde:
• tipoDato puede ser cualquiera de tipos estándares de datos: int, double, String, entre
otros. Esto implica que todos los datos serán únicamente del tipo especificado en la
declaración.
• nombreVariable es el nombre que se asigna al arreglo, en este ejemplo: registroNotas.
• nFilas es el número máximo de filas que tendrá la matriz.
• nCol es el número máximo de columnas que tendrá la matriz.
Sin embargo y únicamente para fines didácticos en los ejercicios, utilizaremos otro tipo de
declaración, que es muy estática, pero válida para evitar el continuo ingreso datos.
SINTAXIS EJEMPLO
tipoDato [][] nombreVariable = {{v1, v2, int [][] RegistroNotas =
v3},{v4, v5, v6},{v7,v8,v9}}; {{6,8,10,2,9},{1,2,3,4,5},{6,7,8,9,10}};
De esta manera dispondremos de un arreglo bidimensional de
3 filas por 5 columnas con los valores asignados entre llaves.
3 3
3 3
3 3
3 3
sum(A,2) opera con los elementos sucesivos en las filas de A y devuelve un vector de columna
de las sumas de cada fila.
El subíndice de cada elemento designa su posición en la ordenación del vector. Se observa que
todos los elementos comparten el nombre y que cada elemento se referencia por su subíndice o
sea su posición relativa en el vector.
Declaración de un arreglo Unidimensional:
Estático:
Estático:
tipo nombre [filas, columnas]
Ej: entero A [3,3] declara un arreglo de datos tipo entero de 3 filas y tres columnas.
Almacenamiento de arreglos en memoria
Arreglos de Una y dos dimensiones se representan como se muestra:
La memoria de la computadora es unidimensional, por lo que el almacenamiento de los arreglos
de más de una dimensión requiere que la posición de los elementos del arreglo sea "linealizada".
La forma más común de almacenamiento de vectores de dos dimensiones es por filas, así un
vector A [3,4] se almacenaría de la manera siguiente:
1 2 3 4 5 6 7 8 9
La posición de un elemento A[i,j] del arreglo A[3,4] de dimensiones [m,n] con relación al
primer elemento es: Posición = n*(i -1) + j
Así la posición dentro del arreglo del elemento A [2,3] del ejemplo anterior sería:
m = 3, n = 4, i = 2, j = 3 Posición = 4 * (2 - 1) + 3 = 7
Operaciones sobre arreglos
Las operaciones que se pueden realizar con arreglos durante el proceso de resolución de un
problema son:
• Asignación
• Lectura / Escritura
• Recorrido
• Búsqueda
• Ordenamiento.
Asignación:
La asignación de valores a un elemento de un arreglo se representa con la instrucción:
A [10] = 3 / asigna el valor 3 al elemento 10 del vector A
Ventas [2,2] = 1500
Si se desea asignar valores a todos los elementos de un vector, se debe usar estructuras de
repetición.
• Caso Unidimensional: Asignar el valor 6 a todos los elementos de un vector A[5]
repetir_desde ( i = 1; i <= 5 ; i=i+1)
A[i] = 6
fin_repetir_desde
• Caso Bidimensional: Inicializar un vector B[2,3] con el valor cero.
repetir_desde ( i = 1; i <= 2 ; i=i+1)
repetir_desde ( j = 1; j <= 3 ; j=j+1)
B[i,j] = 0
fin_repetir_desde
fin_repetir_desde
Lectura / Escritura:
La lectura/escritura de datos en arreglos u operaciones de entrada/salida, normalmente se
realizan con estructuras repetitivas o selectivas. Las instrucciones simples de lectura/escritura
se representan como:
leer(Nombre_del_arreglo[Indice])
mostrar(Nombre_del_arreglo[Indice])
Ej : leer(X[3]) / Lee el elemento 3 del vector X
Recorrido:
A la operación de efectuar alguna acción sobre todos los elementos del vector se le llama
recorrido. Estas operaciones se realizan usando estructuras de repetición, cuyas variables de
control se usan como índices del vector. Se puede realizar esta operación para introducir datos
al vector (leer) o para ver su contenido (mostrar).
Ejemplo 1: Lectura de los 10 valores de un vector P.
Ejemplo 2: El siguiente algoritmo lee las notas del primer examen de Computación de una
sección de 40 alumnos, a fin de calcular el promedio.
Si se deseara mostrar la cantidad de alumnos con notas superiores al promedio se agregan las
siguientes líneas al algoritmo anterior:
Ejemplo 3: Leer una matriz de dos dimensiones A [5,4].
Dado que es una matriz de dos dimensiones, se necesitan dos bucles anidados para recorrer
todos sus elementos.
Análisis:
La estrategia a seguir consiste en asignar la condición deseada (MAYOR) al primer elemento
de la lista (A[1]) y se empieza a comparar con todos los elementos de la lista. Si alguno de los
elementos resulta mayor que el elemento al cual se le ha asignado la condición, se cambia la
condición al nuevo elemento. Al terminar de recorrer todo el vector, el valor que mantiene la
condición deseada es el mayor.
Los resultados sobre el ejemplo se podrían ver como sigue:
Método Burbuja
Argumentos que recibe: vector a ordenar y longitud del arreglo.
Métodos de ordenación por selección
El ordenamiento por selección (Selection Sort en inglés) es un algoritmo de ordenamiento que
requiere n2 operaciones para ordenar una lista de n elementos.
Su funcionamiento es el siguiente:
• Buscar el mínimo elemento de la lista.
• Intercambiarlo con el primero.
• Luego, buscar el mínimo en el resto de la lista.
• Intercambiarlo con el segundo y así sucesivamente.
En general:
• Buscar el mínimo elemento entre una posición i y el final de la lista
• Intercambiar el mínimo con el elemento de la posición i
Ventajas:
Este algoritmo mejora ligeramente el algoritmo de la burbuja. En el caso de tener que ordenar
un vector de enteros, esta mejora no es muy sustancial, pero cuando hay que ordenar un vector
de estructuras más complejas, la operación intercambiar () sería más costosa en este caso. Este
algoritmo realiza menos operaciones intercambiar () que el de la burbuja, por lo que lo mejora
en algo.
Desventajas:
• Realiza numerosas comparaciones.
• Este es un algoritmo lento. No obstante, ya que sólo realiza un intercambio en cada
ejecución del ciclo externo, puede ser una buena opción para listas con registros grandes
y claves pequeñas.
Método Selección
Argumentos que recibe: Vector a ordenar y longitud del arreglo.
Ejemplo:
El arreglo a ordenar es A = ['a','s','o','r','t','i','n','g','e','x','a','m','p','l','e'].
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'.
Esta se intercambia con el dato que está en la segunda posición, la 's', quedando el
arreglo así después de dos recorridos:
a = ['a','a','o','r','t','i','n','g','e','x','s','m','p','l','e'].
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', quedando el arreglo así
a = ['a','a','e','e','t','i','n','g','o','x','s','m','p','l','r'].
De esta manera se va buscando el elemento que debe ir en la siguiente posición hasta
ordenar todo el arreglo.
Método de Ordenamiento Shell
El ordenamiento Shell (Shell sort en inglés) es un algoritmo de ordenamiento.
Métodos de búsqueda.
Método de Búsqueda Secuencial:
La búsqueda secuencial, también se le conoce como
búsqueda lineal. 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 hayan visto todas las
casillas. El resultado de la búsqueda es un solo valor, y
será la posición del elemento buscado o cero.
Dado que el vector o arreglo no está en ningún orden en
particular, existe la misma probabilidad de que el valor se
encuentra ya sea en el primer elemento, como en el último.
Por lo tanto, en promedio, el programa tendrá que
comparar el valor buscado con la mitad de los elementos
del vector. El método de búsqueda lineal funciona bien con
arreglos pequeños o para arreglos no ordenados.
Ventajas:
Es un método sumamente simple que resulta útil cuando se tiene un conjunto de datos pequeños
(Hasta aproximadamente 500 elementos). Es fácil adaptar la búsqueda secuencial para que
utilice una lista enlazada ordenada, lo que hace la búsqueda más eficaz. Si los datos buscados
no están en orden es el único método que puede emplearse para hacer dichas búsquedas.
Desventajas:
• El método tiende hacer muy lento.
• Si los valores de la clave no son únicos, para encontrar todos los elementos con una
clave particular, se requiere buscar en todo el arreglo, lo que hace el proceso muy largo.
Método búsqueda Secuencial
Argumentos que recibe: Vector de búsqueda y longitud del arreglo.
Cuando hablamos de programación, la estructura de datos está representada por una forma
determinada que tenemos de organizar los datos de un equipo informático para que podamos
utilizarlos de la manera más efectiva posible. Dependiendo del tipo de aplicación o recurso que
vayamos a usar requeriremos una estructura de datos independiente y distinta a las demás, dado
que cada una encaja en el contexto de forma determinada y con una serie de objetivos.
Con estas estructuras tenemos la posibilidad de administrar todo tipo de datos sin ningún tipo
de obstáculo, algo que en la actualidad se usa en la red para poder llevar a cabo, por ejemplo,
los sistemas de indexado de contenidos. Y también juegan un papel clave en la creación de los
mejores algoritmos, así como en su uso con lenguajes de programación que se benefician de
ellas. Lo primero que debemos tener claro es la definición de “estructura de datos” y que a
partir de esta definición parten otros conceptos y tipos. Que las estructuras de datos se estudian
como conceptos sobre programación, y no sobre un lenguaje de programación en específico,
por lo que cada lenguaje puede tener diferentes implementaciones de estructuras de datos.
Una “estructura de datos” es una colección de valores, la relación que existe entre estos valores
y las operaciones que podemos hacer sobre ellos; en pocas palabras se refiere a cómo los datos
están organizados y cómo se pueden administrar. Una estructura de datos describe el formato
en que los valores van a ser almacenados, cómo van a ser accedidos y modificados, pudiendo
así existir una gran cantidad de estructuras de datos.
Los datos se representan en la memoria, las estructuras contiguamente asignadas están
compuestas de bloques de memoria únicos, e incluyen a los arrays, matrices, heaps, y hash
tables. las estructuras enlazadas están compuestas de distintos fragmentos de memoria unidos
por pointers o punteros, e incluyen a los lists, trees, y graphs y los contenedores son estructuras
que permiten almacenar y recuperar datos en un orden determinado sin importar su contenido,
en esta se incluyen los stacks y queues. Esta estructura es “la” fundamental de las estructuras
contiguamente asignadas. Arrays ó arreglos son estructuras de datos de tamaño fijo de modo
que cada elemento puede ser eficientemente ubicado por su index (índice) o dirección.
La magia de las estructuras enlazadas es dada por los pointers o punteros, que como su nombre
lo indica apuntan a una dirección de memoria donde se encuentra ubicado un valor
Una diferencia grande entre los Arrays vs linked lists es que insertar o eliminar de una linked
list es más fácil ya que no tiene tamaño fijo y lo único que debemos hacer para insertar o
eliminar un valor es simplemente apuntar al nuevo nodo creado, o apuntar al siguiente nodo de
la lista si un nodo fue eliminado. En un array no existe esta flexibilidad.
En este contexto árboles y grafos se refiere a estructuras de datos que permiten organizar y
mantener información en un computador. Esta forma se inspira una forma de organizar
información con lápiz y papel usando nodos y flechas entre los nodos (a esas flechas también
se les llama arcos, a los nodos también se les llama vértices). Los grafos y árboles en papel son
apropiados por ejemplo para capturar sólo una parte de la información de objetos, situaciones
y otros tipos de información.
El árbol es una estructura de datos fundamental en la informática, muy utilizada en todos sus
campos, porque se adapta a la representación natural de informaciones homogéneas
organizadas y de una gran comodidad y rapidez de manipulación.
En ciencias de la computación, un árbol binario es una estructura de datos en la cual cada nodo
siempre tiene un hijo izquierdo y un hijo derecho. No pueden tener más de dos hijos (de ahí el
nombre "binario"). Si algún hijo tiene como referencia a null, es decir que no almacena ningún
dato, entonces este es llamado un nodo externo. En el caso contrario el hijo es llamado un nodo
interno. Usos comunes de los árboles binarios son los árboles binarios de búsqueda, los
montículos binarios y Codificación de Huffman.
Un grafo en el ámbito de las ciencias de la computación es una estructura de datos, en concreto
un tipo abstracto de datos (TAD), que consiste en un conjunto de nodo (también llamados
vértices) y un conjunto de arcos (aristas) que establecen relaciones entre los nodos. El concepto
de grafo TAD desciende directamente del concepto matemático de grafo.
Un arreglo unidimensional es un tipo de datos estructurado que está formado de una colección
finita y ordenada de datos del mismo tipo. Es la estructura natural para modelar listas de
elementos iguales.
La ordenación es una aplicación fundamental en computación. La mayoría de los datos
producidos por un programa están ordenados de alguna manera, y muchos de los cómputos que
tiene que realizar un programa son más eficientes si los datos sobre los que operan están
ordenados. Uno de los tipos de cómputo que más se benefician de operar sobre un conjunto de
datos ordenados es la búsqueda de un dato: encontrar el número de teléfono de una persona en
un listín telefónico es una tarea muy simple y rápida si conocemos su nombre, ya que los listines
telefónicos se encuentran ordenados alfabéticamente.
La búsqueda secuencial, también se le conoce como búsqueda lineal. 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 hayan visto todas las casillas. El resultado de la búsqueda
es un solo valor, y será la posición del elemento buscado o cero.
Lecturas Recomendadas
• http://www.algorist.com/
• http://sistemas.itlp.edu.mx/tutoriales/progorientobjetos/t11.htm
• http://www.ceidis.ula.ve/cursos/ingenieria/pd_10/clases/Apunt_.pdf
• http://sistemas.itlp.edu.mx/tutoriales/algoritmos/tema_71.htm