Professional Documents
Culture Documents
CURSO:
Análisis y Diseño de Algoritmos
TEMA:
Estructura de Datos para Algoritmos
PRESENTADO POR:
Mamani Charca, Lady Patricia
Quispe Ccallo, Lisbet Charo
Pacsi Quispecondori, Leidy Verónica
Medina Ticona, Yessenia
DOCENTE:
Alave Aguilar, Mariela
SEMESTRE:
CUARTO PERIODO II
PUNO – PERÚ
2018
INDICE
Hoy en día necesitamos conocer los orígenes de la computación, el cómo usar una
estructura de datos, que es la base que nos ayudara a construir soluciones robustas y útiles
para los diversos problemas.
Este trabajo está realizado con la finalidad de informar de que trata la estructura de datos
para algoritmos, se dará a conocer que es una estructura de datos, que es un algoritmo;
así mismo se dará a conocer los algoritmos más representativos y explicando cada uno de
estos en cómo es que funcionan, para el mayor entendimiento se brindara algunos
ejemplos.
ESTRUCTURA DE DATOS
Un entero puede ser muy útil si necesitamos un contador, una suma o un índice en
un programa, pero generalmente también tenemos que tratar con datos que tienen muchas
partes tales como una lista. Cuando la información de un programa está formada de partes,
tenemos que considerar una estructura de datos adecuada.
Las estructuras de datos tienen algunas características propias. Primero, pueden ser
descompuestas en sus elementos componentes. Segundo, la forma de colocar los
elementos es una característica de la estructura que afectará a cómo se accede a cada
elemento. Tercero, la forma de colocar los elementos y la forma en la que se accede a
ellos puede ser encapsulada.
Por ejemplo en la vida real una biblioteca puede descomponerse en sus elementos, los
libros. La colección de libros puede colocarse de varias formas: todos agrupados, en orden
alfabético, por temas, etc. Obviamente la forma en que se ubican en la biblioteca
particular a la que nos estamos refiriendo, no se deja que cada una se sirva sus libros. Si
alguien quiere un libro, le da su petición al bibliotecario, quien hace la entrega de la lista
de libros pertinentes.
Usaremos este mismo método para las estructuras de datos de nuestros programas. Una
estructura de datos se definirá como la forma lógica de colocar los elementos, combinados
con el conjunto de operaciones que necesitamos para acceder a los elementos.
ALGORITMOS
Un algoritmo se puede definir como una secuencia de instrucciones que
representan un modelo de solución para determinado tipo de problemas. O bien como un
conjunto de instrucciones que realizadas en orden conducen a obtener la solución de un
problema.
Formalmente, un grafo se define como G = (V, E), siendo V un conjunto cuyos elementos
son los vértices del grafo y, E uno cuyos elementos son las aristas, las cuales son pares
de elementos en V.
MATRICES
Las matrices o como algunos las llaman "arreglos multidimensionales" son una estructura
de datos bastante similar a los vectores o arreglos. De hecho, una matriz no es más que
una serie de vectores contenidos uno en el otro, es decir, una matriz es un vector cuyas
posiciones son otros vectores. En términos generales, una matriz es una estructura
conformada por filas y columnas, idealmente más de dos filas y columnas, de hecho,
podemos decir que si una "matriz" tiene una única fila o una única columna, entonces
estamos hablando de un vector y no una matriz como tal.
La intersección de una fila y una columna de la matriz son las casillas y cada una de ellas
podrá poseer información, simple o compleja. Un vector posee una única fila y de este
modo un grupo de vectores unidos conforman una matriz, llegando a una conclusión que
una matriz es un vector conformado por otra serie de vectores.
tipoDato nombreMatriz[filas][columnas];
PILAS Y COLAS
Las pilas y colas son estructuras de datos que se utilizan generalmente para simplificar
ciertas operaciones de programación.
PILAS
Una pila (stack en inglés) es una lista ordenada o estructura de datos en la que el modo
de acceso a sus elementos es de tipo LIFO (Last In Firts Out), último en entrar, primero
en salir; que permite almacenar y recuperar datos.
};
Para Insertar elementos en la pila, solo hay que seguir 4 pasos:
Dato
*siguiente NODO
Dato
*siguiente
Dato
*siguiente
NULL
Para quitar elementos de una Pila, igualmente hay que seguir 4 pasos:
2. Igualar el n a aux-dato.
4° Eliminar aux.
Aplicaciones de las pila
Las pilas se utilizan en muchas aplicaciones que utilizamos con frecuencia. Por
ejemplo, la gestión de ventanas en Windows (cuando cerramos una ventana siempre
recuperamos la que teníamos detrás). Otro ejemplo es la evaluación general de cualquier
expresión matemática para evitar tener que calcular el número de variables temporales
que hacen falta. Por ejemplo
COLAS
Las colas también son llamadas FIFO (First In First Out), que quiere decir “el primero
que entra es el primero que sale”.
Colas simples: Se inserta por un sitio y se saca por otro, en el caso de la cola simple se
inserta por el final y se saca por el principio. Para gestionar este tipo de cola hay que
recordar siempre cual es el siguiente elemento que se va a leer y cuál es el último elemento
que se ha introducido.
Colas circulares: En las colas circulares se considera que después del último elemento
se accede de nuevo al primero. De esta forma se reutilizan las posiciones extraídas, el
final de la cola es a su vez el principio, creándose un circuito cerrado.
Colas con prioridad: Las colas con prioridad se implementan mediante listas o arrays
ordenados .No nos interesa en este caso que salgan en el orden de entrada sino con una
prioridad que le asignemos. Puede darse el caso que existan varios elementos con la
misma prioridad, en este caso saldrá primero aquel que primero llego (FIFO).
FIN
Dato Struct Nodo{
NODO
*siguiente int dato;
Nodo *siguiente;
dato };
*siguiente
dato
FRENTE
*siguiente
NULL
Para insertar elementos en una cola, solo hay que seguir 3 pasos:
Para eliminar elementos de una cola solo hay que seguir 3 pasos:
PUNTEROS
1. PUNTEROS (APUNTADOR)
Un puntero es una variable que contiene la dirección de memoria de un dato o de otra
variable que contiene al dato en un arreglo. Esto quiere decir, que el puntero apunta al
espacio físico donde está el dato o la variable. Un puntero puede apuntar a un objeto de
cualquier tipo, como por ejemplo, a una estructura o una función. Los punteros se pueden
utilizar para referencia y manipular estructuras de datos, para referenciar bloques de
memoria asignados dinámicamente y para proveer el paso de argumentos por referencias
en las llamadas a funciones.
Ya se dijo que un puntero es una variable que guarda la dirección de memoria de otra
variable, haciendo lógica a esto, decimos que un puntero se declara igual que cualquier
otra variable, pero anteponiendo un * (asterisco) antes del nombre de la variable.
Su sintaxis sería:
#include <stdio.h>
int main()
{
int a=0; //Declaración de variable entera de tipo entero
int *puntero; //Declaración de variable puntero de tipo entero
puntero = &a; //Asignación de la dirección memoria de a
printf("El valor de a es: %d. \nEl valor de *puntero es: %d. \n",a,*puntero);
printf("La dirección de memoria de *puntero es: %p",puntero);
return 0;
}
Igual que cuando usamos un &, en la lectura de datos con scanf, igual de esta forma
lo usamos aquí, tal vez te acordarás que decíamos que las cadenas de caracteres (%s)
no usaban este operador, esto es porque en una cadena de caracteres es un arreglo de
caracteres, por lo que el primer carácter es la dirección de inicio de la cadena.
El operador *, nos permite acceder al valor de la dirección del puntero, en este caso
nos permite acceder al valor que contiene a la variable a. De esta forma "a" y
"*puntero" muestran el mismo dato, pero esto no quiere decir que sea lo mismo, uno
es un entero y el otro un puntero.
¿Diferentes direcciones?
Tal vez notaste que en cada ejecución la dirección de memoria cambia, esto es porque
es el sistema operativo quien está encargado de administrar la memoria y es éste quien
dice qué espacios podrá tomar el programa.
Esto quiere decir que uno no puede asignarle una dirección de memoria a un
puntero directamente, es decir yo no puedo hacer lo siguiente.
int *puntero=0xbfc5b1c8;
Esto no puedo ni debo hacerlo ya que yo no sé que está haciendo esta dirección de
memoria, si el sistema la tiene o no disponible, etc... Pero sí puedo hacer esto:
int *puntero=NULL;
NULL, es el espacio en memoria con dirección 0, esto quiere decir que existe, lo que
significa que le asignamos una dirección válida al puntero, pero el valor que tiene NULL
no se nos permite modificarlo, ya que pertenece al sistema.
1.2. OPERADORES
Operador de Indirección (*): Además de que nos permite declarar un tipo de dato
puntero, también nos permite ver el VALOR que está en la dirección asignada.
PUNTEROS CONSTANTES
Es posible que hayas pensado como declarar un puntero como una constante, tal vez
pensaste en un define, o en un atributo const. Bueno es posible usar el atributo const,
pero para un puntero hay que hacerlo de otra forma.
FORMA ERRADA
int a=10,b=20;
const int *p = &a; //objeto constante y puntero variable
*p = 15; // ERROR: el valor apuntado por p es constante.
p=&b; //Correcto: p pasa a apuntar a un nuevo objeto.
Pero de esta forma no es muy útil declararlo, pues el que hicimos constante fue el
valor al que apunte p, es decir, mejor hubiésemos hecho que el puntero fuese una
constante.
FORMA CORRECTA
int a=10,b=20;
int * const p = &a; //objeto variable y puntero constante
int * const p = &a; //objeto variable y puntero constante
*p = 15; // Correcto: El valor apuntado es variable.
p=&b; //ERROR: p es constante.
Un puntero a cualquier tipo de dato puede convertirse a un puntero del tipo void *.
Por esto un puntero a void *, recibe el nombre de puntero genérico.
Supongamos:
int *puntero;
funcion (*puntero);
....
void funcion (void *p)
int *q;
q=(int *)p; //En C se podria hacer q = p;
Es decir que un puntero a void se puede usar sin importar el tipo de dato, recuerden
que uno no puede trabajar con punteros que referencia a un tipo de dato diferente,
como lo es un puntero a char, con un puntero a int.
ESTRUCTURAS O REGISTROS
Un registro es una agrupación de datos, los cuales no necesariamente son del mismo tipo.
Se definen con la palabra “struct”.
Para acceder a cada uno de los datos que forman el registro, tanto si queremos leer su
valor como si queremos cambiarlo, se debe indicar el nombre de la variable y el del dato
(o campo) separados por un punto:
ARRAYS DE REGISTROS
Hemos guardado varios datos de una persona. Se pueden almacenar los de varias
personas si combinamos el uso de los “struct” con las tablas (arrays) que vimos
anteriormente. La sintaxis no es exactamente la misma, y tendremos que añadir la palabra
"new" en el momento de reservar espacio. Por ejemplo, si queremos guardar los datos de
100 alumnos podríamos hacer:
#include <iostream>
#include <string>
using namespace std;
int main()
{
struct datosPersona
{
string nombre;
char inicial;
int edad;
float nota;
};
return 0;
}
La inicial del primer alumno sería “alumnos [0].inicial”, y la edad del último sería
“alumnos [99].edad”.
ESTRUCTURAS ANIDADAS
Podemos encontrarnos con un registro que tenga varios datos, y que a su vez ocurra que
uno de esos datos esté formado por varios datos más sencillos. Para hacerlo desde C++,
incluiríamos un “struct” dentro de otro, así:
#include <iostream>
#include <string>
using namespace std;
struct fechaNacimiento
{
int dia;
int mes;
int anyo;
};
struct datosPersona
{
string nombre;
char inicial;
struct fechaNacimiento diaDeNacimiento;
float nota;
};
int main()
{
datosPersona persona;
persona.nombre = "Ignacio";
persona.inicial = 'I';
persona.diaDeNacimiento.mes = 8;
persona.nota = 7.5;
cout << "La nota es " << persona.nota;
return 0;
}
LISTAS
Guardati(2007) define una lista como una colección de elementos donde cada uno de
ellos, además de almacenar información, almacena la dirección del siguiente elemento.
Una lista es una estructura lineal de datos. Es decir, cada uno de sus componentes tiene
un sucesor y predecesor únicos, con excepción del último y del primero, los cuales
carecen de sucesor y predecesor respectivamente.
Las listas pueden implementarse mediante arreglos resultando así una estructura estática.
Otra alternativa para su implementación es usar memoria dinámica, lo que permite que
dicha característica se propague a la lista, obteniendo una estructura dinámica. Las listas
se analizarán como estructuras dinámicas.
2. Lista doblemente enlazadas: cada nodo contiene dos enlaces, uno a su nodo
predecesor y el otro a su sucesor. La lista es eficiente tanto en recorrido directo
(<<adelante>>) como en recorrido inverso (<<atrás>>).
Una lista enlazada consta de un conjunto de nodos. Un nodo consta de un campo dato y
un puntero que apunta al <<siguiente>> elemento de lista.
El primer nodo, frente, es el nodo apuntado por cabeza. La lista encadena nodos juntos
desde el frente al final (cola) de la lista. El final se identifica como el nodo cuyo campo
puntero tiene valor NULL=0. La lista se recorre desde el primer hasta el último nodo; en
cualquier punto del recorrido la posición actual se referencia por el puntero Ptr_actual.
En el caso que la lista no contiene nodo, el puntero cabeza en nulo.
Recorrer la lista
Declaración de un NODO
Una lista enlazada se compone de una serie de nodos enlazadas mediante punteros. Cada
nodo es una combinación de dos partes: un tipo de dato (entero, real, double, carácter,
etc) y un enlace (puntero) al siguiente nodo. En C++ se puede definir un nodo mediante
un nuevo tipo de dato con las palabras reservadas struct o class que contienen las dos
partes citadas
EJEMPLO:
ARBOLES
(Guardati, 2007) Menciona que los árboles son estructuras de datos no lineales. Cada
elemento, conocido con el nombre de nodo, puede tener varios sucesores. En términos
generales, un árbol se define como una colección de nodos donde cada uno, además de
almacenar información, guarda la dirección de sus sucesores. Se conoce la dirección de
uno de los nodos llamado raíz, y a partir de él tiene acceso a todos los otros miembros de
la estructura.
Existen diversas maneras de representar un árbol, las más comunes son: grafos,
anidación de paréntesis y diagramas de Venn.
Árbol representado
Terminología
Hijo: Se dice que un nodo es hijo de otro si este último apunta al primero.
Padre: Se dice que un nodo es padre de otro si este último es apuntado por el primero.
Hermano: Dos nodos son hermanos si son apuntados por el mismo nodo, es decir si
tienen el mismo padre.
Raíz: Se dice que un nodo es raíz si a partir de él se relaciona todos los otros nodos. Si
un árbol no es vacío, entonces tiene un único nodo raíz.
Hoja o terminal. Se dice que un nodo es una hoja del árbol si no tiene hijos.
Nivel de un nodo: Se dice que el nivel de un nodo es el número de arcos que deben ser
recorridos, partido de la raíz, para llegar hasta él.
Altura del árbol: Se dice que la altura de un árbol es el máximo de los niveles,
considerando todos sus nodos.
Grado de un nodo: se dice que el grado de nodo es el número de hijos que tiene dicho
nodo.
Grado del árbol: Se dice que el grado de un árbol es el máximo de los grados,
considerando todos sus nodos.
NODO
Necesitamos un nodo que apunte a otros nodos
Árbol completo
Árbol degenerado
Estructura de un árbol binario
Guardati, S. (2007). Estructura de datos orientada a objetos. Algoritmos con C++. Mexico:
Industrial Atoto.
https://html.rincondelvago.com/estructura-de-datos_16.html?fbclid=IwAR39KYPFILbf1BAAjw
FhnpZPUsqi9nu1O29lalbkGbotQ2zwXCjLWUShbIc
http://ing.unne.edu.ar/pub/informatica/Alg_diag.pdf
https://www.programarya.com/Cursos/C++/Estructuras-de-Datos/Matrices