Está en la página 1de 129

UNIVERSIDAD TECNICA DE ORURO

FACULTAD NACIONAL DE INGENIERIA


INGENIERIA DE SISTEMAS E INFORMATICA

TEXTO GUIA:

ESTRUCTURA DE DATOS

SIS2204

Docente: Ing. Juan Gregorio Choque Uño


Fecha de Realización: Marzo del 2008

Oruro - Bolivia

1
2
CONTENIDO
INTRODUCCION........................................................................................................................6
1.1 ESTRUCTURA DE DATOS. ............................................................................................................................................6

1.2 OPERACIONES SOBRE ESTRUCTURAS DE DATOS. .............................................................................................9

PILAS Y COLAS.......................................................................................................................10
2.1 PILAS. ...............................................................................................................................................................................10

..................................................................................................................................................................................................16

2.2 COLAS. .............................................................................................................................................................................17

2.3 COLAS CIRCULARES. ..................................................................................................................................................19


ELIMINAR EL NODO DELANTERO DE LA COLA.......................................................................................................20

2.4 APLICACIONES DE LISTAS RESTRINGIDAS. .......................................................................................................22

ARCHIVOS, REGISTROS Y CAMPOS....................................................................................26


3.1 ARCHIVOS ......................................................................................................................................................................26

3.2 TIPOS DE ARCHIVOS. ..................................................................................................................................................26

3.3 REGISTROS Y CAMPOS. .............................................................................................................................................28

TRATAMIENTO DE ARCHIVOS..............................................................................................30
4.1 INTRODUCCION ............................................................................................................................................................30

4.2 OPERACIONES SOBRE ARCHIVOS .........................................................................................................................30


ADICION DE DATOS ........................................................................................................................................................31
ELIMINAR DATOS ...........................................................................................................................................................32
CONSULTAS DE DATOS .................................................................................................................................................33
BUSQUEDA DE DATOS ...................................................................................................................................................34

4.3 PARTICION DE ARCHIVOS ........................................................................................................................................35


PARTICION POR CONTENIDO .......................................................................................................................................36
PARTICION POR UNA SECUENCIA " P " DADA .........................................................................................................36
PARTICIÓN DE ARCHIVOS POR TRAMOS ORDENADOS ........................................................................................37

4.4 MEZCLAS DE ARCHIVOS ...........................................................................................................................................38


MEZCLA POR CONTENIDO TOTAL .............................................................................................................................39
MEZCLA POR SECUENCIAS " P " ..................................................................................................................................39
MEZCLA POR TRAMOS ORDENADAS .........................................................................................................................41

4.5 ORDENACIÓN EXTERNA ...........................................................................................................................................42


ORDENACIÓN POR MEZCLA DIRECTA ......................................................................................................................42
ORDENACIÓN POR VON NEWMAN .............................................................................................................................45
ORDENACIÓN POR MEZCLA EQUILIBRADA ............................................................................................................47
ORDENACIÓN POR DIGITOS .........................................................................................................................................49

3
LISTAS ENCADENADAS........................................................................................................52
5.1 LISTAS ENCADENADAS ..............................................................................................................................................52
TIPOS DE LISTAS. ............................................................................................................................................................52

5.2 LISTAS SIMPLEMENTE ENLAZADAS .....................................................................................................................53


OPERACIONES EN LISTAS SIMPLEMENTE ENLAZADAS .......................................................................................54
RECORRIDO ......................................................................................................................................................................54
BUSQUEDA .......................................................................................................................................................................55
INSERCION DE DATOS ...................................................................................................................................................55
ELIMINAR DATOS ...........................................................................................................................................................58

5.3 LISTAS SIMPLEMENTE ENLAZADAS CIRCULARES. .........................................................................................59


OPERACIONES EN LISTAS SIMPLEMENTE ENLAZADAS CIRCULARES .............................................................60
RECORRIDO ......................................................................................................................................................................60
BUSQUEDA .......................................................................................................................................................................61
INSERCION DE DATOS ...................................................................................................................................................61
ELIMINAR DATOS ...........................................................................................................................................................63

5.4 LISTAS DOBLEMENTE ENLAZADAS. .....................................................................................................................64


OPERACIONES EN LISTAS DOBLEMENTE ENLAZADAS. .......................................................................................65
RECORRIDO ......................................................................................................................................................................66
INSERCION DE DATOS ...................................................................................................................................................67
ELIMINAR DATOS ...........................................................................................................................................................69

5.5 LISTAS CIRCULARES DOBLEMENTE ENLAZADAS. ..........................................................................................72


OPERACIONES EN LISTAS DOBLEMENTE ENLAZADAS CIRCULARES. .............................................................73
RECORRIDO ......................................................................................................................................................................73
INSERCION DE DATOS ...................................................................................................................................................74
ELIMINAR DATOS ...........................................................................................................................................................76

ÁRBOLES.................................................................................................................................78
6.1 DEFINICION. ..................................................................................................................................................................78
REPRESENTACIÓN ..........................................................................................................................................................78
MATRIZ DE ADYACENCIA ............................................................................................................................................79
LISTA DE ADYACENCIA ................................................................................................................................................79
ESTRUCTURA DINÁMICA PURA ..................................................................................................................................79

6.2 CONCEPTOS ASOCIADOS ..........................................................................................................................................80

6.3 ARBOL BINARIO ...........................................................................................................................................................81


DEFINICION ......................................................................................................................................................................82
OPERACIONES BASICAS ................................................................................................................................................82
INSERCIÓN DE DATOS ...................................................................................................................................................88
ELIMINAR UN DATO .......................................................................................................................................................88
BÚSQUEDA DE DATOS ...................................................................................................................................................90

6.4 ÁRBOLES BINARIOS DE EXPRESIONES.................................................................................................................90


CONSTRUCCIÓN A PARTIR DE UNA EXPRESIÓN EN NOTACIÓN CONVENCIONAL.......................................91

6.5 ÁRBOLES EQUILIBRADOS O AVL ...........................................................................................................................92


DEFINICIÓN ......................................................................................................................................................................93
INSERCIÓN EN AVL ........................................................................................................................................................93
IMPLEMENTACIÓN DE LA INSERCIÓN ....................................................................................................................100
BORRADO EN AVL ........................................................................................................................................................103
IMPLEMENTACIÓN DE LA ELIMINACIÓN ...............................................................................................................109

4
ÁRBOLES BINARIOS DE EXPRESIONES.....................................................................................................................113

GRAFOS.................................................................................................................................115
7.1 DEFINICIONES. ............................................................................................................................................................115

7.2 ALMACENAMIENTO DE UN GRAFO EN MEMORIA. ........................................................................................122

7.3 APLICACIONES. ..........................................................................................................................................................126

5
TEMA 1

INTRODUCCION
OBJETIVOS

Conceptuar las diferentes etapas por las que atraviesa el procesamiento de datos desde la abstracción de
los mismos hasta la obtención de los resultados en la computadora.

CONTENIDO

1.1 Estructura de Datos


1.2 Operaciones Sobre Estructuras de Datos

1.1 ESTRUCTURA DE DATOS.


Estructuras de datos y tipos de datos abstractos (TDA)
Un tipo de datos es una colección de valores
Un tipo de datos abstracto (TDA) es un tipo de datos definido de forma única mediante un tipo y un
conjunto dado de operaciones definidas sobre el tipo.
Una estructura de datos es la implementación física de un tipo de datos abstracto.
Debido al proceso de abstracción, el diseño deberá realizarse siguiendo tres pasos fundamentales:
1.- Análisis de datos y operaciones
2.- Elección del Tipo de Datos Abstracto
3.- Elección de la implementación

Tipos de datos básicos

TDA Entero: tiene como tipo el conjunto de números enteros, y como operaciones la suma, resta,
multiplicación y división entera
TDA Real: tiene como tipo el conjunto de números reales y como operaciones la suma, resta
multiplicación y división
TDA Booleano: tiene como tipo el conjunto de valores booleanos True, False y como operaciones las
definidas en el álgebra de Boole (AND, OR, NOT)
TDA Carácter: tiene como tipo el conjunto de caracteres definido por un alfabeto dado y como
operaciones todos los operadores relacionales (<, >, =, >=, <=, <>)

Se denominan tipos de datos escalares a aquellos en los que el conjunto de valores está ordenado y
cada valor es atómico: Carácter, Entero, Real y Booleano.
Se denominan tipos de datos ordinales a aquellos en los que cada valor tiene un predecesor (excepto el
primero), y un único sucesor (excepto el último): Carácter, Entero y Booleano.

Los lenguajes de alto nivel suelen presentar tres funciones adicionales asociadas a los tipos de datos
ordinales: posición (Ord), predecesor (Pred) y sucesor (Suc) de un elemento.

6
Otro tipo de datos son los denominados compuestos, dado que son divisibles en componentes que
pueden ser accedidas individualmente. Las operaciones asociadas a los tipos compuestos o
estructurados son las de almacenar y recuperar sus componentes individuales.

Los TDA compuestos básicos:

TDA Conjunto: colección de elementos tratados con las operaciones unión, intersección y diferencia
de conjuntos.
TDA Arreglo: colección homogénea de longitud fija tal que cada una de sus componentes pueden ser
accedidas individualmente mediante uno o varios índices, que serán de tipo ordinal, y que indican la
posición de la componente dentro de la colección.
TDA Registro: tipo de datos heterogéneo compuesto por un número fijo de componentes denominadas
campos a las que se accede mediante un selector de campo.
El TDA Conjunto no es estructurado ya que no está organizado mediante el modo de acceso a sus
componentes individuales, mientras que el Arreglo y el Registro si lo son. Los registros pueden tener
como campos tipos de datos simples o arreglos o incluso otros registros.
Los TDA básicos son los utilizados con mayor frecuencia, pero además cada problema puede requerir
la definición de varios TDA propios. Por ejemplo, un TDA muy utilizado en aplicaciones informáticas
es el TDA lista definido de la siguiente forma:
TDA lista (o Secuencia): colección homogénea de datos, ordenados según su posición en ella, tal que
cada elemento tiene un predecesor (excepto el primero) y un sucesor (excepto el último) y los
operadores asociados son:
• Insertar: inserta un elemento x, en una posición p de la lista
• Localizar: localiza la posición p en la que se encuentra el dato x
• Recuperar: encuentra el elemento x que esta en la posición p
• Suprimir: elimina de la lista el elemento de la posición p
• Suprimir_dato: elimina de la lista cualquier aparición del elemento x
• Anula: ocasiona que la lista se vacíe
• Primero (Fin): proporciona el primer (último) elemento de la lista
• Imprimir: imprime todos los elementos de la lista en su orden.

En general el término “lista” se utiliza cuando el TDA se implementa sobre memoria principal mientras
que “secuencia” suele reservarse para implementaciones sobre memoria secundaria.
La lista es una estructura dinámica ya que su longitud dependerá del número de elementos que tenga,
aumentará al insertar y se reducirá al suprimir. Ahora bien, la lista puede implementarse de formas muy
diferentes. Una de ellas es mediante arreglos. Así, la lista, que es dinámica independientemente de su
implementación, se realiza mediante una implementación estática.

Estructura

Es un conjunto de elementos entrelazados regidos por una serie de leyes. En general, las estructuras que
nos presenta el mundo real están regidas por las leyes físicas.

Estructura de Datos

Una estructura de datos es una colección organizada de elementos de datos bajo las leyes de la
informática. Estos elementos, o ladrillos, son los tipos de datos, con los cuales se forman las estructuras
de datos que incluyen los diferentes lenguajes:

7
• Binarios
• Enteros
• Reales
• Caracteres
o Doble precisión
o Vectores
o Arreglos bidimensionales
o Arreglos n-dimensionales
o Registros
• Complejos

El tipo de dato determina:

• Los rangos de la variable.


• La cantidad de memoria que se le asigna a la variable.
• Las operaciones que se pueden realizar.

Debido a lo limitado de los lenguajes de alto nivel, los programadores estaban insatisfechos por el nivel
de abstracción que lograban.

Este problema, se ha superado al proveer los nuevos lenguajes con mecanismos que le permiten al
programador construir sus propias abstracciones con base en su necesidad, a través de los tipos de datos
definidos por el usuario.

El enfoque de los nuevos lenguajes, orientados por objetos, es tener un conjunto fijo de estructuras y un
conjunto poderoso de primitivas que permiten su manipulación, brindandole al usuario la oportunidad
de definir datos (atributos) y operaciones (métodos).

Estructura Lógica. Es la estructura que define el usuario a nivel de análisis y parte de diseño, al
relacionar lógicamente los elementos para satisfacer un requerimiento determinado.

Estructura Física. Corresponde a la forma en que a través de un lenguaje de programación se crea la


estructura lógica, en memoria auxiliar.

struct ID_CARRO {
char placa[6];
struct PROPIETARIO prop;
struct CARACTER car;

8
};

struct PROPIETARIO {
char direccion[50];
struct NOMBRE nomb;
};
struct CARACTERISTICAS {
char marca[20];
int modelo[2];
char color[10];
};
struct NOMBRE {
char nombre[10];
char apellido_1[10];
char apellido_2[10];
};

1.2 OPERACIONES SOBRE ESTRUCTURAS DE DATOS.


Son varias las operaciones que se efectúan sobre las estructuras de datos, y una vez establecidas se
definen como funciones.

Función Constructora Son los algoritmos y mecanismos que permiten construir una estructura.
Asigna memoria en forma dinámica o espacios en medios magnéticos.

Función Destructora Son los algoritmos y mecanismos que desasignan memoria y liberan recursos
del sistema.

Función de Acceso Son los algoritmos a través de los cuales se llega a una estructura y sus elementos

Función de Prueba Por medio de la función de acceso se llega a un elemento y se prueba si posee
determinado atributo.

Función de Inserción Permite la inclusión de un elemento en una estructura.

Función de Eliminación Permite la exclusión de un elemento de una estructura.

Función Inversa Las funciones de acceso proveen un nombre o valor. Estas funciones son los
mecanismos o procesos, en que dado un valor o un nombre, se determina la posición del elemento de
dato en la estructura.

9
TEMA 2

PILAS Y COLAS
OBJETIVOS

Emplear y desarrollar aplicaciones empleando estructuras estáticas de datos como apoyo a procesos
más complejos.

CONTENIDO

2.1 Pilas
2.2 Colas
2.3 Colas Circulares
2.4 Aplicaciones de Listas Restringidas
2.5 Ejercicios

En este capítulo se introducen dos tipos de listas, pilas y colas, que se pueden actualizar, solo de una
manera muy limitada. Son estructuras bastante importantes utilizadas en multitud de aplicaciones.

2.1 PILAS.
Una pila es una lista en donde tanto las inserciones como las supresiones se hacen por el mismo
extremo, que se conoce como el tope de la pila.

Por ejemplo, la pila de carritos de los supermercados, porque el último carro que se coloca es el
primero que se saca. Esta propiedad de la pila se conoce como LIFO (Last In First Out; último que
entra primero que sale).

PILA SECUENCIAL

Aquí se trabaja como una lista secuencial de acceso restringido. Para su manejo se requieren dos
apuntadores, uno que indica la posición del último elemento insertado, llamado TOPE de la pila, y otro
denominado BASE que apunta al fondo de la pila. Cuando la pila está vacía, no hay elementos,
BASE=TOPE.

Figura 2.1 Pila, se inserta y se elimina por el mismo extremo. El apuntador TOPE apunta al último
elemento de la pila; el apuntador BASE no apunta a ningún elemento de la pila

10
OPERACIONES CON PILAS

Las operaciones primitivas que se efectúan sobre una pila son:

1. Iniciar la pila (dejarla en condiciones de pila vacía).


2. Probar si la pila está vacía.
3. Acceder al elemento del tope de la pila.
4. Insertar un elemento en el tope de la pila (PUSH).
5. Eliminar el elemento tope de la pila (POP).
6. Destruir la pila.

Para la implementación de esta estructura de datos, se hará uso de un arreglo que aquí llamamos PILA,
de dimensión M. Esta es la estructura estática con la que se trabajan estos algoritmos.

Iniciación de una pila. En el arreglo PILA, se inicia la lista restringida.

Precondición: Que exista el arreglo.


Poscondición: Condición de pila vacía.

INIC_PILA
Inicio
BASE = 0
TOPE = BASE
Fin

Aquí, la base apunta al elemento 0 del arreglo, que como se había determinado, no corresponde a
ningún elemento de la lista.

Prueba de Pila Vacía: En general es importante, para todo tipo de estructura, establecer si se
encuentra vacía, pues el proceso varía dependiendo de esta condición.

Este algoritmo retorna un valor verdadero si la pila está vacía.

Precondición: No hay.
Poscondición: Retorna verdadero cuando no hay elementos en la pila. En caso
contrario retorna el valor falso.

ENTERO PILA_VACIA()
Inicio
Si (TOPE==BASE) Entonces
RETORNA VERDADERO
Sino
RETORNA FALSO
Fin-Si
Fin

Esta rutina se emplea en el algoritmo ELIM_PILA que saca el elemento que apunta el TOPE de la pila.

11
Acceder al Elemento Tope de la Pila: Con esta operación se lee el último elemento de la pila y se
lleva a DATO.

Precondición: Pila válida.


Poscondición: En DATO queda una copia del elemento que apunta el índice TOPE
si hay elementos en la pila, en caso contrario DATO queda indefinido.

ACCE_PILA(DATO,I)
Inicio
I = Verdadero
Si (NO PILA_VACIA()) Entonces
DATO = PILA[TOPE]
Sino
I = Falso
Fin-Si
Fin

Insertar un Dato en la Pila: Se coloca DATO en un nodo que queda en el TOPE de la pila. Es posible
que no se pueda hacer la inserción debido a que no hay nodos disponibles recordemos que con la
variable I se indica si se pudo, o no, hacer la inserción.

Precondición: TOPE < M


Poscondición: I verdadero indica que se hizo la inserción de DATO y el índice
TOPE apunta a DATO.

INSER_PILA(DATO,I)
Inicio
I = Verdadero
Si (TOPE>=M) Entonces
I = Falso
Sino
TOPE = TOPE + 1
PILA[TOPE] = DATO
Fin-Si
Fin

Figura 2.2 Estado de la pila luego de la inserción

La condición de saturación generalmente es un error y significa que el área disponible está llena y que
aun se tratan de colocar más datos en ella. La política común es, en primer lugar, tratar de manejar
dicha condición para superarla, o rechazar la inserción e informar al sistema operacional para una
terminación anormal de la tarea.

