APUNTES Estructuras de Datos
APUNTES Estructuras de Datos
“APUNTES”
INTRODUCCION
Como ya sabemos, las computadoras fueron diseñadas o ideadas como una herramienta
mediante la cual podemos realizar operaciones de cálculo complicadas en un lapso de
mínimo tiempo. Pero la mayoría de las aplicaciones de este fantástico invento del hombre,
son las de almacenamiento y acceso de grandes cantidades de información.
La información que se procesa en la computadora es un conjunto de datos, que pueden ser
simples o estructurados. Los datos simples son aquellos que ocupan sólo un localidad de
memoria, mientras que los estructurados son un conjunto de casillas de memoria a las cuales
hacemos referencia mediante un identificador único.
Debido a que por lo general tenemos que tratar con conjuntos de datos y no con datos simples
(enteros, reales, booleanos, etc.) que por sí solos no nos dicen nada, ni nos sirven de mucho, es
necesario tratar con estructuras de datos adecuadas a cada necesidad.
Las estructuras de datos son una colección de datos cuya organización se caracteriza por
las funciones de acceso que se usan para almacenar y acceder a elementos individuales de
datos.
Una estructura de datos se caracteriza por lo siguiente:
-La colocación de los elementos y la manera en que se accede a ellos puede ser
encapsulada
TIPOS DE DATOS
TIPOS DE DATOS
Dinámicos
Estáticos
o El tipo cadena
o Estructurados
o Simples
Ordinales
No-ordinales
Tipos estáticos
Casi todos los tipos de datos son estáticos, la excepción son los
punteros. Que un tipo de datos sea estático quiere decir que el tamaño que
ocupa en memoria no puede variar durante la ejecución del programa. Es decir,
una vez declarada una variable de un tipo determinado, a ésta se le asigna un
trozo de memoria fijo, y este trozo no se podrá aumentar ni disminuír.
Tipos dinámicos.
Dentro de esta categoría entra sólamente el tipo puntero. Este tipo te permite
tener un mayor control sobre la gestión de memoria en tus programas. Con
ellos puedes manejar el tamaño de tus variables en tiempo de ejecución, o sea,
cuando el programa se está ejecutando. Los punteros quizás sean el concepto
más complejo a la hora de aprender un lenguaje de programación.
Tipos simples
Como su nombre indica son los tipos básicos. Son los más sencillos y los más
fáciles de aprender. Los tipos simples más básicos son: entero, lógico, carácter
y real. Y la mayoría de los lenguajes de programación los soportan, no como
ocurre con los estructurados que pueden variar de un lenguaje a otro.
Tipos estructurados
Mientras que una variable de un tipo simple sólo referencia a un elemento, los
estructurados se refieren a colecciones de elementos.
Las colecciones de elementos que aparecen al hablar de tipos estructurados
son muy variadas: tenemos colecciones ordenadas que se representan
mediante el tipo array, colecciones sin orden mediante el tipo conjunto, e
incluso colecciones que contienen otros tipos, son los llamados registros.
Tipos ordinales
Dentro de los tipos simples, los ordinales son los más abundantes. De un tipo
se dice que es ordinal porque el conjunto de valores que representa se puede
contar, es decir, podemos establecer una relación uno a uno entre sus
elementos y el conjunto de los números naturales.
Dentro de los tipos simples ordinales, los más importantes son:
El tipo entero.
El tipo lógico.
El tipo carácter.
Tipos no-ordinales
Simplificando, podríamos reducir los tipos simples no-ordinales al tipo real. Este
tipo nos sirve para declarar variables que pueden tomar valores dentro del
conjunto de los números reales. A diferencia de los tipos ordinales, los no-
ordinales no se pueden contar. No se puede establecer una relación uno a uno
entre ellos y los número naturales. Dicho de otra forma, para que un conjunto
se considere ordinal se tiene que poder calcular la posición, el anterior
elemento y el siguiente de un elemento cualquiera del conjunto.¿Cuál es el
sucesor de 5.12? Será 5.13, o 5.120, o 5.121, ...
ESTRUCTURAS SECUENCIALES
INTRODUCCION
Supongamos que nos enfrentamos a un problema como este: Una empresa que cuenta con
150 empleados, desea establecer una estadística sobre los salarios de sus empleados, y
quiere saber cual es el salario promedio, y también cuantos de sus empleados gana
entre $1250.00 y $2500.00.
Si tomamos la decisión de tratar este tipo de problemas con datos simples, pronto nos
percataríamos del enorme desperdicio de tiempo, almacenamiento y velocidad. Es por eso que
para situaciones de este tipo la mejor solución son los datos estructurados.
Un arreglo puede definirse como un grupo o una colección finita, homogénea y ordenada de
elementos. Los arreglos pueden ser de los siguientes tipos:
De una dimensión.
De dos dimensiones.
De tres o más dimensiones.
Arreglos Unidimensionales
REPRESENTACION EN MEMORIA
Arreglos Bidimensionales
Este tipo de arreglos al igual que los anteriores es un tipo de dato estructurado, finito
ordenado y homogéneo. El acceso a ellos también es en forma directa por medio de un par de
índices.
Los arreglos bidimensionales se usan para representar datos que pueden verse
como una tabla con filas y columnas. La primera dimensión del arreglo
representa las columnas, cada elemento contiene un valor y cada dimensión
representa una relación
La representación en memoria se realiza de dos formas : almacenamiento por
columnas o por renglones.
Para determinar el número total de elementos en un arreglo bidimensional
usaremos las siguientes fórmulas:
RANGO DE RENGLONES| (R1) = Ls1 - (Li1+1)
RANGO DE COLUMNAS (R2) = Ls2 - (Li2+1)
No. TOTAL DE COMPONENTES = R1 * R2
Arreglos Multidimensionales
donde:
i = 1 ... n
n = No. total de dimensiones
Para determinar la dirección de memoria se usa la siguiente formula:
a) LECTURA
b) ESCRITURA
c) ASIGNACION
d) ACTUALIZACION
Una matríz poco densa es aquella que está formada por elementos que en su mayoría
son ceros. Este tipo de matrices son matrices cuadradas que se dividen en los
siguientes tipos:
donde:
A=Matríz triangular superior
n=No. total de elementos
j= renglones
i=columnas
MATRIZ TRIDIAGONAL
Ordenaciones en Arreglos
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úsquedas en Arreglos
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 numero 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
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.
COLAS
Representación en Memoria
Como arreglos
Como listas ordenadas
Cola Lineal
Cola Circular
Las colas lineales tienen un grave problema, como las extracciones sólo
pueden realizarse por un extremo, puede llegar un momento en que el
apuntador A sea igual al máximo número de elementos en la cola, siendo que
al frente de la misma existan lugares vacíos, y al insertar un nuevo elemento
nos mandará un error de overflow (cola llena).
Para solucionar el problema de desperdicio de memoria se implementaron las
colas circulares, en las cuales existe un apuntador desde el último elemento al
primero de la cola.
La representación gráfica de esta estructura es la siguiente:
Las condiciones que debemos tener presentes al trabajar con este tipo de
estructura son las siguientes:
Cola de Prioridades
Operaciones en Colas
Las operaciones que nosotros podemos realizar sobre una cola son las
siguientes:
Inserción.
Extracción.
Las inserciones en la cola se llevarán a cabo por atrás de la cola, mientras que
las eliminaciones se realizarán por el frente de la cola (hay que recordar que el
primero en entrar es el primero en salir).
PILAS
Las pilas son otro tipo de estructura de datos lineales, las cuales presentan
restricciones en cuanto a la posición en la cual pueden realizarse las
inserciones y las extracciones de elementos.
Una pila es una lista de elementos en la que se pueden insertar y eliminar
elementos sólo por uno de los extremos. Como consecuencia, los elementos
de una pila serán eliminados en orden inverso al que se insertaron. Es decir, el
último elemento que se metió a la pila será el primero en salir de ella.
En la vida cotidiana existen muchos ejemplos de pilas, una pila de platos en
una alacena, una pila de latas en un supermercado, una pila de papeles sobre
un escritorio, etc.
Debido al orden en que se insertan y eliminan los elementos en una pila,
también se le conoce como estructura LIFO (Last In, First Out: último en entrar,
primero en salir).
Representación en Memoria
Arreglos.
Listas enlazadas.
Nosotros ahora usaremos los arreglos. Por lo tanto debemos definir el tamaño
máximo de la pila, además de un apuntador al último elemento insertado en la
pila el cual denominaremos SP. La representación gráfica de una pila es la
siguiente:
Como utilizamos arreglos para implementar pilas, tenemos la limitante de
espacio de memoria reservada. Una vez establecido un máximo de capacidad
para la pila, ya no es posible insertar más elementos.
Una posible solución a este problema es el uso de espacios compartidos de
memoria. Supongase que se necesitan dos pilas , cada una con un tamaño
máximo de n elementos. En este caso se definirá un solo arreglo de 2*n
elementos, en lugar que dos arreglos de n elementos.
En este caso utilizaremos dos apuntadores: SP1 para apuntar al último
elemento insertado en la pila 1 y SP2 para apuntar al último elemento insertado
en la pila 2. Cada una de las pilas insertará sus elementos por los extremos
opuestos, es decir, la pila 1 iniciará a partir de la localidad 1 del arreglo y la pila
2 iniciará en la localidad 2n. De este modo si la pila 1 necesita más de n
espacios (hay que recordar que a cada pila se le asignaron n localidades) y la
pila 2 no tiene ocupados sus n lugares, entonces se podrán seguir insertando
elementos en la pila 1 sin caer en un error de desbordamiento.
Las pilas son estructuras de datos muy usadas para la solución de diversos
tipos de problemas. Pero tal vez el principal uso de estas estructuras es el
tratamiento de expresiones matemáticas.
Recursión
Operaciones en Pilas
LISTAS ENLAZADAS
Una lista enlazada o encadenada es una colección de elementos ó nodos, en
donde cada uno contiene datos y un enlace o liga.
Un nodo es una secuencia de caracteres en memoria dividida en campos (de
cualquier tipo). Un nodo siempre contiene la dirección de memoria del siguiente
nodo de información si este existe.
Un apuntador es la dirección de memoria de un nodo
La figura siguiente muestra la estructura de un nodo:
El campo liga, que es de tipo puntero, es el que se usa para establecer la liga
con el siguiente nodo de la lista. Si el nodo fuera el último, este campo recibe
como valor NIL (vacío).
A continuación se muestra el esquema de una lista :
Operaciones en Listas Enlazadas
Las operaciones que podemos realizar sobre una lista enlazada son las
siguientes:
Recorrido. Esta operación consiste en visitar cada uno de los nodos que forman
la lista . Para recorrer todos los nodos de la lista, se comienza con el primero, se
toma el valor del campo liga para avanzar al segundo nodo, el campo liga de este
nodo nos dará la dirección del tercer nodo, y así sucesivamente.
Inserción. Esta operación consiste en agregar un nuevo nodo a la lista. Para esta
operación se pueden considerar tres casos:
o Insertar un nodo al inicio.
o Insertar un nodo antes o después de cierto nodo.
o Insertar un nodo al final.
Borrado. La operación de borrado consiste en quitar un nodo de la lista,
redefiniendo las ligas que correspondan. Se pueden presentar cuatro casos:
o Eliminar el primer nodo.
o Eliminar el último nodo.
o Eliminar un nodo con cierta información.
o Eliminar el nodo anterior o posterior al nodo cierta con información.
Búsqueda. Esta operación consiste en visitar cada uno de los nodos, tomando al
campo liga como puntero al siguiente nodo a visitar.
Listas Lineales
En esta sección se mostrarán algunos algoritmos sobre listas lineales sin nodo
de cabecera y con nodo de cabecera.
Una lista con nodo de cabecera es aquella en la que el primer nodo de la lista
contendrá en su campo dato algún valor que lo diferencíe de los demás nodos
(como : *, -, +, etc). Un ejemplo de lista con nodo de cabecera es el siguiente:
Para el caso de las listas sin nodo de cabecera, se usará la expresión TOP
para referenciar al primer nodo de la lista, y TOP(dato), TOP(liga) para hacer
referencia al dato almacenado y a la liga al siguiente nodo respectivamente.
Listas Dobles
Listas dobles lineales. En este tipo de lista doble, tanto el puntero izquierdo del
primer nodo como el derecho del último nodo apuntan a NIL.
Listas dobles circulares. En este tipo de lista doble, el puntero izquierdo del
primer nodo apunta al último nodo de la lista, y el puntero derecho del último
nodo apunta al primer nodo de la lista.
Listas Circulares
En este tipo de lista se utiliza para representar matrices. Los nodos contienen
cuatro apuntadores. Uno para apuntar al nodo izquierdo (li),otro para apuntar al
derecho(ld), otro al nodo inferior(lb) y por último un apuntador al nodo
superior(la).
ESTRUCTURAS NO LINEALES
A los arboles ordenados de grado dos se les conoce como arboles binarios ya
que cada nodo del árbol no tendrá más de dos descendientes directos. Las
aplicaciones de los arboles binarios son muy variadas ya que se les puede
utilizar para representar una estructura en la cual es posible tomar decisiones
con dos opciones en distintos puntos.
La representación gráfica de un árbol binario es la siguiente:
Representación en Memoria
Por medio de datos tipo punteros también conocidos como variables dinámicas o
listas.
Por medio de arreglos.
Sin embargo la más utilizada es la primera, puesto que es la más natural para
tratar este tipo de estructuras.
Los nodos del árbol binario serán representados como registros que
contendrán como mínimo tres campos. En un campo se almacenará la
información del nodo. Los dos restantes se utilizarán para apuntar al subarbol
izquierdo y derecho del subarbol en cuestión.
Cada nodo se representa gráficamente de la siguiente manera:
Clasificación de Arboles Binarios
A. B. Distinto.
A. B. Similares.
A. B. Equivalentes.
A. B. Completos.
A continuación se hará una breve descripción de los diferentes tipos de árbol
binario así como un ejemplo de cada uno de ellos.
A. B. DISTINTO
Se dice que dos árboles binarios son distintos cuando sus estructuras son diferentes.
Ejemplo:
A. B. SIMILARES
Dos arboles binarios son similares cuando sus estructuras son idénticas, pero la
información que contienen sus nodos es diferente. Ejemplo:
A. B. EQUIVALENTES
Son aquellos arboles que son similares y que además los nodos contienen la misma
información. Ejemplo:
A. B. COMPLETOS
Son aquellos arboles en los que todos sus nodos excepto los del ultimo nivel, tiene dos
hijos; el subarbol izquierdo y el subarbol derecho.
Recorrido de un Arbol Binario
1. INORDEN
o Recorrer el subarbol izquierdo en inorden.
o Examinar la raíz.
o Recorrer el subarbol derecho en inorden.
2. PREORDEN
o Examinar la raíz.
o Recorrer el subarbol izquierdo en preorden.
o recorrer el subarbol derecho en preorden.
3. POSTORDEN
o Recorrer el subarbol izquierdo en postorden.
o Recorrer el subarbol derecho en postorden.
o Examinar la raíz.
Inorden: GDBHEIACJKF
Preorden: ABDGEHICFJK
Postorden: GDHIEBKJFCA
Arboles Enhebrados
Arboles en Montón
Los vértice de un grafo pueden usarse para representar objetos. Los arcos se
utilizan para representar relaciones entre estos objetos.
Las aplicaciones más importantes de los grafos son las siguientes:
CAMINO.Es una secuencia de vértices V1, V2, V3, ... , Vn, tal que cada uno de estos V1-
>V2, V2->V3, V1->V3.
LONGITUD DE CAMINO. Es el número de arcos en ese camino.
CAMINO SIMPLE. Es cuando todos sus vértices, excepto tal vez el primero y el último son
distintos.
CICLO SIMPLE. Es un camino simple de longitud por lo menos de uno que empieza y termina
en el mismo vértice.
ARISTAS PARALELAS. Es cuando hay más de una arista con un vértice inicial y uno terminal
dados.
GRAFO CICLICO. Se dice que un grafo es cíclico cuando contiene por lo menos un ciclo.
GRAFO ACICLICO. Se dice que un grafo es aciclíco cuando no contiene ciclos.
GRAFO CONEXO. Un grafo G es conexo, si y solo si existe un camino simple en cualesquiera
dos nodos de G.
GRAFO COMPLETO ó FUERTEMENTE CONEXO.Un grafo dirigido G es completo si
para cada par de nodos (V,W) existe un camino de V a W y de W a V (forzosamente tendrán que
cumplirse ambas condiciones), es decir que cada nodo G es adyacente a todos los demás nodos
de G.
GRAFO UNILATERALMENTE CONEXO.Un grafo G es unilateralmente conexo si para
cada par de nodos (V,W) de G hay un camino de V a W o un camino de W a V.
GRAFO PESADO ó ETIQUETADO. Un grafo es pesado cuando sus aristas contienen datos
(etiquetas). Una etiqueta puede ser un nombre, costo ó un valor de cualquier tipo de dato.
También a este grafo se le denomina red de actividades, y el número asociado al arco se le
denomina factor de peso.
VERTICE ADYACENTE. Un nodo o vértice V es adyacente al nodo W si existe un arco de m
a n.
GRADO DE SALIDA.El grado de salida de un nodo V de un grafo G, es el número de arcos o
aristas que empiezan en V.
GRADO DE ENTRADA.El grado de entrada de un nodo V de un grafo G, es el número de
aristas que terminan en V.
NODO FUENTE.Se le llama así a los nodos que tienen grado de salida positivo y un grado de
entrada nulo.
NODO SUMIDERO.Se le llama sumidero al nodo que tiene grado de salida nulo y un grado de
entrada positivo.
Creación.
Inserción.
Búsqueda.
Eliminación.