12
Eliminar un Elemento de la Pila: En DATO se coloca el elemento que inicialmente apunta al TOPE
de la pila. Al disminuir TOPE el elemento anterior permanece en el área de memoria como basura.

Precondición: Pila válida.


Poscondición: Si se pudo realizar la operación, I verdadero, DATO queda con
elemento que había en el tope de la pila. Si la pila estaba vacía I es falso y DATO
indeterminado.

ALGORITMO ELIM_PILA(DATO,I)
Inicio
I = Verdadero
Si (NO PILA_VACIA()) Entonces
DATO = PILA[TOPE]
TOPE = TOPE - 1
Sino
I = Falso
Fin-Si
Fin

La condición de pila vacía se presenta cuando se trata de obtener un elemento inexistente, la cual no es
una condición de error.

Esta condición se puede considerar en el sentido de que hay una serie de recursos disponibles para
procesar el DATO que se espera, en caso de que no llegue, simplemente se liberan los recursos o se
inicia el proceso de los datos anteriores.

Es semejante a la condición que se presenta cuando se está procesando un archivo secuencial y se llega
al fin del archivo.

Destruir la Pila. Se sacan todos los elementos de la lista.

Precondición: Pila válida.


Poscondición: Pila vacía.

ALGORITMO DEST_PILA
Inicio
I = Verdadero
Mientras I Hacer
ELIM_PILA(DATO,I)
Rutina_usa (Dato)
Fin-M
Fin

En muchas aplicaciones es necesario vaciar la pila, para esto se incluye la rutina apropiada que utiliza
DATO dentro del ciclo.

13
DISTRIBUCIÓN DE PILAS.

En los lenguajes de programación, las subrutinas y los diferentes componentes de los sistemas
operacionales requieren la utilización de varias pilas, las cuales se pueden disponer de muchas formas,
buscando optimizar el uso de la memoria.

Manejo de Dos Pilas y Operaciones Primitivas.

Como se vio en la inserción, el hecho de que haya saturación implica una terminación anormal,
perdiéndose todo lo procesado.

Figura 2.3 Pilas enfrentadas. El área común es todo el arreglo con sus M elementos. La base de la
pila 1 tiene el índice 0 y el índice de la base de la pila 2 es M.

Se debe observar la figura 2.3 y dejar claro cómo se trabajan los índices y a que nodos apuntan. En los
siguientes algoritmos se incluye la variable IP (indicador de pila) que dirá sobre cual de las dos pilas se
debe realizar la operación.

Iniciación de las Pilas.

Precondición: Arreglo válido.


Poscondición: Las dos pilas en condición de pila vacía.

INIC2PILAS
Inicio
BASE1 = 0; TOPE1 = BASE1
BASE2 = M; TOPE2 = BASE2
Fin

Prueba de Pila Vacía

Precondición: IP solo puede timar valores 1 o 2.


Poscondición: No hay cambio en la pila. Vacía queda en V si la pila IP está vacía
sino vacía queda en F.

ALGORITMO 2PILASVAC(IP,VACIA)
Inicio
Si (IP=1) Entonces
Si (BASE1 = TOPE1)
VACIA = V
Sino
VACIA = F

14
Fin-Si
Sino
Si (BASE2 = TOPE2)
VACIA = V
Sino
VACIA = F
Fin-Si
Fin-Si
Fin

Acceder al Elemento de una de las Dos Pilas

Precondción: IP solo puede tomar valores de 1 o 2.


Poscondición: Si hay datos en la pila IP, I es falso, y en Dato queda copia del
elemento indicado por el tope de la pila IP, sino I es verdadero.

ACC2PILAS(DATO,IP,I)
Inicio
I = V
2PILASVAC(IP,VACIA)
Si (VACIA) Entonces
I = F
Sino
Si (IP=1) Entonces
DATO = PILA[TOPE1]
Sino
DATO = PILA[TOPE2]
Fin-Si
Fin-Si
Fin

Insertar un Dato en una de las Dos Pilas.

Precondición: IP es 1 o 2, no hay saturación mientras ( TOPE1+1) < TOPE2.


Poscondición: Inserción de DATO en una de las dos pilas o la imposibilidad de
hacerlo, I=FALSO.

ALGORITMO INSER2PILAS(DATO,IP,I)
Incio
I = F
Si ((TOPE1+1) < TOPE2) Entonces
Si (IP=1) Entonces
TOPE1 = TOPE1 + 1
PILA[TOPE1] = DATO
Sino
TOPE2 = TOPE2 - 1
PILA[TOPE2] = DATO
Fin-Si
Sino
I = V
Fin-Si
Fin

15
Eliminar un Elemento de una de las Pilas

Precondición: IP solo puede tomar los valores 1 o 2.


Poscondición: Se elimina el elemento tope de pila IP.

ALGORITMO ELIM2PILAS(DATO,IP,I)
Inicio
I = V
2PILASVAC(IP,VACIA)
Si (NO VACIA) Entonces
Si (IP = 1) Entonces
DATO = PILA[TOPE1]
TOPE1 = TOPE1 - 1
Sino
DATO = PILA[TOPE2]
TOPE2 = TOPE2 + 1
Fin-Si
Sino
I = F
Fin-Si
Fin

Destruir una de las Pilas.

Precondición:
Poscondición: Se elimina el elemento tope de pila IP.

ALGORITMO DESTR2PILAS(IP)
Incio
Si (IP = 1) Entonces
Mientras I Ejecute
ELIM_2PILAS(DATO,IP,I)
Rutina_Usa(Dato)
Fin-M
Sino
Mientras I Ejecute
ELIM_2PILAS(DATO,IP,I)
Rutina_Usa(Dato)
Fin-M
Fin-Si
Fin

16
2.2 COLAS.
Es una lista de proceso restringido en la cual las inserciones se hacen por un extremo llamado "último"
y las eliminaciones se hacen por el otro extremo llamado "delantero". Por ejemplo, los aviones que
esperan despegar de un aeropuerto forman una cola, el que llega a la pista queda de último y el que va a
despegar está de delantero en la cola. Se dice que una cola tiene política FIFO(First In, First Out) El
primer elemento en entrar será el primero en salir.

COLA SECUENCIAL

Aquí se trabaja la cola como una lista secuencial de acceso restringido, dentro del arreglo COLA. Para
su manejo se requieren dos índices, ULTIMO que indica el último elemento insertado en la cola, y
DELANTERO que indica el primer elemento de la cola.

Figura 2.4 Cola, se inserta por el último y se suprime por delante. El apuntador U, último, apunta al
último elemento insertado. El apuntador D, delantero, apunta al primer elemento en la cola

OPERACIONES CON COLAS

Sobre una cola se pueden efectuar las siguientes operaciones primitivas, similares a las operaciones de
la pila:

1. Iniciar una cola


2. Probar si la cola está vacía
3. Acceder al elemento delantero de la cola
4. Insertar un elemento en la cola
5. Eliminar el elemento delantero de la cola
6. Destruir la cola

INICIAR COLA.

Se tiene un arreglo COLA asignado para almacenar la cola, con M posiciones disponibles.

Precondición: Arreglo válido


Poscondición: Se tiene condición de cola vacía

INIC-COLA
Inicio
D = 0
U = D
Fin

17
PROBAR SI LA COLA ESTÁ VACÍA

Precondición: Arreglo válido


Poscondición: Si la cola está vacía retorna verdadero, sino falso.
ENTERO COLA_VACIA()
Inicio
Si (D = 0) Entonces
RETORNA V
Sino
RETORNA F
Fin-Si
Fin

ACCEDER A UN ELEMENTO EN LA COLA

Precondición: Arreglo válido


Poscondición: Se saca en DATO el elemento que indica D, sino I es falso.
ACCED-COLA(DATO,I)
Inicio
I = V
Si (NO COLA_VACIA()) Entonces
DATO = COLA[D]
Sino
I = F
Fin-Si
Fin

INSERTAR UN ELEMENTO EN LA COLA.

Se coloca DATO en el nodo siguiente al último, quedando como último. Es posible que no se pueda
hacer la inserción debido a que no hay espacio. La variable I indica si se pudo o no hacer la inserción.

Precondición: Que exista la cola


Poscondición: La cola queda con un elemento adicional DATO, que queda como
último elemento de la cola, o hay terminación normal.
INSER-COLA(DATO,I)
Inicio
I = V
Si (U > M) Entonces
I = F
Sino
Si (COLA_VACIA()) Entonces
D = 1
U = D
Sino
U = U + 1
Fin-Si
COLA[U] = DATO
Fin-Si
Fin

18
ELIMINAR UN ELEMENTO DE LA COLA.

Se elimina el elemento que está de delantero en la cola.

Precondición: Que haya cola.


Poscondición: Se elimina el primer elemento de la cola, si existe, sino, I = falso.
ELIM-COLA(DATO,I)
Inicio
Si (COLA_VACIA()) Entonces
I = F
Sino
Dato =Cola [D]
I = V
Si (D == U) Entonces
U = 0
D = U
Sino
D = D + 1
Fin-Si
Fin-Si
Fin

DESTRUIR LA COLA

Precondición: Cola válida.


Poscondición: Cola vacía.
DESTRU-COLA(IP)
Inicio
I=V
Mientras I Ejecute
ELIM-COLA(DATO,I)
Rutina-Usa(Dato)
Fin-M
Fin

2.3 COLAS CIRCULARES.


Observemos que en el numeral anterior, al hacer eliminaciones, se va corriendo el apuntador D, y las
inserciones también van desplazando el apuntador U, llegando incluso a condiciones de saturación,
cuando hay memoria desperdiciada. Una solución a este inconveniente es formar una cola circular. Es
decir, hacer un manejo de índices.

19
Figura 2.5 Después de que U = M se U = 1.

Figura 2.6 Si se presenta una inserción, hay saturación.

Los algoritmos de iniciación, prueba, acceso y destrucción de la cola son similares a los del caso
anterior. Los de inserción y eliminación varía por la condición inicial: U=0 U=D; y por la condición de
saturación: D=U.

INSERCIÓN EN COLA CIRCULAR

Aunque es similar al de inserción en colas comunes, se debe considerar, cuando U = M, para enviarlo a
0. También se debe tener en cuenta la nueva condición de saturación.

Precondición:Que haya cola.


Poscondición: D apunta al nuevo nodo, si hay espacio, sino, I =falso.
INSER-COL-CIR(DATO,I)
Inicio
I = V
Si (COLA_VACIA() Entonces
D = 1
U = 1
COLA[U] = DATO
Sino
U = U+1
Si (U = M) Entonces
U = 1
Sino
Fin-Si
Si (D=U) Entonces
I = F
Sino
COLA[U] = DATO
Fin-Si
Fin-Si
Fin

ELIMINAR EL NODO DELANTERO DE LA COLA

20
Figura 2.7 (a) Condición inicial crítica
(b) Condición final una vez se ha eliminado el nodo delantero

Precondición: Que haya cola.


Poscondición: U apunta al último elemento de la cola, si hay elementos, sino,
queda la cola en condición de cola vacía.
ALGORITMO ELIM-COLA-CIR(DATO,I)
Inicio
I = V
Si (COLA_VACIA()) Entonces
I = F
Sino
DATO = COLA[D]
Si (D=U) Entonces
D = 0
U = D
Sino
D = D + 1
Si (D = M) Entonces
D = 1
Sino
Fin-Si
Fin-Si
Fin-Si
Fin

21
2.4 APLICACIONES DE LISTAS RESTRINGIDAS.
Son muchas las aplicaciones de estas listas restringidas, en especial en sistemas operativos,
compiladores e interpretadores. Vamos a trabajar una aplicación universal, la evaluación de una
expresión.

ALGORITMO DE NOTACIÓN INFIJA A POSFIJA

La gran mayoría de lenguajes representa las expresiones aritméticas en la llamada forma INFIJA, en la
cual los operadores se encuentran dentro de los operandos. Otra manera de hacerlo es usando notación
POSFIJA o POLACA. En este tipo de notación los operadores aparecen después de los operandos, así
se facilita la evaluación de la expresión.

Vamos a suponer que se tienen los siguientes operadores, con sus respectivas prioridades.

... Operador Prioridad


Asignación = 0
Suma, Resta +,- 1
Multiplicación,
*,/ 2
División
Potencia ^ 3

El algoritmo analiza carácter a carácter la expresión infija, de izquierda a derecha y sigue el siguiente
manejo:

1. Todos los operandos pasan directamente a una cola salida.


2. Los operadores van a una pila. Su posición depende de los que haya en el tope de la pila:

Si el operador que entra, tiene mayor prioridad que el operador que está en el tope de la pila, se
coloca en el tope de la pila.
Si el operador que entra es de prioridad menor o igual al del tope de la pila, la pila se desocupa
enviando los operadores a la cola, hasta que el operador tenga mayor prioridad al del tope de la
pila.

3. Si es un paréntesis izquierdo "(", se manda a la pila.


4. Si es un paréntesis derecho ")", se desocupa la pila hasta encontrar el paréntesis izquierdo y se
mandan los operadores a la cola de salida.
5. Desocupar la pila.

La expresión infija que se va a convertir a posfija, se encuentra en un arreglo X, con N posiciones,


donde X[J], J=1,...,N; es una letra (operando), un paréntesis izquierdo o derecho, o uno de los
operadores = , +, -, *, /, ^

Observaciones sobre la expresión infija.

1. Se supone que la entrada es una expresión infija válida.

22
2. Los operandos consisten de una sola letra
3. No se espera la entrada de constantes ni de referencia a funciones
4. No deben aparecer funciones unarias.

Se define una función de prioridad P:

P( ) ) = -1 P(-) = 1
P(( ) = -1 P(*) = 2
P( = ) = 0 P(/) = 2
P(+) = 1 P(^) = 3

ALGORITMO INF-A-POSF
Precondición: Únicamente los caracteres ya definidos.
Poscondición:

Comience
CREA_PILA
D = 0
TOPE = 0
INSER-PILA( ,I)
Si (I) Entonces
J = 1
K = 1
Mientras (K < N) Ejecute
Si (X[K] = LETRA) Entonces
Y[J] = X[K]
J = J+1
Sino
Si (X[K] = ")" ) Entonces
Mientras (PILA [TOPE]) <> "(" ) Ejecute
Y[J] = PILA[TOPE]
J = J+1
TOPE = TOPE - 1
Fin-Mientras
TOPE = TOPE - 1
Sino
Mientras (P(X[K])<= P(PILA[TOPE]) Ejecute
Y[J] = PILA[TOPE]
J = J+1
TOPE = TOPE-1
Fin-Mientras
TOPE=TOPE+1
PILA[TOPE] = X[K]
Fin-Si
Fin-Si
K=K+1
Fin-Mientras
Mientras [(PILA[TOPE]) <>(I)] Ejecute
Y[J] = PILA[TOPE]
J = J+1
TOPE = TOPE -1
Fin-Mientras

23
Sino
Fin-Si
Termine

ALGORITMO DE EVALUACIÓN EN NOTACIÓN POSFIJA

En este caso se tiene una expresión aritmética en notación posfija se encuentra en un arreglo X. Cada
X(J), J=1,...N., puede ser una letra o un operador (<= , +, -, *, /, ).

Los operandos se van guardando en una pila hasta cuando se encuentra un operador, que hace que se
ejecute esa operación entre los dos nodos operandos que se tengan en los nodos superiores de la pila.

El resultado se guarda en el tope de la pila.

ALGORITMO EVAL-POL
Precondición:
Poscondición:

Comience
TOPE = 0
K = 1
Mientras (K<=N) Ejecute
Si (X[K] = OPERANDO) Entonces
TOPE = TOPE +1
PILA[TOPE] = X[K]
Sino
AUX1 = PILA[TOPE]
TOPE = TOPE-1
AUX2 = PILA[TOPE]
AUX3 = AUX2 (X[K]) AUX1
PILA[TOPE] = AUX3
Fin-Si
K = K +1
Fin-Mientras
Termine

Evaluación de una expresión

Vamos a seguir los dos algoritmos anteriores para la evaluación de la siguiente expresión: G = ((A-
B)*C)+(D/(E ^F))

1. Conversión a Posfija.

X COLA PILA
. .
1 G
2 G =
3 G =(

24
4 G =((
5 GA =((
6 GA =((-
7 GAB =((-
8 GAB- =(
9 GAB- =(*
10 GAB-C =(*
11 GAB-C* =
12 GAB-C* =+
13 GAB-C* =+(
14 GAB-C*D =+(
15 GAB-C*D =+(/
16 GAB-C*D =+(/(
17 GAB-C*DE =+(/(
18 GAB-C*DE =+(/(^
19 GAB-C*DEF =+(/(^
20 GAB-C*DEF^ =+(/
21 GAB-C*DEF^/ =+
22 GAB-C*DEF^/+
23 GAB-C*DEF^/+=

2. Evaluación de la notación Posfija, donde A=4, B=1, C=5, D=64 , E=2, F=5

X COLA PILA
1 G G
2 GA G4
3 GAB G41
4 G3 G3
5 G3C G35
6 G 15 G 15
7 G 15 D G 15 64
8 G 15 D E G 15 64 2
9 G 15 D E F G 15 64 2 5
10 G 15 D 32 G 15 64 32
11 G 15 2 G 15 2
12 G 17 G 17
13 17 17

25
TEMA 3

ARCHIVOS, REGISTROS Y CAMPOS


OBJETIVOS

Estructurar la información con el soporte fundamental para el almacenamiento externo de datos.

Aprovechar de una forma eficiente el medio de almacenamiento secundario de datos.

CONTENIDO
3.1 Archivos
3.2 Registros y Campos
3.3 Archivos Secuenciales y Directos

3.1 ARCHIVOS
Un archivo es un conjunto de registros relacionados entre sí, que forman una entidad, que se puede
identificar y manipular de modo unitario.

Un archivo almacena grandes volúmenes de información en unidades externas (Floppy, HD, Cintas ..).

3.2 TIPOS DE ARCHIVOS.


ARCHIVOS SECUENCIALES.

Son aquellos en los que los registros se graban unos a continuación de otros y el acceso a un registros
determinado, necesita forzosamente el paso por todas los registros anteriores.

CAMPOS DE LONGITUD VARIABLE.

Se realiza este tipo de definición de campos de longitud variable, con el objetivo principal de
ahorro de memoria, ya que con campos de longitud fija se realiza un desperdicio de memoria.
Para la implementación de este tipo de campos se lo realiza con archivos de tipo texto.
Existen dos mecanismos de implementación:

USO DE DELIMITACIONES

DELIMITADOR DE CAMPOS :

Existe un símbolo específico para delimitar los campos ( , ; *)

DELIMITADOR DE REGISTROS :

Símbolo diferente al delimitador de campo.

Ejemplo :

26
Nombre Dirección Edad Lista de Materias

$CLAUDIA, BALLIVIÁN@ 17, SIS-2204, SIS-1103$ANA, LA PAZ@17, SIS-1103, MAT- 2207

SUBCAMPO DE LONGITUD

Registro con un numero constante de campos.

Ejemplo :

Nombre Dirección Edad Lista de Materias

7 CLAUDIA, 9 BALLIVIÁN, 2 17, 8 SIS-2204, 8 SIS-1103, 8 MAT- 2207

Para distinguir algunos registros que contienen los mismos campos se recurre a un campo que contiene
información única o diferente que se le llama clave.

ARCHIVOS DIRECTOS.

Son aquellos en los que los registros se pueden localizar mediante una dirección. El acceso a los
registros es directo.

CAMPOS DE LONGITUD FIJA.

Los campos definidos de esta manera son almacenados en memoria con una longitud fija de datos,
sin importar si se realiza el uso parcial o completo del campo.

OPERACIONES SOBRE ARCHIVOS

Creación. Consiste en la grabación, por primera vez, en un soporte de los registros de un determinado
archivo.

Apertura y Cierre. Un archivo debe poseer las condiciones necesarias para ser abierto, manipularse y
tener acceso a los registros. Para evitar deterioros de información el archivo es cerrado durante el
tiempo que no se utiliza y no debe permitir su acceso.

Borrado. Es la eliminación de todo el archivo, se puede hacer prohibiendo definitivamente su acceso o


destruyendo la información que hay en el.

Ordenamiento o Clasificación. Es lograr una nueva disposición en el soporte de los registros de un


archivo, con una secuencia de ubicación determinada por el valor de sus campos. Este orden puede ser
ascendente o descendente.

Copiado o Duplicación. Consiste en crear un archivo idéntico a otro y existencte, sin que se afecte el
original.

27
Concatenación. Consiste en obtener de dos archivos, con la misma estructura, un archivo que contenga
ambos, de manera que queden uno a continuación del otro.

Intersección. Consiste en formar un único archivo mediante los registros comunes de dos archivos
distintos.

Función o Intercalación. Llamada mezcla, consiste en obtener de dos archivos ordenados por un
mismo campo y con la misma estructura, otro archivo que contenga los registros de ambos y mantenga
su ordenación.

Partición. Consiste en dividir un archivo en dos, de acuerdo a alguna característica determinada de sus
registros.

Compactación o Empaquetamiento. Consiste en reorganizar todos los registros de un archivo,


ocupando todos los huecos de memoria existentes entre ellos, dejen libres fuera de la parte de soporte
ocupada por el archivo todos los espacios correspondientes que hallan sido eliminados del mismo.

3.3 REGISTROS Y CAMPOS.


REGISTROS.

Un registro es un conjunto organizado de datos del mismo o diferente tipo, que estan relacionados entre
sí por contener información relativa a una entidad particular y superior, de la que forman parte y los
unifica.

Los registros están compuestos por campos. Un campo es una unidad mínima de información, dentro
del registro, independiente de las demás. Representa un concepto global en la finalidad unitaria del
registro y se caracteriza por el tipo de datos asociados y el tamaño de memoria que necesita para su
almacenamiento. El campo se puede dividir en subcampos.

CAMPOS.

Los componentes de un registro se denominan campos, los campos son los atributos de los
objetos de estudio, cada campo tiene los siguientes atributos.

• Nombre ( identificador ) de campo que es elegido por el programador.


• Contenido o valor.
• Ubicación dentro del registro.
• Longitud o dimensión.

TIPOS DE CAMPOS.

Existen tres tipos de campos

• Longitud fija.
• Longitud variable
• Campos múltiples

28
TIPOS DE REGISTROS

Registro Lógico. Cada uno de los componentes de un archivo que posee una estructura para almacenar
información referente a un tema general del archivo. Diseñado por el programador.

Registro Físico. Información que el sistema puede transferir como una unidad, en una sola operación de
entrada o salida. Registros según la longitud de sus campos:

Registros de Longitud Fija. Su tamaño no varía. En cuanto a su estructura interna, el registro puede
tener el mismo número de campos de igual longitud cada uno, o diverso número de campos de
diferentes longitudes. En ambos casos la suma de las longitudes de los campos es la misma para cada
registro.

Registros de Longitud Variable. Su tamaño varía de un registro a otro. Su longitud variable puede estar
determinada por un valor máximo o también sin ninguna limitación. Entre las agrupaciones
estructuradas de registros se tienen los archivos de datos y las bases de datos.

OPERACIONES SOBRE REGISTROS.

Aquí se analizan las operaciones que solo afectan a algunos registros. Todas estas operaciones
necesitan la operación de búsqueda como preliminar para localizar los registros deseados.

Recuperación (Consultas y Listados). Consiste en acceder a los registros de un archivo para obtener
una información determinada, almacenada en el.

• Consultas: Se accede a uno o varios registros determinados de un archivo y se visualiza el


contenido de sus campos, por impresora o pantalla.
• Listados: La visualización de la información es una lista ordenada.

Actualización o Mantenimiento. Consiste en introducir nuevos datos en el archivo o en eliminar o


modificar los ya existentes.

• Inserciones: Se introducen uno o varios registros en un archivo, ya creado, al final o en


cualquier lugar del mismo.
• Borrados: Se eliminan uno o varios registros del archivo, borrando su contenido definitivamente
o prohibiendo su acceso.
• Modificaciones: Consiste en cambiar los datos de uno o varios campos de cualquier registro de
archivo.

29
TEMA 4

TRATAMIENTO DE ARCHIVOS
OBJETIVOS

Desarrollar las operaciones básicas sobre la información almacenada en un medio secundario.

Desarrollar nuevos mecanismos de procesamiento de acuerdo a las características del problema.

CONTENIDO
4.1 Introducción
4.2 Operaciones en Archivos
4.3 Partición de Archivos
4.4 Mezclas de Archivos
4.5 Métodos Ordenación Externa

4.1 INTRODUCCION
Un archivo es una colección de registros, donde cada registro esta conformado por un conjunto de
campos.

El objetivo principal del siguiente tema es realizar las siguientes operaciones para el tratamiento de
archivos:

1. Almacenamiento de información.
2. Recuperación de información.
3. Actualización de la información.

Se hace énfasis en la recuperación de la información, debido a que esta es imprescindible para el


usuario, para contar con información en forma inmediata, para lo cual se toca el tema de métodos de
ordenación externa.

4.2 OPERACIONES SOBRE ARCHIVOS


Las operaciones básicas sobre archivos son:

1. Adición de datos
2. Eliminación de datos
3. Consultas
4. Búsquedas

Existen otras operaciones complejas, las cuales son:

1. Partición de Archivos
2. Mezcla o fusión de Archivos

30
Estas últimas son operaciones auxiliares, necesarias para los métodos de ordenación externa.

ADICION DE DATOS

Una de las tareas mas comunes en archivos es la adición de datos, se puede añadir datos de dos
maneras a un archivo:

1. Adición de datos en desorden


2. Manteniendo el orden del archivo

ADICION DE DATOS EN DESORDEN (al final).

Pasos a realizar para añadir un registro en un archivo:


1. Leer Dato.
2. Buscar Dato en el Archivo.
3. Si existe entonces:
mostrar ' Ya Existe '.

Si no :
Añadir el dato al final del Archivo

ADICION DE DATOS EN ORDEN

Para añadir un registro manteniendo el orden del archivo, es necesario el uso de un archivo auxiliar.

Se deben seguir los siguientes:

31
ELIMINAR DATOS

Se puede eliminar datos de dos maneras:

1. Eliminar lógicamente
2. Eliminara físicamente

FÍSICAMENTE:

En este tipo de eliminación es necesario usar un archivo Auxiliar, por lo que este proceso es lento, y
por lo tanto no es usado con frecuencia.

LOGICAMENTE:

Este tipo de eliminación ahorra tiempo cuando se usa grandes volúmenes de información. Ya que se
cuenta con un campo adicional, que permite marcar el registro como eliminado.

32
Muchas aplicaciones usan primeramente la eliminación lógica, y al finalizar el día utilizan la
eliminación de física. Esto por ser más rápida la eliminación lógica que la eliminación física.

CONSULTAS DE DATOS

Se recupera la información sin alterar el estado del registro, para lo cual debe existir un criterio de
selección de la información.

CRITERIOS DE SELECCIÓN

Consulta Simple:

Cuando la clave del registro es específica y hace referencia a un solo registró.


Ejemplo:

Mientras no eof (F) y reg <= clave hacer


Leer (F,reg)
SI Nombre = 'Veronica' ENTONCES
......
FIN SI
Fin mientras

Consultas con rango:

El valor de la clave especificada hace referencia a un conjunto o rango de registros.


Ejemplo :

Mientras no eof (F) y reg <= clave hacer


Leer (F,reg)
SI Edad > 17 ENTONCES
......
FIN SI
Fin mientras

Consulta funcional:

La clave hace referencia a valores que responden, a la evaluación de un proceso o fusión.


Ejemplo:

Mientras no eof (F) y reg <= clave hacer


Leer (F,reg)
SI Edad = prom(Edad) ENTONCES
......
FIN SI

33
Fin mientras

Consulta lógicas:

Una combinación de las tres anteriores por medio de operaciones logicas.


Ejemplo:

Mientras no eof (F) y reg <= clave hacer


Leer (F,reg)
SI Edad = prom(Edad) or Nombre ='Martha' ENTONCES
......
FIN SI
Fin mientras

BUSQUEDA DE DATOS

Existen dos formas de búsqueda de datos:

1. Secuencial en un archivo ordenado


2. Secuencial en un archivo desordenado

BÚSQUEDA SECUENCIAL EN UN ARCHIVO ORDENADO

Se realiza el recorrido de los registros de archivo hasta el incumplimiento de una condición o que
finalice el archivo.

Ejemplo: Realizar la búsqueda del registro, donde Dato='MARIA'.

Inicio
Leer Clave
Abrir (F,Lectura)
Leer (F,reg)
Mientras no eof (F) y reg <= clave hacer
Leer (F,reg)
Fin mientras
Si reg=clave Entonces
Mostrar " Existe el dato"
Si no
Mostrar "No existe el dato"
Fin si
Cerrar (F)
Fin

34
BÚSQUEDA SECUENCIAL EN UN ARCHIVO DESORDENADO

Se realiza el recorrido de los registros hasta encontrar el registro o hasta que se finalice el archivo.

Ejemplo: Realizar la búsqueda del registro, donde Dato='MARIA'.

ALGORITMO
Inicio
Leer Dato
Abrir (F,Lectura)
Leer (F,reg)
Mientras no eof (F) y reg <> clave hacer
Leer (F,reg)
Fin mientras
Si reg=clave Entonces
Mostrar " Existe el dato"
Si no
Mostrar "No existe el dato"
Fin si
Cerrar (F)
Fin

4.3 PARTICION DE ARCHIVOS


A partir de un archivo se genera dos o más archivos de trabajo

Existen tres tipos de partición de archivos:

1. Partición por el contenido


2. Partición por una secuencia ' P ' dada.
3. Partición por secuencias ordenadas.

35
PARTICION POR CONTENIDO

Se debe establecer un criterio de partición, para determinar que registros de F1 se destinan al archivo
F2.

Donde el archivo F1 es solo lectura y el archivo F2 para escritura.

Ejemplo: Crear un archivo llamado CARRERA seleccionando Clave = 'SIS' del Archivo FNI.

ALGORITMO
Inicio
Leer Clave
Abrir FNI (Lectura)
Abrir Carrera (Escritura)
Mientras no eof (FNI) Hacer
Leer (FNI, Reg)
Si Reg = Clave Entonces
Grabar (Carrera, Reg)
Fin si
Fin Mientras
Cerrar (FNI)
Cerrar (Carrera)
Fin

PARTICION POR UNA SECUENCIA " P " DADA

Se establece un numero entero P que índica las secuencias para realizar la partición. Se copia 'P'
registros de Arch a Arch1, luego los siguientes 'P' registros de Arch a Arch2, esto se repite hasta
terminar de leer el archivo Arch

Ejemplo:
Realizar la partición del archivo ARCH en dos archivos ARCH1 y ARCH2, utilizando la secuencia de
partición (P = 2).

36
ALGORITMO
Inicio
Leer (P)
Abrir Arch(Lectura)
Abrir Arch1(Escritura)
Abrir Arch2(Escritura)
Mientras no eof (Arch) Hacer
Copiar_Secuencia(Arch, Arch1, P)
Si no eof (Arch) Entonces
Copiar_Secuencia(Arch, Arch2, P)
Fin si
Fin Mientras
Cerrar (Arch)
Cerrar (Arch1)
Cerrar (Arch2)
Fin

Copiar_Secuencia (Var x, y : Archivo; P: entero)


Inicio
Cont = 0
Mientras (no eof (x)) y (cont < P ) Hacer
Leer (x, Reg)
Grabar (y, Reg)
Cont = Cont +1
Fin mientras
Fin

PARTICIÓN DE ARCHIVOS POR TRAMOS ORDENADOS

Se toma primeramente un tramo ordenado del archivo C y se copia al archivo A, luego se toma otro
tramo ordenado del archivo C para copiarlo al archivo B este proceso se repite hasta que finalice de leer
todo el archivo C.

Ejemplo: Particionar el archivo C en dos archivos A y B por secuencias ordenadas.

ALGORITMO
Inicio
Abrir A (Lectura)
Abrir B (Lectura)
Abrir C (Escritura)
Mientras no eof (C) Hacer
Copiar_Tramo (C, A )
Si no eof (C) Entonces
Copiar_Tramo (C, B )

37
Fin si
Fin Mientras
Cerrar (A)
Cerrar (B)
Cerrar (C)
Fin

Copiar_Tramo (Var x, y : Archivo)


Inicio
Repetir
Copiar_Dato ( x, y )
Hasta Fin_Tramo
Fin

Copiar _Dato ( Var x, y :Archivo)


Inicio
Si eof (x) Entonces
Fin_Tramo = TRUE
Si no
Leer (x, Reg)
Grabar (y, Reg)
Si eof (x) Entonces
Fin_Tramo = TRUE
Si no
Pos = File Pos (x)
Leer (x, Reg1)
Seek (x, Pos)
Fin_Tramo = Reg > Reg1
Fin si
Fin si
Fin

4.4 MEZCLAS DE ARCHIVOS


El proceso de unir dos o más archivos se le denomina mezcla de archivos.

Existen tres tipos al igual que en particiones:

1. Mezcla por Contenido Total.


2. Mezcla por Secuencias " P ".
3. Mezcla por Secuencias Ordenadas.

38
MEZCLA POR CONTENIDO TOTAL

Se procede a la unión de dos archivos A, B en un archivo C, este proceso se los realiza primeramente
copiando toda la información de A al C y posteriormente B al C.

Ejemplo:
Mezclar los Archivos A, B en un tercer archivo C.

ALGORITMO
Inicio
Abrir A (Lectura)
Abrir B (Lectura)
Abrir C (Escritura)
Mientras no eof (A) Hacer
Leer (A, Reg)
Grabar (C, Reg)
Fin Mientras
Mientras no eof (B) Hacer
Leer (B, Reg)
Grabar (C, Reg)
Fin Mientras
Cerrar (A)
Cerrar (B)
Cerrar (C)
Fin

MEZCLA POR SECUENCIAS " P "

Se establece un numero entero 'P', que indica las secuencias para realizar la mezcla de dos archivos. El
resultado de la mezcla es una secuencia ordenada de datos.

Ejemplo: Realizar la Mezcla de A, B en un tercer archivo C, utilizando las secuencias P = 2 para


realizar dicha operación.

39
ALGORITMO
Inicio
Leer (P)
Abrir A (Lectura)
Abrir B (Lectura)
Abrir C (Escritura)

Mientras no eof (A) y no eof (B) Hacer


Mezclar_SecP
Fin Mientras
Mientras no eof (A) Hacer
Copiar_SecP (A, C, P)
Fin Mientras
Mientras no eof (B) Hacer
Copiar_SecP (B, C, P)
Fin Mientras

Cerrar (A)
Cerrar (B)
Cerrar (C)
Fin

Mezclar_SecP
Inicio
SecA =0; SecB=0
Repetir
PosA = FilePos(A);Leer(A, RegA);Seek (A, PosA)
PosB = FilePos(B);Leer(B, RegB);Seek (B, PosB)

Si RegA < RegB Entonces


Copiar_SecP (A, C,P)
SecA=SecA+1
Si SecA=P Entonces
Copiar_SecP (B, C,P-SecB)
SecB =P
Fin Si
Si no
Copiar_SecP (B, C,P)
SecB=SecB+1
Si SecB=P Entonces
Copiar_SecP(A, C,P-SecA)
SecA =P
Fin si
Fin si
Hasta SecA=P y SecB=P
Fin

Copiar_SecP (Var x, y : Archivo; P : Entero)


Inicio
Cont = 0
Mientras no eof (x) y Cont < P Hacer
Leer (x, Reg); Grabar (y, Reg)
Cont = Cont +1
Fin Mientras
Fin

40
MEZCLA POR TRAMOS ORDENADAS

Se realiza la mezcla los archivos A y B en el archivo C, tomando tramos ordenados. Es decir se realiza
la mezcla del primer tramo ordenado de A con la de B.

Ejemplo: Realizar la mezcla A y B en un tercer archivo C, utilizando las secuencias ordenadas.

ALGORITMO
Inicio
Abrir A (Lectura)
Abrir B (Lectura)
Abrir C (Escritura)
Mientras no eof (A) y no eof (B) Hacer
Mezclar_Tramo
Fin Mientras
Mientras no eof (A) Hacer
Copiar_Tramo (A, C)
Fin Mientras
Mientras no eof (B) Hacer
Copiar_Tramo (B, C)
Fin Mientras
Cerrar (A)
Cerrar (B)
Cerrar (C)
Fin

Mezclar_Tramo
Inicio
Repetir
PosA = FilePos (A)
Leer (A, RegA)
Seek (A, PosA)

PosB = FilePos (B)


Leer (B, RegB)
Seek (B, PosB)

Si Reg1 < Reg2 Entonces


Copiar_Dato (A, C)
Si Fin_Tramo Entonces
Copiar_Tramo (B, C)
Fin Si

41
Si no
Copiar_Dato (B, C)
Si Fin_Tramo Entonces
Copiar_Tramo (A, C)
Fin si
Fin si
Hasta Fin _Tramo
Fin

Copiar_Tramo ( Var x, y : Archivo)


Inicio
Repetir
Copiar_Dato (x, y)
Hasta Fin_Tramo
Fin

Copiar_Dato (Var x, y: Archivo)


Inicio
Si eof (x) Entonces
Fin_Tramo = TRUE
Si no
Leer (x, Reg)
Grabar (y, Reg)
Si eof (x) Entonces
Fin_Tramo = TRUE
Si no
Pos = File Pos (x)
Leer (x, Reg1)
Seek (x,Pos)
Fin_Tramo = Reg > Reg1
Fin si
Fin si
Fin

4.5 ORDENACIÓN EXTERNA


Debido a la limitación en memoria interna y a la enorme información que es almacenada en los
archivos, no es posible utilizar los métodos de ordenación interna. Para lo cual existen distintos
métodos de ordenación externa exclusivos que son las siguientes:

• Ordenación por Mezcla Directa.


• Ordenación Von Newman.
• Ordenación por Mezcla Equilibrada.
• Ordenación por Dígitos.

Todos estos métodos hacen el uso de archivos auxiliares, para realizar el proceso de ordenación de
archivos.

ORDENACIÓN POR MEZCLA DIRECTA

El método solo funciona con archivos donde su longitud sea múltiplo de 2n, hace el uso de los
siguientes archivos:

42
C Archivo a ordenar
A,B Archivos auxiliares

Se deben seguir los siguientes pasos para ordenar:

1. Partir el archivo C en la mitad, copiar la primera mitad del archivo C en el archivo A, y la otra
mitad en el archivo B.
2. Mezclar los archivos auxiliares A y B por secuencias de 2n. Donde: n = 0,1,2,3...
3. Repetir los pasos 1 y 2 hasta que la secuencia sea mayor que la mitad del archivo a ordenar
(secuencia{2n}> long(C)/2)

Ejemplo:

Ordenar los siguientes datos.

ALGORITMO
Inicio
Sec = 1
Abrir C (Lectura)
Repetir
Abrir B (Escritura)
Abrir A (Escritura)
Seek (C, 0)
Particionar
Seek (A, 0); Seek (B, 0); Seek (C, 0)
Mezclar

43
Cerrar A; Cerrar B
Sec = Sec * 2
Hasta Sec > (Filesize (C) Div 2)
Cerrar C
Fin

Particionar
Inicio
Max = Filesize (C) Div 2
Para J = 1 Hasta Max Hacer
Leer C, Reg
Grabar A, Reg
Fin Para
Para J = 1 Hasta Max Hacer
Leer C, Reg
Grabar B, Reg
Fin Para
Fin

Mezclar
Inicio
Mientras no eof (A) y no eof (B) Hacer
Mezclar_Sec
Fin Mientras
Fin

Mezclar_Sec
Inicio
SecA = 0; SecB = 0
Repetir
PosA = FilePos (A); Leer A, RegA; Seek (A, PosA)
PosB = FilePos (B); Leer B, RegB; Seek (B, PosB)
Si RegA < RegB Entonces
Leer A, Reg
Grabar C, Reg
SecA =SecA + 1
Si SecA = Sec Entonces
Copiar_SecP (B, C, Sec-SecB);
SecB = Sec
Fin si
Si no
Leer B, Reg
Grabar C, Reg
SecB = SecB + 1
Si SecB = Sec Entonces
Copiar_SecP (A, C, Sec-SecA);
SecA = Sec
Fin si
Fin si
Hasta (SecA = Sec) y (SecB = Sec)
Fin

Copiar_SecP (Var x, y : Archivo; Sec : Entero)


Inicio
Cont = 0
Mientras no eof (x) y (Cont < Sec) Hacer
Leer (x, Reg)
Grabar (y, Reg)
Cont = Cont +1;

44
Fin Mientras
Fin

ORDENACIÓN POR VON NEWMAN

El método solo funciona con archivos donde su longitud sea múltiplo de 2n, hace el uso de los
siguientes archivos:

C Archivo a ordenar
A,B Archivos auxiliares

Se deben seguir los siguientes pasos para ordenar:

1. Partir el archivo C en secuencias de 2n, copiar intercaladamente las secuencias del archivo C,
primeramente en el archivo A, y luego en el archivo B.
2. Mezclar los archivos auxiliares A y B por secuencias de 2n. Donde: n = 0,1,2,3...
3. Repetir los pasos 1 y 2 hasta que la secuencia sea mayor que la mitad del archivo a ordenar
(secuencia{2n}> long(C)/2)

Ejemplo:

Ordenar los siguientes datos.

45
ALGORITMO
Inicio
Sec = 1
Abrir C (Lectura)
Repetir
Abrir B (Escritura)
Abrir A (Escritura)
Seek (C, 0)
Particionar
Seek (A, 0); Seek (B, 0); Seek (C, 0)
Mezclar
Cerrar A; Cerrar B
Sec = Sec * 2
Hasta Sec > (Filesize (C) Div 2)
Cerrar C
Fin

Particionar
Inicio
Mientras no eof (C) Hacer
Copiar_SecP (C, A, Sec)
Si no eof (C) Entonces
Copiar_SecP(C,B,Sec)
Fin si
Fin mientras
Fin

Copiar_SecP (Var x, y : Archivo; Sec : Entero)


Inicio
Cont = 0
Mientras no eof (x) y (Cont < Sec) Hacer
Leer (x, Reg)
Grabar (y, Reg)
Cont = Cont +1;
Fin Mientras
Fin

Mezclar
Inicio
Mientras no eof (A) y no eof (B) Hacer
Mezclar_Sec
Fin Mientras
Fin

Mezclar_Sec
Inicio
SecA = 0; SecB = 0
Repetir
PosA = FilePos (A)
Leer A, RegA
Seek (A, PosA)

PosB = FilePos (B)


Leer B, RegB
Seek (B, PosB)

46
Si RegA < RegB Entonces
Leer A, Reg
Grabar C, Reg
SecA =SecA + 1
Si SecA = Sec Entonces
Copiar_SecP (B, C, Sec-SecB);
SecB = Sec
Fin si
Si no
SecB = SecB + 1
Si SecB = Sec Entonces
Copiar_SecP (A, C, Sec-SecA);
SecA = Sec
Fin si
Fin si
Hasta (SecA = Sec) y (SecB = Sec)
Fin

ORDENACIÓN POR MEZCLA EQUILIBRADA

El método funciona con todo tipo de archivos, hace el uso de los siguientes archivos:

C Archivo a ordenar
A,B Archivos auxiliares

Se deben seguir los siguientes pasos para ordenar:

1. Partir el archivo C en secuencias ordenadas, copiar intercaladamente las secuencias ordenadas


del archivo C, primeramente en el archivo A, y luego en el archivo B.
2. Mezclar los archivos auxiliares A y B por secuencias ordenadas.
3. Repetir los pasos 1 y 2 hasta que la mezcla de secuencias sea igual a uno (n_tramos=1).

Ejemplo: Ordenar los siguientes datos.

47
ALGORITMO
PRINCIPAL
Inicio
Abrir C (Lectura)
Repetir
Abrir A (Escritura);Abrir B (Escritura);
Seek (C, 0)
Particionar
Seek (C, 0); Seek (A, 0); Seek (B, 0)
Num_Tramos = 0
Mezclar;
Cerrar A; Cerrar B
Hasta Num_Tramos =1
Cerrar C
Fin

Particionar
Inicio
Mientras no eof (C) Hacer
Copiar Tramo (C, A)
Si no eof (C) Entonces
Copiar_Tramo(C,B)
Fin si
Fin mientras
Fin

Copiar_Tramo (x, y : Archivo)


Inicio
Repetir
Copiar_Dato (x, y)
Hasta Fin_Tramo
Fin

Copiar_Dato (var x, y : Archivo)


Inicio
Si eof (x) Entonces
Fin_Tramo = TRUE
Si no
Leer (x), Reg
Grabar (y), Reg

Si eof (x) Entonces


Fin_Tramo = TRUE
Si no
Pos = FilePos (x)
Leer (x), Reg1)
Seek (x, Pos )
Fin_Tramo = Reg > Reg1
Fin si
Fin si
Fin

Mezclar
Inicio

Mientras no eof (A) y no eof (B) Hacer


Mezclar_Tramos
Num_Tramos = Num_Tramos + 1
Fin Mientras

48
Mientras no ef (A) Hacer
Copiar_Tramo (A, C)
Num_Tramos = Num_Tramos + 1
Fin Mientras

Mientras no ef (B) Hacer


Copiar_Tramo (B, C)
Num_Tramos = Num_Tramos + 1
Fin Mientras

Fin

Mezclar_Tramo
Inicio
Repetir
PosA = File Pos (A);
Leer (A, RegA);
Seek (A, PosA)
PosB = File Pos (B);
Leer (B, RegB);
Seek (B, PosB)
Si RegA < RegB Entonces
Copiar_Dato (A, C)
Si Fin_Tramo Entonces
Copiar_Tramo (B, C)
Fin Si
Si no
Copiar_Dato (B, C)
Si Fin_Tramo Entonces
Copiar_Tramo (A, C)
Fin si
Fin si
Hasta Fin _Tramo
Fin

ORDENACIÓN POR DIGITOS

El método funciona solo con archivos que almacenan datos numéricos con cifras elevadas, hace el uso
de los siguientes archivos:

C Archivo a ordenar
A0, A1..., A9 Archivos auxiliares

Se deben seguir los siguientes pasos para ordenar:

1. Partir el archivo C de acuerdo al digito inspeccionado, ejemplo si el digito inspeccionado es 1


este dato debe copiarse al archivo A1. Se debe empezar inspeccionando por la posicion de la
unidad, decena, centena...etc.
2. Mezclar los 10 archivos auxiliares A0..A9 en orden, empezando del archivo A0 y finalizando
en el archivo A10.
3. Repetir los pasos 1 y 2 hasta que se haya inspeccionado todos los dígitos, es decir unidades,
decenas, centenas, etc.

49
Ejemplo:Ordenar los siguientes datos.

ALGORITMO
FUNCION PRINCIPAL
Var Arch : [0....9] of Archivo
Inicio

Abrir C (Lectura)
Dig = 0
Repetir
Abrir_Archivos
Seek (C, 0)
Particionar
Para I = 0 Hasta 9 Hacer Seek (Arch [ i ], 0)
Seek (C, 0)
Mezclar
Dig = Dig + 1
Cerrar_Archivos
Hasta Dig > 4
Cerrar C
Fin

Particionar
Inicio
Mientras no eof (C) Hacer

50
Leer C, Reg
Aux = Reg Div (Exp(Dig * Ln (10)))
Pos = Aux Mod 10
Grabar Arch [Pos], Reg
Fin Mientras
Fin

Mezclar
Inicio
Para I = 0 Hasta 9 Hacer
Mientras no eof (Arch [I]) Hacer
Leer Arch [I], Reg
Grabar C, Reg
Fin Mientras
Fin Para
Fin

Abrir_Archivos
Inicio
Para I = 0 Hasta 9 Hacer
NOMBRE = 'DATOS'+ CHR(48 + i)+ '.DAT'
Abrir Arch [i] (Escritura)
Fin Para
Fin

Cerrar_Archivos
Inicio
Para I = 0 Hasta 9 Hacer
Cerrar Arch [ i ]
fin Para
Fin

51
TEMA 5

LISTAS ENCADENADAS
OBJETIVOS

Emplear estructuras dinámicas de datos en el procesamiento de la información.

Desarrollar algoritmos para optimizar las operaciones básicas que se llevan a cabo en proceso de
ejecución en estructuras lineales.

CONTENIDO
5.1 Introducción
5.2 Lista Simplemente Enlazada
5.3 Listas Simplemente Enlazadas Circulares
5.4 Listas Doblemente Enlazadas
5.5 Listas Doblemente Enlazadas Circulares

5.1 LISTAS ENCADENADAS


Las listas enlazadas son estructuras de datos lineales, que constan de una secuencia de nodos que se
encuentran enlazados uno con otro, mediante un enlace o puntero.

La adición / eliminación en estas estructuras de datos, se realiza en tiempo de ejecución y en forma


dinámica.

La cantidad de nodos que una lista enlazada puede contener esta limitada por la memoria del
computador.

TIPOS DE LISTAS.

Existen los siguientes tipos de listas enlazadas:

Listas simplemente enlazadas

52
Listas simplemente enlazadas circulares

Listas doblemente enlazadas

Listas doblemente Enlazadas circulares

5.2 LISTAS SIMPLEMENTE ENLAZADAS


Una lista simplemente enlazada se representa tal como se muestra en la siguiente grafica:

Donde:

El nodo Raíz es un puntero al primer elemento de la lista.

Cada elemento (nodo) de la lista simplemente enlazada debe tener dos campos:

• Un campo información (info) que contiene el valor de ese elemento y puede contener
cualquier tipo estándar o definido por el usuario.
• Un campo enlace (o puntero) que indica la posición del siguiente elemento de la lista.

NODO
53
Existe una marca para fin de lista, que es la constante NIL, también representada por una barra
inclinada o el signo eléctrico de tierra.

Declaración de un nodo usando el lenguaje Pascal:

Type
pnodo = ^nodo
nodo = record
info : Integer;
Sig :pnodo;
End;

Declaración de un nodo usando el lenguaje C:

struct Nodo
{
int info;
struct Nodo *sig;
};

OPERACIONES EN LISTAS SIMPLEMENTE ENLAZADAS

Como cualquier estructura de datos, en las listas simplemente enlazadas se puede realizar las siguientes
operaciones básicas:

• Inserción
• Eliminación
• Búsqueda
• Recorrido

RECORRIDO

Para realizar el recorrido en una lista simple, es necesario el uso de un puntero auxiliar ACT, con la
cual se visita toda la lista, empezando por la RAIZ y finalizando cuando el puntero ACT apunta a NIL.

ALGORITMO:

Recorrido(Dato:Integer)
Inicio
Actual = Raíz
Mientras(Actual <> Nil) hacer
Actual =Actual^.sig

54
Mostar Actual^.inf
Fin Mientras
Fin.

BUSQUEDA

Para realizar la búsqueda en una lista simple, es necesario el uso de un puntero auxiliar ACT, con la
cual se busca empezando por la RAIZ y finalizando cuando el puntero ACT apunta al elemento
buscado o a NIL.

ALGORITMO:

Buscar(Dato:Integer)
Inicio
Actual = Raíz
Mientras(Actual<>Nil) y (Actual^.inf<>Dato) hacer
Actual =Actual^.sig
Fin Mientras
Si Actual^.inf = Dato entonces
Mostar "El Dato Esta en la Lista"
Sino
Mostrar "No Existe el Dato"
Fin si
Fin.

INSERCION DE DATOS

Existen distintas formas de adición de nodos a una lista simple, de acuerdo a los propósitos de uso de
estos, entre las cuales se tiene:

• Insertar cuando lista esta vacía


• Insertar al principio
• Insertar al final
• Insertar al medio de dos nodo

En todas ellas se realiza una tarea común:

• Crear una nuevo nodo


• Almacenar el elemento
• Agregar los enlaces respectivos

INSERTAR CUANDO LISTA ESTA VACIA:

55
Insertar(5)

• New(Nuevo)
• Nuevo^.inf= 5
• Raiz = nuevo (1)
• Nuevo^.sig= nil(2)

INSERTAR AL PRINCIPIO:

Insertar(3)

• New(Nuevo)
• Nuevo^.inf= 3
• Nuevo^.sig = Raiz(1)
• Raiz = Nuevo (2)

INSERTAR AL FINAL:

Insertar(13)

56
• New(Nuevo)
• Nuevo^.inf= 13
• ant^.sig =Nuevo(1)
• Nuevo^.sig =Nil(2)

INSERTAR AL MEDIO DE DOS NODOS:

Insertar(7)

• New(Nuevo)
• Nuevo^.inf= 7
• Nuevo^.sig =Act(1)
• Ant^.sig = Nuevo(2)

ALGORITMO :

Insertar (Dato:Entero)
Inicio
New(Nuevo)
Nuevo^.inf = Dato
Si Raiz = Nil Entonces
Raiz = Nuevo
Nuevo^ sig = Nil
Si no
Anterior = Raiz
Actual = Raiz
Mientras (Actual <>Nil) y (Dato> Actual^.Inf) Hacer
Anterior = Actual
Actual = Actual^.sig
Fin Mientras
Si Anterior =Actual Entonces
Nuevo^.sig = Raiz
Raiz = Nuevo
Si no
Nuevo^.sig = Actual

57
Anterior^.sig = Nuevo
Fin si
Fin si
Fin.

ELIMINAR DATOS

Para eliminar un dato de una lista simple, es necesario buscarlo en la lista primeramente.

La búsqueda se realiza con dos punteros auxiliares ANT y ACT, si el dato se encuentra en la lista, el
puntero ACT apunta a ella y el puntero ANT apunta al anterior elemento.

Existen dos casos que se presentan al eliminar un dato:

1. Eliminar el primer elemento


2. Eliminar un elemento distinto del primero

ELIMINAR EL PRIMER ELEMENTO

Dada la siguiente lista:

Eliminar(5)

• Raiz= act^.sig(1)
• Dispose(act)

ELIMINAR UN ELEMENTO DISTINTO DEL PRIMERO

Dada la siguiente lista:

Eliminar(9)

58
• ant^.sig = act^.sig
• Dispose(act)

ALGORITMO:

Eliminar (Dato:Entero)
Inicio
Si Raiz = nil then
Mostrar ‘No existe Datos’
Si no
Anterior = Raiz
Actual = Raiz
Mientras (Actual <> Nil) y (Actual^.inf <> Dato) Hacer
Anterior = Actual
Actual =Actual^.sig
Fin Mientras
Si Actual^.inf = Dato entonces
Si Anterior = Actual entonces
Raiz = Actual^.sig
Sino
Anterior^.sig = Actual^.sig
Fin si
Dispose(Actual)
Sino
Imprimir "No Existe el Dato"
Fin si
Fin si
Fin.

5.3 LISTAS SIMPLEMENTE ENLAZADAS CIRCULARES.


Una lista circular es aquella en la cual el puntero siguiente del último elemento apunta hacia el primer
elemento. Por lo cual en estas listas no existe ni primero ni último elemento, aunque se debe elegir
obligatoriamente un puntero para referenciar la lista.

Esta lista presenta la gran ventaja de que cada nodo en una lista circular es accesible desde cualquier
nodo. Tiene el inconveniente de que requiere un diseño cuidadoso para evitar caer en un bucle infinito.

Existen dos tipos de listas enlazadas simples circulares:

59
• Listas simples circulares sin nodo cabecera

• Listas simples circulares con nodo cabecera

El manejo de la primera es complejo, de tal modo que solo se usaremos las listas enlazadas con nodo
cabecera, debido a su fácil manejo.

OPERACIONES EN LISTAS SIMPLEMENTE ENLAZADAS CIRCULARES

Como cualquier estructura de datos, en las listas simplemente enlazadas circulares se puede realizar las
siguientes operaciones básicas:

• Inserción
• Eliminación
• Búsqueda
• Recorrido

RECORRIDO

Para realizar el recorrido en una lista simple circular, es necesario el uso de un puntero auxiliar ACT,
con la cual se visita toda la lista, empezando por la RAIZ y finalizando cuando el puntero ACT apunta
a NIL.

ALGORITMO:
Recorrido(Dato:Integer)
Inicio
Actual = Raíz^.sig
Mientras(Actual <> Raiz) hacer
Actual =Actual^.sig
Mostarc Actual^.inf

60
Fin Mientras
Fin.

BUSQUEDA

Para realizar la búsqueda en una lista simple, es necesario el uso de un puntero auxiliar ACT, con la
cual se busca empezando por la RAIZ y finalizando cuando el puntero ACT apunta al elemento
buscado o a NIL.

ALGORITMO :
Buscar(Dato:Integer)
Inicio
Actual = Raíz^.sig
Mientras(Actual <> Raiz) y (Actual^.inf <> Dato) hacer
Actual =Actual^.sig
Fin Mientras
Si Actual^.inf = Dato entonces
Mostar "El Dato Esta en la Lista"
Sino
Mostrar "No Existe el Dato"
Fin si
Fin.

INSERCION DE DATOS

Existen distintas formas de adición de nodos a una lista simple circular, de acuerdo a los propósitos de
uso de estos. Entre las cuales se tiene:

• Insertar cuando lista esta vacía


• Insertar al medio de dos nodos

En todas ellas se realiza una tarea común, que es el de crear una nuevo nodo para almacenar al
elemento que será agregado a la lista.

INSERTAR CUANDO LISTA ESTA VACIA:

Insertar(5)

61
• New(Cab)
• New(Nuevo)
• Nuevo^.inf= 5
• Raiz = Cab (1)
• Cab^.sig= nuevo (2)
• Nuevo^.sig= Raiz (3)

INSERTAR AL MEDIO DE DOS NODOS:

Insertar(7)

• New(Nuevo)
• Nuevo^.inf= 7
• Nuevo^.sig = Act (1)
• Ant^.sig = Nuevo (2)

ALGORITMO :

Insertar (Dato:Entero)
Inicio
New(Nuevo)
Nuevo^.inf = Dato
Si Raiz = Nil Entonces
New(Cab)
Raiz = Cab
Cab^.sig =Nuevo
Nuevo^.sig = Raiz
Si no
Anterior = Raiz
Actual = Raiz^ sig
Mientras (Actual <> Raiz) y (Dato> Actual^.Inf) Hacer

62
Anterior = Actual
Actual = Actual^.sig
Fin Mientras
Nuevo^.sig = Actual
Anterior^.sig = Nuevo
Fin si
Fin.

ELIMINAR DATOS

Para eliminar un dato de una lista simple circular, es necesario buscarlo en la lista primeramente. La
búsqueda se realiza con dos punteros auxiliares ANT y ACT, si el dato se encuentra en la lista, el
puntero ACT apunta a ella y el puntero ANT apunta al anterior elemento.

Existen dos casos que se presentan al eliminar un dato:

• Eliminar él ultimo elemento de la lista


• Eliminar un elemento distinto del ultimo

ELIMINAR EL ULTIMO ELEMENTO DE LA LISTA

Dada la siguiente lista:

Eliminar(9)

Para eliminar el ultimo elemento, es necesario liberar la memoria de los nodos que apuntan a ANT y
ACT.

• Dispose(ant)
• Dispose(act)
• Raiz = nil (1)

ELIMINAR UN ELEMENTO DISTINTO DEL ULTIMO

Dada la siguiente lista:

63
Eliminar(5)

• ant^.sig = act^.sig
• Dispose(act)

ALGORITMO:

Eliminar (Dato:Entero)
Inicio
Si Raiz = nil then
Mostrar ‘No existe Datos’
Si no
Anterior = Raiz
Actual = Raiz^.sig
Mientras (Actual <> Raiz) y (Actual^.inf <> Dato) Hacer
Anterior = Actual
Actual =Actual^.sig
Fin Mientras
Si Actual^.inf <>Raiz entonces
Si Anterior = Actual^.sig entonces
Dispose(Anterior)
Raiz = Nil
Sino
Anterior^.sig = Actual^.sig
Fin si
Dispose(Actual)
Sino
Imprimir "No Existe el Dato"
Fin si
Fin si
Fin.

5.4 LISTAS DOBLEMENTE ENLAZADAS.


En muchas aplicaciones se requiere recorrer la lista en dos direcciones. Estos recorridos se pueden
conseguir manteniendo dos campos de enlace en cada nodo en lugar de uno.

64
Estos enlaces(punteros) se utilizan para denotar la dirección del predecesor y sucesor de un nodo dado.
El predecesor se llama enlace izquierdo y el sucesor enlace derecho.

Donde:

• Nodo Inicio es un puntero al primer elemento de la lista.


• Nodo Fin es un puntero al ultimo elemento de la lista.
• Una lista cuya Estructura de Nodo,contiene dos campos de enlace se denominará lista lineal
doblemente enlazada.

NODO

Donde:

• campo enlace ant. apunta al anterior nodo de la lista.


• campo info contiene cualquier tipo estándar de datos.
• campo enlace sig. apunta al siguiente nodo de la lista.

Existe una marca para fin de lista, que es la constante NIL, también representada por una barra
inclinada o el signo eléctrico de tierra.

Declaración de un nodo usando el lenguaje Pascal:

Type
pnodo = ^nodo
nodo = record
info : Integer;
Ant, Sig :pnodo;
End;

Declaración de un nodo usando el lenguaje C:

Struct nodo
{
int info;
struct nodo *Ant, * Sig;
};

OPERACIONES EN LISTAS DOBLEMENTE ENLAZADAS.

Las operaciones básicas para manipular listas doblemente enlazadas son:

65
 Inserción
 Eliminación
 Recorrido
 Búsqueda

RECORRIDO

En una lista doble circular es posible realizar dos tipos de recorridos, esto debido a que en estas listas
existen enlaces en ambas direcciones.

 Recorrido en forma ascendente


 Recorrido en forma descendente

RECORRIDO EN FORMA ASCENDENTE

Este recorrido se inicia cuando el puntero apunta a INICIO y se recorre de nodo a nodo con el puntero
SIG hasta que el nodo apunte a NIL.

ALGORITMO:

Inicio
Actual = Inicio
Mientras Actual <> NIL hacer
Mostrar Actual^.inf
Actual = Actual^.sig
Fin Mientras
Fin.

RECORRIDO EN FORMA DECENDENTE

Este recorrido se inicia cuando el puntero apunta a FIN y se recorre de nodo a nodo con el puntero
ANT hasta que el puntero apunte a NIL.

ALGORITMO:

Inicio
Actual = Fin}
Mientras Actual <> Nil Hacer
Mostrar Actual^.inf

66
Actual = Actual^.ant
Fin Mientras
Fin.

INSERCION DE DATOS

Existen distintas formas de adición de nodos a una lista doble, de acuerdo a los propósitos de uso de
estos. Entre las cuales se tiene:

• Insertar cuando lista esta vacía


• Insertar al principio
• Insertar al final
• Insertar al medio de dos nodos

En todas ellas se realiza una tarea común, que es el de crear una nuevo nodo para almacenar al
elemento que será agregado a la lista.

INSERTAR CUANDO LISTA ESTA VACIA:

Dada la siguiente lista:

Insertar(5)

• New(Nuevo)
• Nuevo^.inf= 5
• Inicio = nuevo (1)
• Fin = nuevo (2)
• Nuevo^.ant= nil (3)
• Nuevo^.sig= nil (4)

INSERTAR AL PRINCIPIO

Dada la siguiente lista:

Insertar(3)

67
• New(Nuevo)
• Nuevo^.inf= 3
• Inicio = Nuevo(1)
• Nuevo^.sig = Act(2)
• Act^.ant = Nuevo(3)
• Nuevo^.ant = Nil(4)

INSERTAR AL FINAL:

Dada la siguiente lista:

Insertar(13)

• New(Nuevo)
• Nuevo^.inf= 13
• ant^.sig = Nuevo(1)
• Nuevo^.sig = Nil(2)
• Fin = Nuevo(3)
• Nuevo^.ant = Ant(4)

INSERTAR AL MEDIO DE DOS NODOS:

Dada la siguiente lista:

68
Insertar(7)

• New(Nuevo)
• Nuevo^.inf= 7
• Ant^.sig = Nuevo(1)
• Nuevo^.sig = Act(2)
• Act^.ant = Nuevo(3)
• Nuevo^.ant = Ant (4)

ALGORITMO:

Insertar (Dato:Entero)
Inicio
New(Nuevo)
Si Inicio = Nil Entonces
Inicio = Nuevo; Final = Nuevo
Nuevo^.ant = Nil;
Nuevo^.sig = Nil
Si no
Anterior = Inicio
Actual = Inicio
Mientras (Actual <> Nil) y( Actual^.inf < Dato) Hacer
Anterior = Actual
Actual =Actual^.sig
Fin Mientras
Si Actual = Anterior Entonces
Nuevo^.sig = Inicio
Inicio^.ant = Nuevo
Inicio = Nuevo
Nuevo^.ant = Nil
Si no
Si Actual = Nil Entonces
Final = Nuevo
Si no
Actual^.ant = Nuevo
Fin si
Nuevo^.sig = Actual
Anterior^.sig = Nuevo
Nuevo^.ant = Anterior
Fin si
Fin si
Fin.

ELIMINAR DATOS

Para eliminar un dato de una lista doble, es necesario buscarlo en la lista primeramente.

69
La búsqueda se realiza con dos punteros auxiliares ANT y ACT, si el dato se encuentra en la lista, el
puntero ACT apunta a ella y el puntero ANT apunta al anterior elemento.

Existen dos casos que se presentan al eliminar un dato:

• Eliminar el primer elemento


• Eliminar un elemento distinto del primero
• Eliminar él ultimo elemento

ELIMINACIÓN AL PRINCIPIO:

Dada la siguiente lista:

Eliminar(5)

1. Inicio = Inicio^.sig
2. Inicio^.ant = Nil
Dispose(act)

ELIMINACIÓN AL MEDIO:

Dada la siguiente lista:

Eliminar(8)

70
1. Ant^.sig = Act^.sig
2. Act^.sig^.ant = Ant
Dispose(act)

ELIMINACIÓN AL FINAL:

Dada la siguiente lista:

Eliminar (9)

1. Ant^.sig = Act^.sig = nil


2. Final = Ant
Dispose(act)

ALGORITMO:

Eliminar (Valor: Entero)


Inicio
Anterior = Inicio
Actual = Inicio
Mientras (Actual <> Nil) y (Actual^.inf <> Valor) hacer
Anterior = Actual
Actual =Actual^.sig
Fin Mientras
Si Actual^.inf <> Valor Entonces
Mostrar "No Existe el Elemento"
Si no
Si Actual=Anterior Entonces
Si Actual^.sig <> Nil Entonces
Inicio = Inicio^.sig
Inicio^.ant = Nil
Si no
Final = Nil
Inicio = Nil
Fin si
Si no
Si Actual^.sig <> Nil entonces
Actual^.sig^.Ant = Anterior
Si no
Final = Anterior

71
Fin si
Anterior^.sig = Actual^.sig
Fin si
Fin si
Fin.

5.5 LISTAS CIRCULARES DOBLEMENTE ENLAZADAS.


Una lista doble circular es aquella en la cual el puntero siguiente del último elemento apunta hacia el
primer elemento. En estas listas no existe ni primero ni último elemento, aunque se debe elegir
obligatoriamente un puntero para referenciar la lista.

Esta lista presenta la gran ventaja de que cada nodo en una lista doble circular es accesible desde
cualquier nodo. Tiene el inconveniente de que requiere un diseño cuidadoso para evitar caer en un
bucle infinito.

Existen dos tipos de listas enlazadas simples circulares:

Listas dobles circulares sin nodo cabecera

Listas dobles circulares con nodo cabecera

El manejo de la primera es complejo, de tal modo que solo se usaremos las listas enlazadas con nodo
cabecera, debido a su fácil manejo.

72
OPERACIONES EN LISTAS DOBLEMENTE ENLAZADAS CIRCULARES.

Las operaciones básicas para manipular listas doblemente enlazadas son:

 Inserción
 Eliminación
 Recorrido
 Búsqueda

RECORRIDO

En una lista doble circular es posible realizar dos tipos de recorridos, esto debido a que en estas listas
existen enlaces en ambas direcciones.

 Recorrido en forma ascendente


 Recorrido en forma descendente

RECORRIDO EN FORMA ASCENDENTE

Este recorrido se inicia cuando el puntero apunta a Raiz^.sig y se recorre de nodo a nodo con el puntero
SIG hasta llegar al nodo Raiz.

ALGORITMO:

Inicio
Actual = Raiz^.sig
Mientras Actual <> Raiz hacer
Mostrar Actual^.inf
Actual = Actual^.sig
Fin Mientras
Fin.

RECORRIDO EN FORMA DECENDENTE

Este recorrido se inicia cuando el puntero apunta a Raiz^.ant y se recorre de nodo a nodo con el puntero
ANT hasta llegar al nodo Raiz.

73
ALGORITMO:

Inicio
Actual = Raiz^.ant
Mientras Actual <> Raiz Hacer
Mostrar Actual^.inf
Actual = Actual^.ant
Fin Mientras
Fin.

INSERCION DE DATOS

Existen dos formas de inserción de datos a una lista doblemente enlazada circular:

• Inserción en una lista vacía


• Insertar al medio de dos nodos

INSERCIÓN EN UNA LISTA VACIA

Insertar(9)

• New(Cab)
• New(nuevo)
• nuevo^.inf=9
• Raiz = Cab (1)
• Cab^.sig = Nuevo (2)
• Nuevo^.sig = Cab (3)
• Cab^.ant = Nuevo (4)
• Nuevo^.ant = Cab (5)

74
INSERTAR AL MEDIO DE DOS NODOS:

Insertar(6)

• New(Cab)
• New(nuevo)
• nuevo^.inf=6
• Ant^.sig = Nuevo(1)
• Nuevo^.sig = Act(2)
• Act^.ant = Nuevo(3)
• Nuevo^.ant = Ant(4)

ALGORITMO:

Insertar (dato:entero)
Inicio
New(Nuevo)
Nuevo^.inf = Dato
Si Raiz = Nil Entonces
New(NodoC)
Raiz = NodoC
NodoC^.sig = NodoC
NodoC^.ant = Nuevo
Nuevo^.ant = NodoC
Si no
Anterior = Raiz
Actual = Raiz^.sig
Mientras (Actual <> Raiz) y (Actual^.inf < dato) Hacer
Anterior = Actual
Actual =Actual^.sig
Fin Mientras
Nuevo^.sig = Actual
Actual^.sig = Nuevo
Nuevo^.ant = Anterior
Actual^.ant = Nuevo
Fin si
Fin.

75
ELIMINAR DATOS

Para eliminar un dato de una lista doble circular, es necesario buscarlo en la lista primeramente.

La búsqueda se realiza con dos punteros auxiliares ANT y ACT, si el dato se encuentra en la lista, el
puntero ACT apunta a ella y el puntero ANT apunta al anterior elemento.

Existen dos casos que se presentan al eliminar un dato:

• Eliminar él ultimo elemento


• Eliminar un elemento

ELIMINAR ÉL ULTIMO ELEMENTO

Eliminar(9)

• Dispose(ant)
• Dispose(act)
• Raiz = Nil

ELIMINAR UN ELEMENTO

Eliminar(9)

76
• Ant^.sig = Act^.sig(1)
• Act^.sig ^.ant = Ant(2)
• Dispose(act)

ALGORITMO:

Eliminar (Valor:Entero)
Inicio
Anterior = Raiz
Actual = Raiz^.sig
Mientras (Actual <> Raiz) y (Actual^.inf <> Valor) Hacer
Anterior = Actual
Actual =Actual^.sig
Fin Mientras
Si (Actual^.inf <> Valor) Entonces
Mostrar "No Existe el Elemento"
Si no
Si Actual^.sig = Anterior) Entonces
Dispose(Anterior)
Raiz = Nil
Si no
Anterior^.sig = Actual^.sig
Actual^.sig ^.ant= Anterior
Fin si
Dispose(Actual)
Fin si
Fin.

77
TEMA 6

ÁRBOLES
OBJETIVOS

Desarrollar aplicaciones con estructuras ramificadas que optimizan las operaciones básicas.

Encontrar nuevas formas de organización de datos en forma ramificada de acuerdo a las características
de la aplicación.

CONTENIDO
6.1 Introducción
6.2 Conceptos Asociados
6.3 Árbol Binario de Búsqueda
6.4 Árboles Equilibrados o AVL

6.1 DEFINICION.
Un árbol es una lista en la que cada uno de sus elementos apunta a uno, ninguno o varios elementos del
mismo tipo.

Un árbol es una estructura dinámica y homogénea, por tanto está compuesto de elementos del mismo
tipo base T, de forma que la estructura puede estar vacía o compuesta por un elemento del tipo base T
del que cuelgan un número finito de estructuras árbol similar, a las que llamaremos subárboles, y entre
sí son disjuntos.

Dos árboles son iguales cuando tengan igual número de nodos, igual contenido en ellos y, además,
estén dispuestos de igual manera

REPRESENTACIÓN

Un árbol es una estructura de datos no lineal que establece una jerarquía entre sus elementos.

Un árbol puede ser representado, en tres formas diferentes:

 Matriz de adyacencia.
 Lista de adyacencia.

78
 Estructura dinámica pura.

MATRIZ DE ADYACENCIA

Es un array [1..n,1..n] OF BOOLEAN donde n es el número de nodos que tiene el árbol y cada posición
de la matriz indicará si existe un enlace entre dos nodos. Esto es normal hacerlo en lenguajes en que no
pueden crearse componentes dinámicamente, y referenciales por medio de punteros.

Ejemplo:

LISTA DE ADYACENCIA

Es una tabla de 1 a n, siendo n el número de nodos, donde cada elemento de la tabla representa cada
uno de los nodos del árbol y de cada uno de los elementos sale un puntero a una lista que está formada
por todos los nodos que están enlazados con él.

Ejemplo:

ESTRUCTURA DINÁMICA PURA

En ella, todos los componentes o nodos, se representan por punteros explícitos.

Vamos a tener un tipo como:

PNodo=^Nodo;
Nodo=RECORD
Info:Tinfo;
Enlace1,..., EnlaceN: PNodo;
END;

79
6.2 CONCEPTOS ASOCIADOS
A continuación veremos algunos conceptos asociados a los Arboles.

Nodo: Cada uno de los elementos de un árbol.

Rama: Es cada uno de los enlaces que existe entre los nodos de un árbol.

Raíz: Es aquel nodo que no tiene antecesores, es decir, todos son descendientes directos o indirectos
de el.

Subárbol: Se llama subárbol de raíz m al conjunto de nodos que dependen directa o indirectamente
de él, así como al propio m.

Antecesor o padre: Es un nodo del que cuelga algún otro, llamado descendiente o hijo.

Grado de un nodo: Es el número de descendientes directos que tiene, el grado de un árbol es igual
al del nodo con mayor grado.

Nivel : Es el número de ramas que hay que recorrer para llegar a él desde la raíz, tendiendo en cuenta
que la raíz tiene nivel uno.

80
Nodo terminal u hoja: Es aquel que tiene grado cero, es decir, que no tiene ningún descendiente.

Nodo interno: Es aquel que no es hoja.

Longitud de camino interno de un arbol: Es la suma de las longitudes de camino de todos sus
nodos.

LCI = 1+2+2+3+3+3 = 14

Longitud de camino externa: Es la suma de las longitudes de camino de todos los Nodos
Especiales (Es aquel que se hace colgar de aquellos nodos que no tienen completo el cupo de
descendientes).

LCE = 3+4+4+4+4+4+4 = 27

Longitud de camino interna media: Es la longitud de camino interna partido del número de
nodos

6.3 ARBOL BINARIO


Los árboles de grado 2 tienen una especial importancia. Se les conoce con el nombre de árboles
binarios.

Se define un árbol binario como un conjunto finito de elementos (nodos) que bien está vació o está
formado por una raíz con dos árboles binarios disjuntos, llamados subárbol izquierdo y derecho de la
raíz.

81
En los apartados que siguen se considerarán únicamente árboles binarios y, por lo tanto, se utilizará la
palabra árbol para referirse a árbol binario. Los árboles de grado superior a 2 reciben el nombre de
árboles multicamino.

DEFINICION

Los árboles binarios se utilizan frecuentemente para representar conjuntos de datos cuyos elementos se
identifican por una clave única.

Si el árbol está organizado de tal manera que la clave de cada nodo es mayor que todas las claves del
subárbol izquierdo, y menor que todas las claves del subárbol derecho se dice que este árbol es un árbol
binario de búsqueda.

Ejemplo:

OPERACIONES BASICAS

Una tarea muy común a realizar con un árbol es ejecutar una determinada operación con cada uno de
los elementos del árbol. Esta operación se considera entonces como un parámetro de una tarea más
general que es la visita de todos los nodos o, como se denomina usualmente, del recorrido del árbol.

Si se considera la tarea como un proceso secuencial, entonces los nodos individuales se visitan en un
orden específico, y pueden considerarse como organizados según una estructura lineal.

Existen dos formas básicas de recorrer un árbol:

o Recorrido en amplitud.
o Recorrido en profundidad.

RECORRIDO EN AMPLITUD.

En el recorrido por amplitud se visitan los nodos por niveles. Para ello se utiliza una estructura auxiliar
tipo "cola" en la que después de mostrar el contenido del nodo, empezando por el nodo raíz, se
almacenan los punteros correspondientes a sus hijos izquierdo y derecho.

De esta forma si recorremos los nodos de un nivel, mientras mostramos su contenido, almacenamos en
la cola los punteros a todos los nodos del nivel siguiente.

82
Resultado:

20, 10, 30, 5, 15, 25

El algoritmo:
Amplitud
Inicio
Ptr = raiz
Cima = 1
Inicio=1
Pila[cima] = Ptr

Mientras Inicio<=cima hacer

ptr=Pila[Inicio]
inicio++
Mostrar ptr^.inf

Si ptr^der <> nil entonces


Cima=cima+1
Pila[cima] = ptr^.der
Fin_si

Si ptr^izq <> nil entonces


Cima=cima+1
Pila[cima] = ptr^.izq
Fin_si

Fin_mientras
Fin.
RECORRIDO EN PROFUNDIDAD.

Para visualizar o consultar los datos en un árbol se necesita recorrer el árbol. Al contrario que las listas
enlazadas, los árboles no tienen un primer valor, un segundo valor, etc.

Existen métodos de recorrido de un árbol binario, de acuerdo al orden en que se visitan los nodos, de
forma que será preciso elegir cuidadosamente el tipo de recorrido. Según sea la estrategia a seguir, los
recorridos se conocen como:

 Recorrido inorden
 Recorrido preorden
 Recorrido postorden

83
Las tres etapas básicas en el recorrido de un árbol binario recursivamente son:

- Visitar el nodo (Raiz)


- Recorrer el subárbol izquierdo (izq.)
- Recorrer el subárbol derecho (der.)

RECORRIDO PREORDEN

Si el árbol no esta vació, el método implica los siguientes pasos:

- Visitar el nodo (Raiz)


- Recorrer el subárbol izquierdo (izq.)
- Recorrer el subárbol derecho (der.)

El algoritmo usando recursividad:


preorden (var p:pnodo)
inicio
si p <>nil entonces
escribir p^.inf
preorden (p^.izq)
preorden (p^.der)
fin si
fin

En el árbol, los nodos se han numerado en el orden que son visitados en el recorrido preorden

· Primero se visita el nodo raíz A.

· Después se visita el subárbol izquierdo. Este consta de los nodos (B, D y E), por lo que siguiendo con
el orden (Raiz, izq., der.), se visita primero B, luego D y por ultimo E.

· Por ultimo se visita el subárbol derecho que consta de los nodos (C, F y G). Siguiendo el orden (Raiz,
izq., der.), se visita primero C, luego F y por ultimo G.

El recorrido es: A-B-D-E-C-F-G

El algoritmo sin usar recursividad:

84
Preorden
Inicio
Cima = 1
Pila[cima] = nil
Ptr = raiz

Mientras ptr <> nil hacer

Mostrar ptr^.inf

Si ptr^der <> nil entonces


Cima=cima+1
Pila[cima] = ptr^.der
Fin_si

Si ptr^.izq <> nil entonces


Ptr = ptr^.izq
Sino
Ptr = pila[cima]
Cima=cima-1
Fin_si

Fin_mientras
Fin.
RECORRIDO INORDEN
Si el árbol no esta vació, el método implica los siguientes pasos:

- Recorrer el subárbol izquierdo (Izq)


- Visitar el nodo (Raiz)
- Recorrer el subárbol derecho (Der)

El algoritmo usando recursividad:


inorden (var p:pnodo)
inicio
si p <> nil entonces
inorden (p^.izq)
escribir p^.inf
inorden (p^.der)
fin si
fin

En el árbol, los nodos se han numerado en el orden que son visitados en el recorrido enorden.

85
· El primer recorrido es el subárbol izquierdo del nodo raíz. Este consta de los nodos (B, D y E), por lo
que siguiendo con el orden (Izq, Raiz, Der), se visita primero D, luego B y por ultimo E.

· Después se visita el nodo raíz A.

· Por ultimo se visita el subárbol derecho que consta de los nodos (C, F y G). siguiendo el orden (Izq,
Raiz, Der), se visita primero F, luego C y por ultimo G.

El recorrido es: D-B-E-A-F-C-G

El algoritmo sin usar recursividad:


Inorden
Inicio
Cima = 1
Pila[cima]=nil
Ptr = raiz

Mientras ptr <> nil hacer


Mientras ptr <> nil hacer
Cima=cima+1
Pila[cima] = ptr
Ptr = ptr^.izq
Fin_mientras

Ptr = pila[cima]
Cima=cima-1
Tieneder =false

Mientras Ptr <> nil y no tieneder hacer

Mostrar ptr ^.inf


Si ptr^.der <> nil entonces
Ptr = ptr^.der
Tieneder = true
Sino
Ptr = pila[cima]
Cima=cima-1
Fin_si
Fin_mientras
Fin_mientras
Fin.
RECORRIDO POSTORDEN
Si el árbol no esta vació, el método implica los siguientes pasos:

- Recorrer el subárbol izquierdo (Izq)


- Recorrer el subárbol derecho (Der)
- Visitar el nodo (Raiz)

El algoritmo usando recursividad:


postorden (var p:pnodo)

86
inicio
si p <> nil entonces
postorden (p^.izq)
postorden (p^.der)
escribir p^.inf
fin si
fin

En el árbol, los nodos se han numerado en el orden que son visitados en el recorrido preorden.

· Primero se visita el subárbol izquierdo. Este consta de los nodos (B, D y E), por lo que siguiendo con
el orden (Izq, Der, Raiz), se visita primero D, luego E y por ultimo B.

· Por ultimo se visita el subárbol derecho que consta de los nodos (C, F y G). Siguiendo el orden (Izq,
Der, Raiz), se visita primero F, luego G y por ultimo C.

· Por ultimo se visita el nodo raíz A.

El recorrido es: D-E-B-F-G-C-A

El algoritmo sin usar recursividad:


Postorden
Inicio
Cima = 1
Pila[cima]=nil
Ptr = raiz
Mientras ptr <> nil hacer
Mientras ptr <> nil hacer
Cima=cima+1
Pila[cima] = ptr
Si ptr^.der <> nil entonces
Cima = cima+1
Pila[cima]= -ptr^.der
Fin_si
Ptr = ptr^.izq
Fin_mientras

Ptr = pila[cima]
Cima = cima-1
Salir = false

87
Mientras ptr <> nil y no salir hacer
Si prt > 0 entonces
Mostrar prt^.inf
Ptr = pila[cima]
Cima = cima-1
Sino
Ptr = -ptr
Salir=true
Fin_si
Fin_mientras
Fin_mientras
Fin.

INSERCIÓN DE DATOS

La inserción de datos en un arbol binario de búsqueda, se realiza de acuerdo al valor que se debe
insertar, si el dato es menor que la raíz es insertada en el subárbol izquierdo, si el dato es mayor que la
raíz es insertada en el subárbol derecho.

Insertar(Var raiz:pnodo;dato:entero)
Inicio
Si raiz = nil entonces
New(raiz)
Raiz^.inf = dato
Raiz^.izq = nil
Raiz^.der = nil
Sino
Si dato > raiz^.inf entonces
Insertar (raiz^.der,dato)
Sino
Insertar(raiz^.izq,dato)
Fin_si
Fin_si
Fin.

ELIMINAR UN DATO

Existen varios casos de eliminación en un arbol binario de búsqueda:

Nodo que no tiene hijos:

Solución : Ptr = nil

Nodo que tiene un hijo:

88
Solución : Ptr = ptr^.der

Solución : Ptr = ptr^.izq

Nodo que tiene dos hijos:

En este caso existen dos posibilidades de reemplazo, donde el nodo a ser eliminado puede ser
reemplazado por los siguientes nodos:

caso a).- El nodo del subárbol izquierdo que se encuentra mas a la derecha

caso b).- El nodo del subárbol derecho que se encuentra mas a la izquierda

89
ALGORITMO :

Eliminar(dato:integer;Var ptr:pnodo)
Inicio
Si ptr = nil entonces
Mostrar "no existe el elemento"
Sino
Si dato > ptr^.inf entoces
Eliminar (dato,ptr^.der)
Sino
Si dato < ptr^.inf entonces
Eliminar(dato,ptr^.izq)
Sino
Aux =ptr
Si aux^.izq=nil entonces
Ptr =aux^.der
Sino
Si aux^.der = nil entonces
Ptr=aux^.izq
Sino
Reemplazar(aux^.izq)
Fin_si
Fin_si

Free(aux)

Fin_si
Fin_si
Fin_si
Fin.

Reemplazar(Var Ader:pnodo)
Inicio
Si Ader^.der <> nil entonces
Reeplazar(Ader^.der)
Sino
Ptr^.inf = Ader^.inf
aux = Ader
Ader = Ader^.izq
Fin_si
Fin.

BÚSQUEDA DE DATOS

La búsqueda de un nodo comienza en el nodo raíz y sigue estos pasos:

· La clave buscada se compara con la clave del nodo raíz.


· Si las claves son iguales, la búsqueda se detiene, o si el subárbol esta vació.
· Si la clave buscada es mayor que la clave raíz, la búsqueda se reanuda en el subárbol derecho.
· Si la clave buscada es menor que la clave raíz, la búsqueda se reanuda en el subárbol izquierdo.

6.4 ÁRBOLES BINARIOS DE EXPRESIONES


Los árboles binarios se utilizan para almacenar expresiones. Por ejemplo, el
arbol de la figura representa la expresión (A+B)*C. Las expresiones

90
matemáticas se pueden escribir según diversos tipos de notaciones. La notación infija es la empleada
habitualmente y requiere el uso de paréntesis, pero únicamente cuando es necesario modificar la
prioridad entre los distintos operadores.

CONSTRUCCIÓN A PARTIR DE UNA EXPRESIÓN EN NOTACIÓN


CONVENCIONAL

Para construir se utilizaran, como estructura de datos auxiliares, una pila de punteros a los nodos de
un árbol y otra pila de operadores para retenerlos temporalmente hasta que llegue el momento de
incorporarlos al árbol. Los pasos a seguir son lo siguientes.
1. Cuando se lee un OPERANDO se crea un árbol de un nodo y se mete el apuntador a el en
correspondiente pila.
2. Cuando se lee un OPERADOR se retiene en la pila de operadores. Los operadores se van poniendo
en esta pila hasta encontrar uno con mayor o igual prioridad, en cuyo caso se sacan los que hubiera
en la pila de mayor o igual prioridad y se coloca en ella este ultimo operador leido.
3. Cuando se lee un PARÉNTESIS IZQUIERDO se retiene en la pila de operadores.
4. Cuando se lee un PARÉNTESIS DERECHO se sacan los OPERADORES que hubiera en la pila de
operadores hasta encontrar el paréntesis izquierdo.
5. El proceso termina cuando se acaba la entrada y la pila de operadores queda vacía.
Nota: Al sacar de la pila de operadores uno de ellos, extraer de la pila de punteros los dos últimos
apuntadores. Con estos tres elementos, se forma un nuevo árbol cuya raíz almacena el operador y
los punteros anteriores. El apuntador a este nuevo árbol se coloca ahora en la pila de apuntadores.

Ejemplo: Sea la expresión :


Q= 4+5^(2*3)+8

1.-

2.- El ) saca los operadores de la pila hasta el (

91
3.- El + saca de la pila todos los operadores con mayor prioridad que el y l continuación se coloca el

4.-

5.-

6.5 ÁRBOLES EQUILIBRADOS O AVL


Es una suavización de las restricciones para formar árboles perfectamente equilibrados. Un árbol AVL
(llamado así por las iniciales de sus inventores: Adelson-Velskii y Landis) es un árbol binario de

92
búsqueda en el que para cada nodo, las alturas de sus subárboles izquierdo y derecho no difieren en
más de 1.

El algoritmo para mantener un árbol AVL equilibrado se basa en reequilibrados locales, de modo que
no es necesario explorar todo el árbol después de cada inserción o borrado.

DEFINICIÓN

La definición no sólo es simple, sino que además conduce a un procedimiento de reequilibrado


relativamente sencillo, y a una longitud de camino media prácticamente idéntica a la del árbol
perfectamente equilibrado.

En un árbol AVL, se pueden realizar en O(lon n) unidades de tiempo, incluso en el peor de los casos,
las siguientes operaciones:

Encontrar un nodo con una clave dada.


Insertar un nodo con una clave dada.
Borrar un nodo con una clave dada.

Vamos a añadir un campo nuevo a la declaración del tipo TArbol, que se llamará factor de equilibrio
(equ), este factor de equilibrio (equ) es la diferencia entre las alturas del árbol derecho y el izquierdo:

FE = altura subárbol derecho - altura subárbol izquierdo;

Por definición, para un árbol AVL, este valor debe ser -1, 0 ó 1.

Condiciones para variar equ:

o La inserción se hace en las hojas


o Cuando creamos un nuevo nodo el campo de equilibrio vale 0, ya que la altura del
subárbol izquierdo es igual que la del derecho.
o Cuando insertamos por la derecha incrementamos el valor del campo de equilibrio.
o Cuando insertamos por la izquierda decrementamos el valor del campo de equilibrio.

INSERCIÓN EN AVL

La inserción se hace siempre en las hojas, y vamos a tener un campo de equilibrio, además una variable
global llamada crecido de tipo BOOLEAN, que en el momento de insertar lo vamos a poner a TRUE
para después controlar si se ha desequilibrado o no.

Se sube restando o sumando 1 hasta llegar a un cero. Si a la hora de sumar o restar un uno se sale del
rango hay que reequilibrar.

DESEQUILIBRIOS Y REEQUILIBRIOS

Al insertar un nuevo nodo en un árbol equilibrado se pueden producir desequilibrios, que quedarán
representados en los casos mostrados a continuación.

93
En las figuras, las cajas rectangulares representan subárboles, y la altura añadida por la inserción se
indica con cruces. Simples transformaciones restauran el equilibrio deseado.

DESEQUILIBRIO IZQUIERDA - IZQUIERDA SIMPLE.

Dado el siguiente Arbol Balanceado, donde se observa que el nodo B ya se encuentra crecido en 1 nivel
en su subarbol izquierdo.

Se añade al subarbol izquierdo del nodo A un nuevo dato "X", lo que causa un desequilibrio en el
arbol, ya que el subarbol izquierdo del nodo B se encuentra crecido ahora en 2 niveles.

Se corrige con la rotación izquierda-izquierda simple, que consiste en subir el nodo A, que tendrá al
final el campo de equilibrio a 0.

DESEQUILIBRIO DERECHA -DERECHA SIMPLE.

94
Se reequilibra con rotación derecha-derecha simple. Es el reflejado del anterior.

La figura muestra la situación antes y después de la rotación simple, donde el elemento X fue insertado
en E, y b corresponde al nodo N. Antes de la inserción, la altura de N es la altura de C+1. Idealmente,
para recuperar la condición de balance se necesitaria bajar A en un nivel y subir E en un nivel, lo cual
se logra cambiando las referencias derecha de b e izquierda de d, quedando este último como nueva
raíz del árbol, N'.

Nótese que ahora el nuevo árbol tiene la misma altura que antes de insertar el elemento, C+1, lo cual
implica que no puede haber nodos desbalanceados más arriba en el árbol, por lo que es necesaria una
sola rotación simple para devolver la condición de balance al árbol. Nótese también que el árbol sigue
cumpliendo con la propiedad de ser ABB.

DESEQUILIBRIO IZQUIERDO-DERECHO COMPUESTO

Dado el siguiente Arbol Balanceado, donde se observa que el nodo B ya se encuentra crecido en 1 nivel
en su subarbol izquierdo.

Se añade al subarbol derecho del nodo A un nuevo dato "X", lo que causa un desequilibrio en el arbol,
ya que el subarbol izquierdo del nodo B se encuentra crecido ahora en 2 niveles.

95
Se corrige con la rotación izquierda-derecha compuesta. Se sube el nodo C que pasa a tener el campo
de equilibrio a 0.

DESEQUILIBRIO DERECHO - IZQUIERDO COMPUESTO

Se reequilibra con rotación derecha-izquierdo compuesto, es el reflejado del anterior.

96
Para el caso de la figura, la altura de N antes de la inserción era G+1. Para recuperar el balance del
árbol es necesario subir C y E y bajar A, lo cual se logra realizando dos rotaciones simples: la primera
entre d y f, y la segunda entre d, ya rotado, y b, obteniéndose el resultado de la figura. A este proceso
de dos rotaciones simples se le conoce como rotación doble, y como la altura del nuevo árbol N' es la
misma que antes de la inserción del elemento, ningún elemento hacia arriba del árbol queda
desbalanceado, por lo que solo es necesaria una rotación doble para recuperar el balance del árbol
después de la inserción. Nótese que el nuevo árbol cumple con la propiedad de ser ABB después de la
rotación doble.

EJEMPLO DE INSERCIONES DE NODOS

A continuación se simulan las inserciones de nodos en un árbol de búsqueda equilibrado, partiendo del
árbol vació. Por comodidad se supone que el campo clave es entero. El factor de equilibrio actual de un
nodo y el nuevo al añadir un nodo se representan como superíndices de los nodos. Los punteros n, nl y
n2 referencia al nodo que viola la condición de equilibrio y a los descendientes en el camino de
búsqueda.

Insertar las claves 68-45-29:

Una vez insertado el nodo con la clave 29, al regresar por el camino de búsqueda cambia los factores de
equilibrio, así el del nodo 45 pasa a -1, y en el nodo 68 se pasa a -2. Se ha roto el criterio de equilibrio y
debe de reestructurarse. Al ser los factores de equilibrio -l y -2 deben de realizarse una rotación de los
nodos II para rehacer el equilibrio. Los movimientos de los punteros para realizar esta rotación II

n^.izqdo = n1^.drcho
n1^.drcho = n
n = n1

Realizada la rotación, los factores de equilibrio serán siempre O en las rotaciones simples. El árbol
queda de la forma siguiente:

97
Inserción de las claves 75 y 90

Una vez insertado el nodo con la clave 90, a la derecha del nodo 75, y regresar por el camino de
búsqueda para así calcular los nuevos factores de equilibrio, se observa que dicho factor queda
incrementado en 1 pues la inserción ha sido por la derecha. En el nodo con clave 68 queda roto el
equilibrio. Para reestructurar se realiza una rotación DL Los movimientos de los punteros para realizar
esta rotación DD:

n^.Drcho = n1^. Izqdo


n1^.Izqdo = n
n = n1

Una vez realizada la rotación, los factores de equilibrio de los nodos implicados será 0, como ocurre en
todas las rotaciones simples, el árbol queda como sigue:

Insertamos la clave 70
98
para insertar el nodo con la clave 70 se sigue el camino : Derecha de 45 izquierda de 75 y se inserta por
la derecha al nodo 68. al regresar por el camino de búsqueda.

Queda, los factores de equilibrio se incrementan en 1 si se fue por la rama derecha, se decrementa en
¡ si se fue por la rama izquierda. En el nodo 45 cl balanceo se ha roto. La rotación de los nados para
reestablecer el equilibrio es DI. Los movimientos de los punteros para realizar esta rotación DI

n1^. Izqdo = n2^. Drcho


n1^. Drcho = n1
n^. Drcho = n2^. Izqdo
n2^. Izqdo = n
n = n2

Los factores de equilibrio de los nodos implicados en la rotación dependen del valor antes de la
inserción del nodo referenciado por n2 según esta tabla:

si n2 ^.fe= -1 n2^.fe = 0 n2^. fe =1


n^.fe 0 0 -1
n1^.fe 1 0 0
n2^.fe 0 0 0

Con esta rotación el árbol quedaría

Inserción de la clave 34

99
El camino seguido para insertar el nodo con clave 34 ha seguido el camino de izquierda dc 68,
izquierda de 45, derecha de 29. Al regresar por el camino de búsqueda, el factor de equilibrio del nodo
29 se incrementa en 1 por seguir el camino de la rama derecha, el del nodo 45 se decrementa en 1 por
seguir la rama izquierda y pasa a ser -2, se ha roto el criterio de equilibrio. La rotación de los nodos
para reestablecer el equilibrio es ID.

Los movimientos de los punteros para realizar esta rotación ID

n1^. Drcho = n2^.Izqdo


n2^. Izgdo = nl
n^. Izgdo = n2^.Drcho
n2^. Drcho = n
n = n2

Los factores de equilibrio de los nodos implicados en la rotación dependen del valor antes de la
inserción del nodo referenciado por n2, según esta tabla:

si n2 ^.fe= -1 n2^.fe = 0 n2^. fe =1


n^.fe 1 0 0
n1^.fe 0 0 -1
n2^.fe 0 0 0

Con esta rotación el árbol quedaría

IMPLEMENTACIÓN DE LA INSERCIÓN

100
Un algoritmo que inserte y reequilibre dependerá en forma crítica de la forma en que se almacene la
información relativa al equilibrio del árbol. Una solución consiste en mantener la información sobre el
equilibrio, de forma completamente implícita, en la estructura misma del árbol. En este caso, sin
embargo, el factor de equilibrio debe "averiguarse" cada vez que se encuentre afectado por una
inserción, con el consiguiente trabajo resultante.

Otra forma (la que vamos a usar) consiste en atribuir a, y almacenar con, cada nodo un factor de
equilibrio explícito. La definición de nodo se amplía entonces a:

TYPE Nodo=RECORD
Clave:Tclave;
Info:Tinfo;
Izq,Der:^Nodo;
Equi:-1..1
END

El proceso de inserción de un nodo consta fundamentalmente de las tres partes consecutivas siguientes:

· Seguir el camino de búsqueda hasta que se comprueba que la clave aún no está en el árbol.
· Insertar el nuevo nodo y determinar el factor de equilibrio resultante.
· Volver siguiendo el camino de búsqueda y comprobar el factor de equilibrio de cada nodo.

Aunque este método realiza algunas comprobaciones que son redundantes, una vez que se establece el
equilibrio, éste no necesita comprobarse en los antecesores del nodo en cuestión.

En cada paso se debe mandar información sobre si la altura del subárbol (en el cual se ha realizado la
inserción) ha aumentado o no. Por lo tanto se extiende la lista de parámetros del procedimiento con el
BOOLEAN Crecido, que debe ser un parámetro de tipo variable, ya que se utiliza para transmitir un
resultado.

procedure insertar (dato : word; var p : pnodo; var h : boolean);


var
p1,p2:puntero;
begin
if p = nil then
begin
new (p);
h:= true;
with p^ do
begin
inf:= dato;
izq:= nil;
der:= nil;
equi:= 0;
contador:= 1;
end;
end
else
if dato < P^.Inf Then
begin
Insertar (dato,p^.Izq,h);
if h then {la rama izq. ha crecido}

101
case p^.equi of
+1: begin
p^.equi:=0;
h:= false;
end;
0: p^.equi:=-1;
-1: begin {reequilibrar}
p1 := p^.izq;
if pl^.equi = -1 then
begin { rotacion II simple }
p^.izq := pl^.der;
p1^.der:=p;
p^.equi=0;
p := p1;
end
else
begin { rotación ID doble}
p2 := p1^.der;
p1^.der := p2^.izq;
p2^.izq := p1;
p^.izq := p2^.der;
p2^.der := p;
if p2^.equi = -1 then p^.equi := +1 else p^.equi :=0;
if p2^.equi = +1 then p1^.equi := -1 else p1^.equi :=0;
p := p2;
end;
p^.equi := 0;
h := false;
end;
end
end
else
if dato > p^.inf then
begin
insertar (dato, p^.der, h);
if h then {la rama derecha ha crecido}
case p^.equi of
-1: begin
p^.equi:=0;
h:=false;
end;
0: p^.equi :=+1;
+1: begin {reequilibrar}
p1 := p^.der;
if p1^.equi = +1 then
begin {rotacion DD simple}
p^.der := p1^.izq;
p1^.izq := p;
p^.equi := 0;
p := p1;
end
else
begin { rotación DI doble }
p2 := p1^.izq;
p1^.izq := p2^.der;
p2^.der := p1;
p^.der := p2^.izq;
p2^.izq := p;
if p2^.equi = +1 then p^.equi := -1 else p^.equi := 0;

102
if p2^.equi = -1 then p1^.equi := +1 else p1^.equi := 0;
p := p2;
end;
p^.equi := 0;
h := false;
end;
end
end
else
begin
p^.contador := p^.contador +1;
h:=false;
end;
end;
end;

BORRADO EN AVL

Vamos a ver solo las distintas posibilidades que se pueden dar al borrar un nodo en el lado derecho. A
la izquierda es simétrico.

EQUILIBRIOS Y DESEQUILIBRIOS

CASO 1. RAIZ.

Caso 1.1: Si alguno de los subárboles que salen de la raíz está vació, entonces el otro estará vació o
solo tiene un nodo, por ser un árbol equilibrado.

Si solo tiene dos nodos se sube el no-borrado hacia arriba.


Si solo está el nodo a borrar, el árbol acaba vació.

Caso 1.2: Si no hay ningún subárbol vació se sube el nodo de más a la derecha del subárbol izquierdo,
se intercambia los valores de la raíz por los de ese nodo, y después es borra este último.

CASO 2. BORRADO EN EL SUBÁRBOL DERECHO.

Caso 2.1: Si el campo de equilibrio tiene un cero, los dos subárboles son iguales. Entonces lo borramos
y el campo de equilibrio pasa a -1.

Caso 2.2: Si tiene un 1, entonces el subárbol derecho tiene una altura más que el izquierdo. Al borrar
equilibramos y pasa a ser 0 ya que restamos 1.

Se puede haber desequilibrado por la izquierda porque al borrar se ha disminuido en uno la altura del
árbol.

103
Caso 2.3: Si tiene un -1, la altura del subárbol izquierdo es mayor que la del derecho. Al borrar en el
derecho se rompe el equilibrio, que pasa a -2.Hay tres casos.

Caso 2.3.1

Caso 2.3.2

Caso 2.3.3

Que visto de otra forma, puede ser:

104
Mediante rotación izquierda-derecha compuesta queda:

Hay otros dos casos, que el bloque 2'2 sea el más pequeño, o que lo sea el 2'1.Tienen altura N-2 y por
lo demás se tratan igual.

EJEMPLO DE BORRADO DE NODOS

Una vez eliminado el nodo siguiendo los criterios establecidos anteriormente, se regresa por el camino
de búsqueda calculando los nuevos factores de equilibrio (Fe) de los nodos visitados. Si en alguno de
los nodos se viola el criterio de equilibrio, debe de restaurarse el equilibrio.

En el algoritmo de inserción, una vez que era efectuada una rotación el proceso terminaba ya que los
nodos antecedentes mantenían el mismo factor de equilibrio. En la eliminación debe de continuar el
proceso puesto que se puede producir más de una rotación en el retroceso realizado por el camino de
búsqueda, pudiendo llegar hasta la raíz del árbol.

En los procedimientos se utiliza el argumento boolean hh, será activado cuando la altura del subárbol
disminuya debido a que se haya eliminado un nodo, o bien porque al reestructurar haya quedado
reducida la altura del subárbol.

105
En el árbol de la figura va a ser eliminado el nodo con la clave 42: al ser un nodo hoja el borrado es
simple, se suprime el nodo. Al volver por el camino de búsqueda para determinar los Fe, resulta que el
Fe del nodo con clave 39 pasaría a ser -2 ya que ha decrementado la altura de la rama derecha, es
violado el criterio de equilibrio. Hay que reestructurar el árbol de raíz 39

Rotación ii por que


N^.feß (-1-1) y
n1^.fe <=0

El árbol resultante es

Ahora se elimina el nodo con la clave 21. Al tener dos ramas, toma el nodo más a la derecha de la rama
izquierda que es el de clave 11. Al volver por el camino de búsqueda para calcular los Fe, el factor de
equilibrio del nodo 11 pasaría a ser 2 y por tanto hay reestructurar el árbol de raíz II.

106
Rotación ID por que
N^.fe ß (1+1) y
n1^.fe < 0

El árbol resultado es :

En estos dos ejemplos se observa que después de realizar la eliminación de un nodo, y cuando se
regresa por el camino de búsqueda, el factor de equilibrio del nodo visitado disminuye en 1 si la
eliminación se hizo por su rama derecha y se incrementa en 1 si la eliminación se hizo por su rama
izquierda. Consideremos ahora este árbol equilibrado:

Se elimina el nodo de clave 25. Como es un nodo hoja se suprime. La supresión se hace por la rama
izquierda, por lo que la altura de la rama derecha correspondiente aumenta en 1, y lo mismo ocurre con
el factor de equilibrio.

107
Los factores de equilibrio quedan:

Rotación DD por que


N^.fe = 1+1
N1^.fe >= 1

El árbol resultante es:

Al seguir regresando por el camino de búsqueda, el nodo raíz debe de incrementar su Fe con lo que
pasaría a +2, por consiguiente hay que restaurar el árbol, la rotación es derecha-izquierda ya que

N^.fe 1+1 y n1^.fe <0

El nuevo árbol queda así es

108
IMPLEMENTACIÓN DE LA ELIMINACIÓN

En el algoritmo de supresión se introducen dos procedimientos simétricos de equilibrado: Equilibrar1


se invoca cuando la altura de la rama izquierda ha disminuido y Equilibnar2 se invocará cuando la
altura de la rama derecha haya disminuido.

En el procedimiento Equilibrar1 al disminuirla altura de la rama izquierda, el factor de equilibrio se


incrementa en 1. Por lo que de violarse el factor de equilibrio la rotación que se produce es del tipo
derecha-derecha, o derecha-izquierda.

procedure Rotaciondd (var N: Ptrae; Nl: ptrae);


begin
N^.Drcho:=N1^.Izqdo;
N1^. Izgdo:=n;
if N1^. Fe= 1 then
begin
N^.Fe:=0;
N1^.Fe:=0
end
else
begin
N^.Fe:= 1;
Nl^.Fe:= -1;
end,
N :=N1;
end;

procedure Rotaciondi (var N: Ptrae; Nl: Ptrae);


var
N2 : Ptrae;
begin
N2:=Nl^.lzqdo;
N^.Drcho:=N2^.Izqdo;
N2^.Izqdo:=N;
Nl^.lzqdo:=N2^.Drcho;
N2^.Drcho:=Nl;
if (N2^.Fe=l ) then N^.Fe=-l else N^. Fe: =0
if (N2^.Fe=-l) then N1^.Fe:=1 else Nl^.Fe:=0;
N2^.Fe:=0;
N :=N2;
end;

109
procedure Rotacionii(var N: Ftrae; N1: Ptrae);
begin
N^.Izqdo:= N1^.Drcho;
N1^.Drcho:=N;
if N1^.Fe= -1 then
begin
N^.Fe :=0;
N1^.Fe := 0;
end
else
begin
N^.Fe :=-1;
N1^.Fe := 1
end;
N := N1;
end;

procedure Rotacionid(Vat N:Ptrae; N1:Ptrae)


var
n2:ptrae;
begin
N2= N1^.drcho;
N^.Izqdo:= N2^.Drcho;
N2^.Drcho:= N;
N1^.Drcho:= N2^Izqdo;
N2^.Izqdo:= Nl;
if (N2^.f2=1) then N1^.Fe:=-1 else N1^.Fe:=O;
if (N2^.Fe=-l) then N^.Fe:=l else N^..Fe:=O;
N2^.Fe:=0;
N:= N2;
end;

procedure Equilibrarl(var N:Ptrae: var hh; bolean)


{hh: activado cuando ha disminuido en altura la rama izquierda del nodo N}
var
Nl :Ptrae:
begin
case N^.Fe of
-1: N^.Fe:= O;
O: begin
N^.Fe:= 1;
hh:= false
end;
1: begin {Hay que restaurar el equilibrio}
Nl:= N^.drcho;
{Es determinado el tipo de rotación}
if N1^. Fe >= 0 then
begin
if N1^. Fe = 0 then
hh;= false; {No disminuye de nuevo la altura}
Rotaciondd(N, N1)
end
else
Rotaciondi(N, N1)
end;
end;
end;

110
En el procedimiento Equilibnar2 al disminuir la altura de la rama derecha, el factor de equilibrio queda
decrementado en 1. De producirse una violación del criterio de equilibrio, la rotación será del tipo
izquierda-izquierda, o izquierda-derecha.

procedure Equilibrar2(var N:Ptrae: var hh; bolean)


{hh: activado cuando ha disminuido en altura la rama izquierda del nodo N}
var
Nl :Ptrae:
begin
case N^.Fe of
1: N^.Fe := 0;
0: begin
N^.Fe := -1;
hh:= false
end;
-1: begin {Hay que restaurar el equilibrio}
Nl:= N^.Izqdo;
{Es determinado el tipo de rotación}
if N1^.Fe <= 0 then
begin
if N1^.Fe = 0 then
hh;= false; {No disminuye de nuevo la altura}
Rotacion_ii(N, N1)
end
else
Rotacion_id(N, Nl)
end;
end;
end;

A continuación son escritos los procedimientos de borrar_balanceado y el procedimiento anidado bor.


El algoritmo que sigue es el mismo que el de borrado en los árboles de búsqueda sin criterio de
equilibrio. La principal diferencia está en que en el momento que una rama disminuye en altura es
llamado el procedimiento respectivo de equilibrar.

procedure borrar_balanceado(var R:Ptrae;var hh:boolean;X: Tipoinfo)


var
q: Ptrae;

procedure bor(var d: ptrae; var hh: boolean);


begin
if d^.Drcho<>nil then
begin
bor(d^.Drcho, hh);
if hh then {Ha disminuido rama derecha}
Equilibrar2 (d,hh)
end
else
begin
q^.info:=d^.info;
q: =d;
d:=d^.Izqdo;
hh:= true
end;
end;

begin

111
if not ArbolVacio( R ) then
if x < R^.info then
begin
borrar_balanceado(R^.lzqdo,hh , x):
if hh then
Equilibrarl.(R, hh)
end
else
if x>R^.info then begin
borrar_balanceado(R^.Drcho.,hh ,x)
if hh then
Equilibrar2(R, Hh)
end
else
begin {ha sido encontrado el nodo}
q:= R;
if q^.Drcho= nil then
begin
R:= q^.Izqdo;
hh:= true{Disminuye la altura}
end
else
if q ^.Izqdo=nil then
begin
R:=q^.drcho;
hh:= true
end
else
begin
bor(q^.Izqdo,hh);
if hh then
Equilibrar1(R, hh)
end;
dispose(q);
end;
end;

112
ÁRBOLES BINARIOS DE EXPRESIONES

Los árboles binarios se utilizan para almacenar expresiones. Por ejemplo, el


arbol de la figura representa la expresión (A+B)*C. Las expresiones
matemáticas se pueden escribir según diversos tipos de notaciones. La
notación infija es la empleada habitualmente y requiere el uso de paréntesis,
pero únicamente cuando es necesario modificar la prioridad entre los distintos
operadores.

CONSTRUCCIÓN A PARTIR DE UNA EXPRESIÓN EN NOTACIÓN CONVENCIONAL

Para construir se utilizaran, como estructura de datos auxiliares, una pila de punteros a los nodos de
un árbol y otra pila de operadores para retenerlos temporalmente hasta que llegue el momento de
incorporarlos al árbol. Los pasos a seguir son lo siguientes.
6. Cuando se lee un OPERANDO se crea un árbol de un nodo y se mete el apuntador a el en
correspondiente pila.
7. Cuando se lee un OPERADOR se retiene en la pila de operadores. Los operadores se van poniendo
en esta pila hasta encontrar uno con mayor o igual prioridad, en cuyo caso se sacan los que hubiera
en la pila de mayor o igual prioridad y se coloca en ella este ultimo operador leido.
8. Cuando se lee un PARÉNTESIS IZQUIERDO se retiene en la pila de operadores.
9. Cuando se lee un PARÉNTESIS DERECHO se sacan los OPERADORES que hubiera en la pila de
operadores hasta encontrar el paréntesis izquierdo.
10. El proceso termina cuando se acaba la entrada y la pila de operadores queda vacía.
Nota: Al sacar de la pila de operadores uno de ellos, extraer de la pila de punteros los dos últimos
apuntadores. Con estos tres elementos, se forma un nuevo árbol cuya raíz almacena el operador y
los punteros anteriores. El apuntador a este nuevo árbol se coloca ahora en la pila de apuntadores.

Ejemplo: Sea la expresión :


Q= 4+5^(2*3)+8

1.-

113
2.- El ) saca los operadores de la pila hasta el (

3.- El + saca de la pila todos los operadores con mayor prioridad que el y l continuación se coloca el

4.-

5.-

114
TEMA 7

GRAFOS
OBJETIVOS

Analizar e implementar estructuras tipo malla para la representación de sistemas. Desarrollar


algoritmos de procesamiento de una manera óptima.

CONTENIDO

7.1 Definiciones
7.2 Almacenamiento de un Grafo en Memoria
7.3 Aplicaciones

Los grafos son estructuras de datos, utilizadas comúnmente en el manejo de redes, en la construcción
de circuitos eléctricos, en las estrategias de ventas, en el área de economía, cartografía y otras muchas
áreas del conocimiento.

7.1 DEFINICIONES.
7.1.1 Grafo

Un grafo es una estructura de datos compuesta por vértices y arcos. gráficamente un grafo se puede ver
así:

Figura 7.1 Grafo

El conjunto de vértices es: v = {A, B, C, D, E, F, G, H, I, J, K, L}

Un arco une dos vértices adyacentes. Por ejemplo el arco JK o el arco EG o GE. No se puede hablar del
arco AC pero si del AB y del BC.

7.1.2 Grafo Dirigido

115
Un grafo dirigido o dígrafo, es aquel en el que sus arcos tienen una orientación, por ejemplo:

Figura 7.2 Grafo con arcos dirigidos

El arco SERVIDOR-CONTROLADOR, es completamente válido. En este dígrafo no existe el arco


CONTROLADOR-SERVIDOR.

El conjunto de vértices del dígrafo anterior es:

V = { SERVIDOR, ESTACION UNO, ESTACION DOS, CONTROLADOR, DISPOSITIVO DE


SALIDA, TERMINAL BRUTA }

7.1.3 Adyacencia

Se dice que existe adyacencia entre dos vértices si están unidos por un arco. También se dice que estos
vértices son adjuntos. Por ejemplo para el siguiente grafo:

Figura 7.3 Adyacencia

los vértices A y B son adyacentes. En el caso de dígrafos, la adyacencia se expresa desde o hacia.
Como en el siguiente ejemplo:

116
Figura 7.4 Adyacencia en un dígrafo

Para este caso, se dice que A es adyacente hacia B, y D es adyacente hacia E, A es adyacente desde C y
a su vez D desde B. Para simplificar se emplea la siguiente notación:

• AB: A es adyacente hacia B y B es adyacente desde A.


• CA: C es adyacente hacia A y A es adyacente desde C.

7.1.4 Incidencia

Los arcos inciden en los vértices. Un arco es incidente en un vértice, si una de sus puntas llega a ese
vértice. Por ejemplo:

Figura 7.5 Incidencia en un grafo

El arco a, es incidente en A y B.

Para el caso de los dígrafos:

Figura 7.6 Incidencia en un dígrafo.

El arco a es incidente en B. Este arco no es incidente en A ya que ese arco sale de A, y nunca llega a A.

7.1.5 Grafos y Digrafos Fuertemente Conectados

Un grafo está fuertemente conectado si desde cualquier vértice se puede llegar a todos los demás; o si
desde cualquier vértice, se pueden visitar todos los demás. Por ejemplo:

117
Figura 7.8 Grafo fuertemente conectado

De la misma manera, un dígrafo está fuertemente si desde cualquier vértice se pueden visitar todos los
demás. Por ejemplo:

Figura 7.9 Dígrafo fuertemente conectado.

Desde los vértices A,B, C, D y E se puede llegar a todos los otros vértices. Por ello este dígrafo está
fuertemente conectado.

7.1.6 Grafos y Digrafos débilmente conectados

Un grafo o dígrafo es débilmente conectado, si por lo menos desde un vértice no podemos llegar a los
demás. Esta propiedad la cumple el siguiente dígrafo:

Figura 7.10 Dígrafo débilmente conectado.

En este caso desde B no se puede llegar a ningún otro nodo, por ello es un dígrafo débilmente
conectado.

7.1.7 Camino Simple

118
Se presenta cuando a partir de cualquier vértice, se puede recorrer la estructura, sin repetir ningún
vértice ni ningún arco. Por ejemplo:

Figura 7.11 Camino simple

Partiendo del vértice C, se puede recorrer todo el grafo, sin repetir vértices ni arcos.

7.1.8 Grafo de Euler

Es un camino cerrado que recorre todos los arcos del grafo. Es decir se pueden visitar los vértices o
nodos cuantas veces sea necesario, pero los arcos solo se pueden recorrer una vez.
Ejemplo:

Figura 7.12 Grafo de Euler

El recorrido desde el vértice A puede ser : ACDEFGBEHDAHBA. Como se puede observar los nodos
D, E, B y H son visitados dos veces, el nodo A es visitado 3 veces pero todos los arcos son recorridos
una sola vez.

7.1.9 Circuito Hamiltoniano

Si partiendo de cualquier vértice , se pueden recorrer todos los vértices sin repetir ninguno, y
finalmente se llega al vértice origen. En el grafo anterior se encuentra el siguiente circuito
Hamiltoniano : A C D E F G B H A.

Un grafo Hamiltoniano que recorre n vértices, consiste exactamente de n arcos.

7.1.10 Grado de un vertice

Es el número de arcos que inciden en un vértice. Para los dígrafos pueden existir para cada vértice dos
tipos de grado:

• GRADO DE ENTRADA

119
• GRADO DE SALIDA

Los grados de entrada de un vértice en un dígrafo, se determinan por el número de arcos que inciden en
el vértice y los grados de salida se determinan por el número de arcos que parten del vértice.

Figura 7.13 Grados de entrada y de salida.

Para la figura anterior, los grados de entrada y salida para cada vértice son:

GRADO- GRADO-
VERTICE
ENTRADA SALIDA
A 2 0
B 2 0
C 1 3
D 0 3
E 2 1

7.1.11 Grafos Regulares

Un grafo se dice que es regular , si todos los vértices tienen el mismo grado. Por ejemplo:

Figura 7.14 Grafo Regular

120
7.1.12 Arco Cíclico

Un arco es cíclico si parte de un vértice y llega al mismo vértice.

Ejemplo:

Figura 7.15 Grafo con arcos cíclicos (AA y BB)

En la anterior figura se tienen dos arcos cíclicos, uno en A y el otro en B.

7.1.13 Grafos Simples

Un grafo es simple, si no tiene arcos cíclicos y existe un solo arco entre dos vértices.

7.1.14 Grafos Completos

Un grafo es completo si cada vértice tiene un grado igual a n-1, donde n es el número de vértices que
componen el grafo. Por ejemplo los siguientes grafos son completos:

Figura 7.17 Grafos completos de


2, 3, 4, 5 y 6 vértices.

121
7.2 ALMACENAMIENTO DE UN GRAFO EN MEMORIA.
Existen varias formas de almacenar estas estructuras en memoria.

• COMO LISTA DE ADYACENCIA


• COMO MATRIZ DE ADYACENCIA
• COMO MATRIZ DE INCIDENCIA

Figura 7.18 Grafo a almacenar en memoria.

7.2.1 Lista De Adyacencia

Para almacenar un grafo en una lista de adyacencia, debemos trabajar con un arreglo de listas. Cada
una de estas listas almacena los adjuntos a un vértice dado, comenzando por los vértices de más arriba
y los de más a la izquierda como orden de prioridad.

Por ejemplo una lista tendrá almacenados todos los adjuntos al vértice E; otra lista tendrá almacenados
todos los adjuntos al vértice I, etc. Esta es la lista de adyacencia para el grafo anterior (figura 7.19):

Figura 7.19 Lista de adyacencia del


grafo de la figura 7.18

122
7.2.1.1 Almacenamiento en memoria. Grafo es un arreglo de estructuras de tipo nodo. Aquí la
estructura nodo está conformada por dos campos. El primero es el campo indice que es el identificador
de un nodo. El segundo es el campo siguiente que es un apuntador a otra estructura de tipo nodo.

La rutina Iniciar_grafo se encarga de colocar un cero en el campo de indice de cada elemento de la


estructura grafo, como también colocar el valor NULO para el campo siguiente, donde nv es el número
de vértices del grafo.

INICIAR_GRAFO ( nv)
Inicio

i=1
Mientras ( i <= nv)
Ind[i]= 0
Sig[i]=A
i=i + 1
Fin-Mientras

Fin

El algoritmo Leer_grafo se encarga de leer el índice de cada vértice y sus correspondientes adjuntos
(que forman una lista) para así formar el grafo.

LEER_GRAFO(nv)
Inicio

INICIAR_GRAFO(nv)
i =1
Mientras ( i <= nv) Ejecute
nad =NumAdjuntos[i]
j =1
Mientras( j <= nad) Ejecute
ad =Lea(adjunto)
ins _ grafo (grafo, i, ad )
j=j + 1
Fin-Mientras
i =i + 1
Fin-Mientras

Fin

El algoritmo ins_grafo se encarga de crear el nodo en memoria que conformará la lista de adyacencia
para el vértice i, dentro del arreglo grafo.

INS_GRAFO (grafo, i, ad)


Inicio

ASIGNA_NODO (nuevo, ad)


sig [i] =nuevo
q =A
p =*grafo [i].sig

Mientras (p=A) Haga

123
q =p
p = *p.sig
Fin-Mientras

Si (q = A)
*grafo [i].sig = nuevo
Sino
*q.sig = nuevo
Fin-Si

Fin

El algoritmo Recorrer_grafo ejecuta la operación de Visita a cada nodo adjunto de todos los vértices de
un grafo.

Recorrer_grafo (grafo, nv)


Inicio

i =1
Mientras (i<= nv)
p =grafo [i]
Visite_Vertice (p)
q =*grafo [i].sig

Mientras (q =A)
Visite_Vertice (q)
q =*q.sig
Fin-Mientras

i=i +1
Fin-Mientras

Fin

7.2.2 Matriz De Adyacencia

En este caso a cada elemento M[ i , j ], se le asigna un 0 si el vértice i no es adjunto al vértice j.; y un 1


en caso contrario. Para el mismo grafo (figura 7.18), la matriz de adyacencia es:

124
Figura 7.20 Matriz de adyacencia
para el grafo de la figura 7.18

Como se puede observar la matriz de adyacencia es simétrica.

7.2.2.1 Almacenamiento en memoria. Se tiene una matriz bidimensional denominada grafo. El orden
de la matriz es nv * nv, donde nv es el número de vértices en el grafo. Cada elemento matriz[i,j] tiene
un valor de 0 si el nodo ( vértice ) j es adjunto al nodo i.

Leer_grafo (grafo)
Inicio

nv =Leer_Numero_de_Vertices(grafo)
lniciar_grafo(grafo,nv)
i =1
Mientras (i <= nv)

j =Leer_adjunto(grafo[i])

Mientras (j )
matriz [i, j] =1
j =Leer_adjunto(grafo[j])
Fin-Mientras

i =i + 1

Fin-Mientras

Fin

7.2.3 Matriz De Incidencia

Esta estructura es aplicable para los dígrafos. En la matriz de incidencia cada fila representa a cada uno
de los nodos del grafo, y las columnas los posibles arcos de dicho grafo; en la casilla M [i ,j ], aparecerá
un 1 cuando el nodo de la fila i es inicial, y un -1, cuando el nodo i es final. En la siguiente figura
aparece un dígrafo y su correspondiente matriz de incidencia:

Figura 7.21 Matriz de incidencia

125
7.2.3.1 Almacenamiento en memoria. Para este caso también se maneja una matriz bidimensional
denominada grafo, pero ahora el elemento grafo[i, j] será igual a 1 si el nodo i es inicial, y será igual a
-1 si es el nodo final. Tendrá un valor de cero si los dos nodos, el nodo i y el nodo j no están conectados
directamente.

Leer_grafo (grafo)
Inicio

nv =Lea numero de vértices(grafo)


Iniciar_grafo(grafo,nv)
i =1

Mientras (i <= nv) Haga

j =Leer_nodo_de_salida(grafo[i])

Mientras (j ) Haga
grafo [i, j] = 1
j =Leer_nodo_de_salida(grafo[j])
Fin-Mientras

j =Leer nodo de entrada(grafo[i])

Mientras ( j <= nv ) Haga


grafo[i, j] = -1
j =Leer_nodo_de_entrada(grafo[j])
Fin-Mientras

i =i + 1

Fin-Mientras

Fin

7.3 APLICACIONES.
Dentro de las aplicaciones clásicas y fundamentales se encuentra el estudio de redes. En este campo se
han desarrollado técnicas como son Cálculo del Flujo Máximo y Cálculo del Costo Mínimo; en ambos
casos se trata de optimización en redes.

Para el Flujo máximo existen 3 algoritmos conocidos:

• METODO DE CORTES
• METODO DE GRAFICO AUXILIAR
• METODO DE FORD - FULKERSON

Para el Costo Mínimo existen 2 algoritmos conocidos:

• METODO DE GRAFICOS DIRIGIDOS


• METODO DE DIJKSTRA

126
7.3.1 Algoritmo De Dijkstra

Este algoritmo usado para determinar el costo mínimo, es el más implementado en ciertos dispositivos
de Hardware. Se encarga de determinar las rutas con el menor costo, desde un nodo origen hacia todos
los otros nodos de un grafo.

El algoritmo va pasando por diferentes estados. En el estado K, las rutas más cortas a los K nodos más
cercanos han sido determinadas y estos nodos están dentro de un grupo denominado M. En el estado K
+ 1, un nodo que no está en M y que tiene la ruta más corta desde el nodo origen es incluido en M.

Al final todos los nodos estaran en M, y sus rutas desde el origen habran sido determinadas.

El algoritmo puede ser formalmente descrito como sigue:

N = número de nodos en el grafo( red ).


s = nodo fuente
M = grupo de nodos que han sido incorporados por el algoritmo.
dij= Costo del enlace desde el nodo i al nodo j; dii = 0 y dij =
si los dos nodos no están directamente conectados;
dij>= 0 si los dos nodos están directamente conectados.
Dn= costo de la ruta con el menor costo, desde el nodo s al nodo n.

El algoritmo tiene tres pasos; los pasos 2 y 3 son repetidos hasta que M = N. Es decir tales pasos son
repetidos hasta que las rutas finales han sido asignadas a todos los nodos de la red:

1. Inicializar:

M = {s}
// Al grupo de nodos M solo se incorpora el nodo origen.
Dn = dsn para n >s
// Los costos de las rutas iniciales hacia los nodos vecinos son simplemente los costos del enlace.

2. Encontrar el nodo vecino que no está en M y que tiene el enlace con menor costo desde el nodo s. El
nodo encontrado se incorpora a M.
Encontrar w M tal que Dw = min { Dj } para j M
Insertar w a M.

3. Actualizar las rutas con el costo mínimo:


Dn = min[Dn, Dw + dwm] para todo j M
Sí el último término es el mínimo, la ruta de s a n es ahora la uta desde s a w concatenada con el enlace
que va de w a n.

Cada iteración de los pasos 2 y 3 coloca un nuevo nodo en M y define la ruta con costo mínimo desde s
hasta ese nodo. Esa ruta solo pasa a través de nodos que están en M.

127
Figura 7.22 Dígrafo

La siguiente tabla muestra el resultado de aplicar el algoritmo sobre el grafo de la figura 7.22, usando s
=1 como nodo de origen.

La siguiente figura muestra el resultado de cada iteración:

128
Figura 7.23 Algoritmo de Dijkstra

129