Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
VICERRECTORÍA ACADÉMICA
ESCUELA DE CIENCIAS EXACTAS Y NATURALES
CÁTEDRA DE TECNOLOGÍA DE SISTEMAS
CARRERA DE INGENIERÍA EN INFORMÁTICA
Material Complementario
para el curso
Estructura de datos
Código 825
Elaborado por
Enrique Gómez Jiménez
Créditos:
Producción académica y
asesoría metodológica:
Ana Láscaris-Comneno Slepuhin
Encargada de Cátedra:
Karol Castro Cháves
Revisión filológica:
Óscar Alvarado Vega
2
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Tabla de Contenidos
PRESENTACIÓN ................................................................................................................................ 4
ALGORITMOS ...............................................................................................................................................................5
DISEÑO Y ANÁLISIS DE ALGORITMOS...........................................................................................................................5
¿QUÉ ES UNA ESTRUCTURA DE DATOS? ....................................................................................................................6
ABSTRACCIÓN DE DATOS ............................................................................................................................................6
TIPOS DE DATOS ABSTRACTOS (TDA)........................................................................................................................6
TIPOS DE ESTRUCTURAS DE DATOS ESENCIALES:......................................................................................................6
MERGESORT ................................................................................................................................................................8
QUICKSORT .................................................................................................................................................................9
SELECCIÓN RÁPIDA ...................................................................................................................................................12
REPRESENTACIÓN .....................................................................................................................................................25
Matriz de Adyacencia.........................................................................................................................................25
Lista de adyacencias..........................................................................................................................................26
PROBLEMA DEL CAMINO MÍNIMO SIN PESOS .............................................................................................................27
PROBLEMA DEL CAMINO MÍNIMO CON PESOS POSITIVOS (DIJKSTRA) ......................................................................28
PROBLEMA DEL CAMINO MÍNIMO CON COSTES NEGATIVOS (DIJKSTRA)...................................................................33
PILAS .........................................................................................................................................................................36
ARREGLOS .................................................................................................................................................................36
Arreglos unidimensionales: ...............................................................................................................................37
COLAS .......................................................................................................................................................................40
Árboles generales:..............................................................................................................................................46
ÁrbolesbBinarios:................................................................................................................................................46
Árboles y recursividad:.......................................................................................................................................48
RECORRIDO DE ÁRBOLES ..........................................................................................................................................50
Recorrido en postorden .....................................................................................................................................50
Recorrido en orden simétrico............................................................................................................................51
Recorrido en preorden .......................................................................................................................................51
Operaciones ........................................................................................................................................................63
AVL .......................................................................................................................................................................67
Árboles Rojinegros .............................................................................................................................................81
AA-Árboles...........................................................................................................................................................91
B-Árboles ...........................................................................................................................................................100
TABLAS HASH ............................................................................................................................. 101
3
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Presentación
Este material está diseñado para reforzar el curso de Estructura de datos (código
825). Está creado para los estudiantes de la carrera Informática Administrativa. Su
propósito es brindar a los estudiantes una guía práctica que les permita reforzar la
temática que se revisa en las tutorías presenciales de laboratorio.
El material es un complemento práctico del libro de texto del curso, de la Orientación del
curso y de la Guía de estudio respectiva.
Este será útil a todos los estudiantes como medio de preparación para la tutoría
presencial. En especial, este documento le ayudará al estudiante cuando no pueda
asistir a la tutoría, ya que aquí podrá encontrar una visión general práctica de los temas
de estudio del curso.
El curso adopta un enfoque novedoso separando la presentación de cada estructura en
su especificación (a través de una interfaz Java) e implementación. Este enfoque
proporciona varios beneficios, entre ellos la promoción del pensamiento abstracto. Antes
de conocer la implementación se presenta la interfaz de la clase, motivando así al
estudiante a pensar desde el principio sobre la funcionalidad y la eficiencia potencial de
las distintas estructuras de datos.
Los estudiantes que utilizarán el libro de texto que brinda el curso de Estructura de
datos deben poseer previamente conocimientos básicos sobre algún lenguaje de
programación modular u orientado a objetos. El curso presenta el material utilizando el
lenguaje de programación Java. Este es un lenguaje relativamente reciente, que a
menudo se compara con C++. Java ofrece diversas ventajas; muchos programadores lo
consideran un lenguaje más seguro, portable y fácil de usar que C++.
4
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Algoritmos
Computacionalmente, podríamos definir algoritmo como un conjunto de instrucciones
claramente especificadas que el ordenador debe seguir para resolver un problema. Una
vez que tenemos la idea práctica de cómo llevar a cabo esos pasos, sea secuencial o
concurrentemente, lo podríamos implementar en un lenguaje de programación.
5
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
El análisis mediante una función cuadrática tiene como término dominante N2 por alguna
constante.
En el caso del análisis que utiliza una función cúbica, se determina mediante N3
multiplicado por alguna constante. Por ejemplo, 10 N3 + N2 + 40N + 80 es una función
cúbica.
Estructura de datos
Para representar adecuadamente un algoritmo, se requiere la existencia de estructuras
de datos también adecuadas. Estas estructuras, además, deben contar con operaciones
que le permitan gestionar las estructuras que contienen. Esa representación de datos y
las operaciones permisibles sobre ellas es lo que se conoce como estructura de datos.
Abstracción de datos
La abstracción es un proceso mental que permite representar un modelo de la vida real
a través de sus rasgos esenciales. En la estructura de datos, la abstracción representa
una técnica o metodología que permite diseñar estructuras de datos, extrayendo sus
características particulares, y representando su funcionalidad a través de un modelo
fácilmente entendible.
6
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
9 Pilas
9 Listas
9 Listas enlazadas
9 Árboles
9 Árboles binarios de búsqueda
9 Tablas Hash
9 Colas de prioridad
A continuación, se presentará brevemente cada una de estas estructuras:
Algoritmos de ordenación
Los métodos de ordenamiento Shellsort constituyen el algoritmo más largo y
complejo de la ordenación por inserción, pero el más simple de los algoritmos más
rápidos. Shellsort tiene la mecánica de comparar primero los elementos que están muy
separados, para después hacerlo con los más cercanos, reduciéndose gradualmente al
método de inserción. En resumen, la idea principal consiste en disminuir movimientos
de datos, considerando:
a) Comparar primero los datos más alejados (los que distan entre sí).
b) Disminuir los intervalos para ir comparando datos más cercanos.
c) Reducirse hasta utilizar el método de inserción en el que la distancia entre los
datos que comparamos es uno.
7
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
10. //
11. public static void shellSort( int a[ ]){
12. for( int gap = a.length / 2; gap > 0; gap = gap == 2 ? 1 : (int) ( gap / 2.2 ) ){
13. for( int i = gap; i < a.length; i++ )
14. {
15. int tmp = a[ i ];
16. int j;
17. for(j = i; j >= gap && tmp < a[ j - gap ] ; j -= gap ){
18. a[ j ] = a[ j - gap ];
19. }
20. a[ j ] = tmp;
21. }
22. }
23. }
24. }//class ShellSort
En resumen, el ordenamiento Shellsort presentado en el programa anterior consiste en:
• Suponer un arreglo[]
• Elegir un intervalo gap
• Ordenar por inserción los elementos que distan entre sí ese intervalo
• Elegir un nuevo intervalo (de tamaño menor)
• Volver a ordenar por inserción
• Repetir el proceso hasta que el tamaño del intervalo sea 1
Mergesort
El algoritmo de ordenación Mergesort utiliza la mecánica divide y vencerás.
Básicamente consiste en lo siguiente:
a) Suponer un arreglo[]
b) Si el número de elementos es 0 o 1 termina
c) Si no se divide el arreglo por la mitad
d) Se ordenan recursivamente los dos subvectores resultantes
e) Se mezclan las dos mitades ordenadas en un arreglo ordenado
8
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Quicksort
El método de ordenamiento Quicksort es el más eficiente para la clasificación interna
de los elementos de una estructura de datos, como lo es un vector. La funcionalidad de
este método consiste en clasificar un arreglo o vector A[1], …, A[n] tomando del arreglo
un valor clave denominado pivote. Sobre este pivote se reorganizan los demás
elementos del arreglo. Una idea sobre cómo trabaja es la siguiente:
• Se escoge un elemento clave del arreglo y se le denomina pivote. Se espera que
una mitad de los elementos del arreglo precedan a este pivote y la otra mitad lo
sucedan. Por ende, el pivote debe ser lo más cercano al valor medio de la clave
del arreglo.
9
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
• Se permutan los elementos del arreglo con el fin de que para algún elemento j
todos los elementos que signifiquen claves menores que el pivote aparezcan en
A[1], …, A[j] y todos aquellos con claves (valores) iguales al pivote o mayores que
éste aparezcan en A[j+1], …, A[n]
• Se aplica recursivamente Quicksort a A[1], …, A[j] y A[j-1], …, A[n] para ordenar
cada grupo de elementos.
En la figura 3 se presentan las secuencias recursivas que se utiliza para la clasificación
rápida (Quicksort), en este caso para ordenar la secuencia de enteros 3,1,4,1,5,9,2,6,5.
En cada secuencia se ha seleccionado como elemento pivote (v) al mayor de los dos
valores distintos que se encuentran más a la izquierda. La recursión termina cuando la
porción del arreglo posee valores similares.
En el caso de las secuencias del ordenamiento rápido, indicados en la figura 3, se
muestran los diferentes niveles de ejecución, los cuales constan de 2 pasos: uno antes
de dividir cada subarreglo y el segundo después. Todo concluye cuando se desea
particionar el subarreglo, y sus elementos están conformados por elementos similares o
se encuentran ordenados.
33 11 44 11 55 99 22 66 55 33
Partición v=3
22 11 11 44 55 99 22 66 55 33
Nivel 1
22 11 11 44 55 99 22 66 55 33
Partición v=2 Partición v=5
11 11 22 44 33 33 99 66 55 55 Nivel 2
11 11 22 44 33 33 99 66 55 55
Concluido Concluido Partición v=4 Partición v=9
33 33 44 55 66 55 99 Nivel 3
33 33 44 55 66 55 99
Concluido Concluido Partición v=6 Concluido
55 55 66 Nivel 4
10
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
11
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
31. ;
32. if ( i < j )
33. intercambiarReferencias( a, i, j );
34. else
35. break;
36. }
37. //colocar el pivote
38. intercambiarReferencias( a, i, fin -1 );
39.
40. quicksort( a, ini, i – 1 ); //ordenar elementos pequeños
41. quicksort( a, i + 1, fin ); //ordenar elementos grandes
42. }
43. }
44. public static void Quicksort ( Comparable [ ] a )
45. Quicksort ( a, 0, a.length – 1 );
46. }
Selección rápida
El ordenamiento por selección rápida se asemeja al algoritmo Quicksort,
diferenciándose en que solamente realiza una llamada recursiva en comparación con las
dos que este hace. Básicamente, consiste en encontrar el k-ésimo elemento menor de
una colección de N elementos. La implementación en Java de este algoritmo es la
siguiente:
1. //Método de selección interno que hace las llamadas recursivas
2. //coloca el k-ésimo elemento en a[k-1]
3. //la llamada inicial es seleccionRapida(a,0,a.length,k)
4.
5. private static void
6. SeleccionRapida(Comparable [] a, int ini, int fin, int k)
7. {
8. If (ini + LIMITE > fin)
9. OrdenacionPorInsercion(a,ini,fin)
12
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
10. else
11. //ordenar ini, medio, fin
12. int medio = (ini + fin) / 2:
13. if (a[medio].menorQue(a[ini]))
14. intercambiarReferencias(a,ini,medio);
15. if (a[fin].menorQue(a[ini]))
16. intercambiarReferencias(a,ini,fin);
17. if (a[fin].menorQue(a[medio]))
18. intercambiarReferencias(a,medio,fin);
19. //colocar el pivote en la posición fin-1
20. intercambiarReferencias(a,medio, fin-1);
21. Comparable pivote = a[fin-1];
22. //Iniciar la partición
23. int i, j;
24. for (i=ini, j=fin-1; ;)
25. while(a[++i].menorQue(pivote))
26. ;
27. while(pivote.menorQue(a[--j]))
28. ;
29. if(i<j)
30. intercambiarReferencias(a,i,j);
31. else
32. break;
33. }
34. //colocar el pivote
35. intercambiarReferencias(a,i, fin-1);
36. //recursión; solo cambia esta parte
37. if (k-1 < i)
38. seleccionRapida(a,ini,i-1,k);
39. else if(k-1>i)
40. seleccionRapida(a,i+1,fin,k);
13
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
41. }
42. }
/**
* Utilizando Shellsort
14
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
*/
public static <AnyType extends Comparable<? super AnyType>>
void shellsort( AnyType [ ] a )
{
int j;
for( int gap = a.length / 2; gap > 0; gap /= 2 )
for( int i = gap; i < a.length; i++ )
{
AnyType tmp = a[ i ];
for( j = i; j >= gap &&
tmp.compareTo( a[ j - gap ] ) < 0; j -= gap )
a[ j ] = a[ j - gap ];
a[ j ] = tmp;
}
}
/**
* Utilizando Heapsort Estandard
*/
public static <AnyType extends Comparable<? super AnyType>>
void heapsort( AnyType [ ] a )
{
for( int i = a.length / 2; i >= 0; i-- ) /* buildHeap */
percDown( a, i, a.length );
for( int i = a.length - 1; i > 0; i-- )
{
swapReferences( a, 0, i ); /* deleteMax */
percDown( a, 0, i );
}
}
/**
15
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
/**
* Método interno de heapsort el cual es utilizado en
* deleteMax y buildHeap.
*/
private static <AnyType extends Comparable<? super AnyType>>
void percDown( AnyType [ ] a, int i, int n )
{
int child;
AnyType tmp;
/**
16
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
/**
* Método interno que realiza llamadas recursivas
*/
private static <AnyType extends Comparable<? super AnyType>>
void mergeSort( AnyType [ ] a, AnyType [ ] tmpArray,
int left, int right )
{
if( left < right )
{
int center = ( left + right ) / 2;
mergeSort( a, tmpArray, left, center );
mergeSort( a, tmpArray, center + 1, right );
merge( a, tmpArray, left, center + 1, right );
}
}
/**
* Método interno que mezcla dos arreglos ordenados
*/
private static <AnyType extends Comparable<? super AnyType>>
void merge( AnyType [ ] a, AnyType [ ] tmpArray, int leftPos, int rightPos, int rightEnd )
{
17
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
// Main loop
while( leftPos <= leftEnd && rightPos <= rightEnd )
if( a[ leftPos ].compareTo( a[ rightPos ] ) <= 0 )
tmpArray[ tmpPos++ ] = a[ leftPos++ ];
else
tmpArray[ tmpPos++ ] = a[ rightPos++ ];
// Copia en tmpArray
for( int i = 0; i < numElements; i++, rightEnd-- )
a[ rightEnd ] = tmpArray[ rightEnd ];
}
/**
* Algoritmo Quicksort
*/
public static <AnyType extends Comparable<? super AnyType>>
void quicksort( AnyType [ ] a )
{
quicksort( a, 0, a.length - 1 );
}
18
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
/**
* Método que intercambia los elementos en un arreglo
*/
public static <AnyType> void swapReferences( AnyType [ ] a, int index1, int index2 )
{
AnyType tmp = a[ index1 ];
a[ index1 ] = a[ index2 ];
a[ index2 ] = tmp;
}
/**
* Retorna mediana de la izquierda, centro y derecha.
* Ordena estos y oculta el pivote.
*/
private static <AnyType extends Comparable<? super AnyType>>
AnyType median3( AnyType [ ] a, int left, int right )
{
int center = ( left + right ) / 2;
if( a[ center ].compareTo( a[ left ] ) < 0 )
swapReferences( a, left, center );
if( a[ right ].compareTo( a[ left ] ) < 0 )
swapReferences( a, left, right );
if( a[ right ].compareTo( a[ center ] ) < 0 )
swapReferences( a, center, right );
// Pone el pivote en la posición derecha - 1
swapReferences( a, center, right - 1 );
return a[ right - 1 ];
}
19
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
/**
* Método quicksort mediante llamadas recursivas.
*/
private static <AnyType extends Comparable<? super AnyType>>
void quicksort( AnyType [ ] a, int left, int right )
{
if( left + CUTOFF <= right )
{
AnyType pivot = median3( a, left, right );
// Inicio de la partición
int i = left, j = right - 1;
for( ; ; )
{
while( a[ ++i ].compareTo( pivot ) < 0 ) { }
while( a[ --j ].compareTo( pivot ) > 0 ) { }
if( i < j )
swapReferences( a, i, j );
else
break;
}
swapReferences( a, i, right - 1 ); // Restaura pivote
quicksort( a, left, i - 1 ); // Ordena elementos pequeños
quicksort( a, i + 1, right ); // Ordena elementos grandes
}
else // Realizar una inserción ordenada en en sub arreglo
insertionSort( a, left, right );
}
/**
* Ordenamiento por inserción interna en sub arreglos
*/
20
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
/**
* Algoritmo de selección rápida
*/
public static <AnyType extends Comparable<? super AnyType>>
void quickSelect( AnyType [ ] a, int k )
{
quickSelect( a, 0, a.length - 1, k );
}
/**
* Método selección interna mediante llamadas recursivas.
*/
private static <AnyType extends Comparable<? super AnyType>>
void quickSelect( AnyType [ ] a, int left, int right, int k )
{
if( left + CUTOFF <= right )
{
AnyType pivot = median3( a, left, right );
// Inicio del particionamiento
21
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
22
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Random.permute( a );
Sort.heapsort( a );
checkSort( a );
Random.permute( a );
Sort.shellsort( a );
checkSort( a );
Random.permute( a );
Sort.mergeSort( a );
checkSort( a );
Random.permute( a );
Sort.quicksort( a );
checkSort( a );
Random.permute( a );
Sort.quickSelect( a, NUM_ITEMS / 2 );
System.out.println( a[ NUM_ITEMS / 2 - 1 ] + " " + NUM_ITEMS / 2 );
}
}
}
23
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Grafos y caminos
Un grafo es una red de elementos conectados entre sí. Actualmente se considera una
herramienta muy utilizada para modelar problemas reales en los cuales sus
componentes podrían representarse mediante un grafo. Por ejemplo, mediante un grafo
podrían representarse las carreteras de Costa Rica y las ciudades que conecta. En
tales circunstancias, las ciudades poseen varios caminos o carreteras por los cuales se
puede llegar a ella. Este tipo de problemas se resuelven mediante la implementación de
grafos.
En la teoría de grafos, debe considerarse la siguiente terminología:
• Grafo: Conjunto de nodos y arcos o de vértices y aristas
• Nodo: Elemento básico de información de un grafo
• Arco: Enlace que une dos nodos del grafo
• Nodos adyacentes: Dos nodos que son unidos por un arco
• Camino: Secuencia de nodos en los que cada par de nodos son adyacentes
• Camino simple: Camino en el que todos los nodos contenidos son diferentes,
con la posible excepción del primero y el último que podrían ser el mismo
• Grafo no dirigido: Los arcos en el grafo no tienen una dirección particular, es
decir, son bidireccionales. Por ejemplo, si los nodos A y B son adyacentes, es
igual ir de A a B que de B a A.
• Grafo dirigido: Es llamado dígrafo. Es donde los arcos del grafo tienen una
dirección asociada. El primer elemento del arco es el origen y el segundo es
considerado el destino. Por ejemplo: el arco A B es diferente del arco B A.
• Grafo ponderado: Cada arco del grafo tiene asociado un peso o valor.
Generalmente se asocia con costos y distancias, entre otros.
• Ciclo: Es un grafo dirigido. El ciclo es un camino donde el nodo de inicio y el
nodo final son el mismo.
• Grafo conectado: Un grafo no dirigido es conectado si hay un camino de
cualquier nodo hacia cualquier otro en el grafo.
• Dígrafo fuertemente conectado: Un grafo dirigido se considera fuertemente
conectado si hay un camino desde cualquier nodo hacia cualquier otro.
• Dígrafo débilmente conectado: Un grafo dirigido se considera débilmente
conectado si no hay caminos para llegar de cualquier nodo hacia cualquier otro.
24
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Guanacaste
Guanacaste
Puntarenas
Puntarenas
Alajuela
Alajuela
San
San José
José
José
Heredia
Heredia
Cartago
Cartago
Limó
Limón
Limón
Figura No. 2: Grafo representando los caminos entre las provincias de Costa Rica
Representación
Un grafo puede ser representado de muchas formas. Aquí se citan algunas de estas
formas:
Matriz de Adyacencia
Un grafo se puede representar fácilmente mediante una matriz. Inclusive, es la forma
más sencilla de representar un grafo. A esta matriz se le denomina matriz de
adyacencia. Esta matriz consiste básicamente en un arreglo bidimensional de tamaño n
x n, donde n es la máxima cantidad de nodos en el grafo. Cada casilla de la matriz se
carga con valores verdadero (v) o falso (f) en caso de que posea un camino de un nodo
(fila) con otro (columna). En caso de los grafos no dirigidos la matriz será simétrica. Sin
embargo, esto no ocurre en los dígrafos, donde se considera la dirección de cada uno
de los arcos. Para el caso de los grafos ponderados, la matriz podrá ser cargada con el
peso asociado a cada uno de los arcos.
La ventaja principal de la representación de grafos mediante una matriz de adyacencia
es su simplicidad, dado que facilita las operaciones que puedan realizarse sobre el
grafo.
25
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
A B C D E
A
A D
D A F F V V V
B F F V V F
C V V F F F
E C B
B D V V F F V
E V F F V V
Lista de adyacencias
Mediante una lista de adyacencias, la representación de un grafo gana en dinamismo.
Esto por cuanto no se tiene que pensar en un tamaño máximo de representación para
los nodos y sus arcos de un grafo, sino que más bien se van creando los nodos y sus
arcos a medida que se van necesitando. Básicamente, consiste en definir una lista
encadenada de nodos y, para cada uno de ellos, encadenar una lista con los nodos
adyacentes. Si se utiliza una lista de adyacencias para representar un grafo no dirigido
se desperdicia mucho espacio de memoria, dado que la información de cada arco se
encuentra duplicada, puesto que existe una vinculación de un nodo a otro y viceversa.
26
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
A
A D
D
E
E C B
B
27
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
V
V00 V
V11
00
Se escoge el vértice V2 como el nodo origen
V
V22 V
V33 V
V44 para la búsqueda de los caminos mínimos
V
V55 V
V66
11
V
V00 V
V11
00
Se busca la mínima distancia de V2 que es 1
V
V22 V
V33 V
V44 y se determina que son V0 y V5
11 El camino es V2ÆV0 y V2ÆV5
V
V55 V
V66
11 22
V
V00 V
V11
00 22
Se busca la siguiente distancia de V2 que es 2
V
V22 V
V33 V
V44 partiendo desde V0 y V5 se determina que son
V1 y V3.
11
El camino es V2ÆV0ÆV1 y V2ÆV0ÆV3
V
V55 V
V66
11 22
V
V00 V
V11
00 22 33 Se busca la siguiente distancia de V2 que es 3
partiendo desde V1 y V3 se determina que son
V
V22 V
V33 V
V44 V4 y V6. El camino es V2ÆV0ÆV1ÆV4 y
11 33 V2ÆV0ÆV3ÆV6
V
V55 V
V66
28
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
pretende encontrar el camino más corto, según su costo total, desde el vértice de origen
al resto de los vértices.
Básicamente, para construir el algoritmo del AEM desarrollado por Dijkstra, deben
seguirse los siguientes pasos:
• Crear el grafo vacío AEM (Árbol de Extensión Mínima).
• Insertar cualquier nodo vértice x del grafo en el AEM.
• Insertar todos los nodos vértices vecinos del nodo vértice x en una cola
priorizada. El valor del arco que une al nodo vértice x con su vecino es su
prioridad; la mayor prioridad es el valor menor
• Mientras la cola priorizada no esté vacia y no se hayan agregado todos los nodos
del AEM:
o Sacar un nodo vértice de la cola priorizada.
o Si el nodo vértice no está en el AEM, agregarlo con su correspondiente
arco y meter todos sus vecinos, que no estén en el AEM, en la cola
priorizada.
En la figura siguiente se muestra un ejemplo de cómo implementar el AEM de un grafo,
mediante una cola priorizada.
2 2
A
A B
B A
A B
B
12 8 8
AEM
AEM
12
6 C
C 6 C
C 3
3
D
D E
E D
D E
E
7
B C D C E F D D Cola
Cola priorizada
priorizada
2 12 10 8 9 3 6 7
29
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Para utilizar la cola de prioridad indicada en la figura anterior existen dos formas:
1. Almacenar cada vértice en la cola de prioridad y
2. Utilizar la distancia (obtenida consultando la tabla del grafo) como función de
ordenación.
“La cola de prioridad es una estructura apropiada. El método más sencillo es insertar en
la cola de prioridad una nueva entrada formada por un vértice y una distancia, cada vez
que se reduce la distancia de un vértice. Podemos encontrar el vértice adonde
movernos eliminando repetidamente el vértice de mínima distancia hasta que salga un
vértice no visitado” Mark Allen.
A continuación, se presenta la implementación en Java del algoritmo de Dijkstra,
mediante una cola de prioridad.
1. /**
2. *Objeto almacenado en la cola de prioridad
3. *en el algoritmo de Dijkstra
4. */
5. class Camino implements Comparable
6. {
7. int dest; //w
8. int coste; //d(w)
9.
10. static Camino infNeg = new Camino(); //centinela
11.
12. Camino()
13. { this( 0 ); }
14.
15. Camino( int d )
16. { this( d, 0 );}
17.
18. Camino( int d, int c )
19. { dest = d; coste = c;}
20.
21. public bolean menorQue( Comparable lder )
22. { return coste < ( (Camino) lder ).coste;}
30
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
23.
24. public int compara( Comparable lder)
25. { return coste < ( (Camino) lder ).coste ? -1 :
26. coste > ( (Camino) lder ).coste ? 1 : 0;}
27. }
31
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
32
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
3. El ciclo For más externo inicia a partir de la línea No. 17. Aquí se centra la
atención sobre el vértice v, procesándolo y examinando los vértices adyacentes,
indicados por w.
4. v se elige repetidamente mientras se eliminan elementos de la cola de prioridad
(línea 24) hasta encontrar un vértice aún no procesado.
5. El atributo extra se utiliza para ir almacenando la información del punto anterior.
Inicialmente vale 0. Cuando el vértice se procesa pasa a valer 1 (línea 28)
33
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
34
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Pilas y colas
Las pilas y colas se utilizan para administrar el orden de entrada de un conjunto de
datos. Una pila será útil cuando la aplicación requiera de un orden inverso al orden de
entrada original de los datos. Un ejemplo típico es el manejo de las llamadas a
subrutinas en un programa de cómputo o el proceso de conversión de expresiones a
diferentes formatos (situación que se requiere en la implantación de un compilador). Una
cola será útil cuando la aplicación requiera del orden estricto de entrada de los datos.
Los ejemplos característicos de esta estructura son los buffer de memoria en los que se
almacenan temporalmente los datos (como el de impresión o de entrada de datos por
teclado).
A continuación se describen ambas estructuras.
35
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Pilas
Una pila es una estructura de datos en la cual el acceso está limitado al elemento más
recientemente insertado. Una pila se implementa en un TDA vector o arreglo
unidimensional, marcándose su índice N como el primer elemento en el fondo del TDA.
El efecto de insertar elementos en la pila se conoce como apilar, mientras que el sacar
un elemento se conoce como desapilar. Lógicamente, en este TDA el elemento a
desapilar es el último elemento apilado. Es como tener una pila de libros: inicialmente
vamos apilando uno sobre el otro, quedando el primer libro en el fondo y el último como
el más próximo a ser desapilado. Esta acción de apilar/desapilar se denomina LIFO
(Last Input, Last Output), es decir, el último en entrar es el primero en salir. En
castellano sería UEPS.
Apilamiento
Desapilamiento
Ultimo elemento
insertado
Primer elemento
insertado
Arreglos
Los arreglos son estructuras de datos ampliamente utilizados, y muy fáciles de
entender y derivar en otras estructuras complejas. En realidad, un arreglo es una
36
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
37
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Ya que hemos repasado el concepto de los arreglos en Java, ahora vamos a continuar
con el tema de las pilas y colas.
Como se había indicado, una pila es un caso especial de una lista lineal, en el cual la
inserción y supresión son operaciones que solo pueden ocurrir en un extremo de la pila,
el cual se denomina como tope de la pila.
Un ejemplo de pila es el apilamiento de una bandeja de libros en una biblioteca, o de los
platos en un restaurante. Podemos agregar más platos, pero es el último plato apilado
el que podemos desapilar primero. Igual ocurre con los libros.
Las operaciones básicas de una pila son las siguientes:
9 Crear(pila)
9 EsVacia(pila)
9 Apilar(elemento, pila)
9 Desapilar(elemento, pila)
El siguiente código Java implementa el TDA Pila.
1. package EstructuraDatos;
2.
3. import Excepciones.*;
4.
5. // Interfaz Pila: tomado de Estructura de Datos en Java, de Mark Allen.
6. //
7. // **************** OPERACIONES PÚBLICAS ******************
8. // void apilar (Object x); Æ Inserta x
9. // void desapilar() Æ Elimina el último elemento insertado.
10. // Object cima(); Æ Devuelve el último elemento insertado.
11. // Object cimaYDesapilar(); Æ Devuelve y elimina el último elemento.
38
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
39
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Colas
Las colas se definen como una estructura de datos cuyos elementos se manejan bajo la
filosofía PEPS (Primero en Entrar Primero en Salir) o FIFO (First Input, First Output).
Una cola es una estructura lineal y finita, donde los elementos pueden ser de cualquier
tipo que se requiera. Su dominio lo forman aquellos elementos que puedan llegar a
almacenarse en la estructura, y se obtienen por dos partes de estructura: una llamada
frente que señala donde se encuentra el siguiente elemento por atender en la cola, y
otra llamada final que significa el lugar donde se encuentra el último elemento.
Las operaciones básicas de una cola son:
9 Insertar: insertar al final de la cola.
9 QuitarPrimero: quitar el elemento que se encuentra al frente de la cola.
9 Primero: acceso al primer elemento de la cola.
Entrada Salida
Fondo Frente
40
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Obsérvese que los elementos entran al TDA Cola por el fondo y salen por el frente. En
este caso, el ingreso sería A, B, C y D y la salida sería A, B, C y D.
A continuación, se implementa en Java el TDA Cola:
1. package EstructuraDatos;
2.
3. import Excepciones.*;
4.
5. // Interfaz Cola: tomado de Estructura de Datos en Java, de Mark Allen.
6. //
7. // **************** OPERACIONES PÚBLICAS ******************
8. // void Insertar (x); Æ Inserta x
9. // Object primero() Æ Devuelve el primer elemento.
10. // Object quitarPrimero; Æ Devuelve el último elemento insertado.
11. // boolean esVacia(); Æ Devuelve Trae si la cola está vacia.
12. // void vaciar(); Æ Elimina todos los elementos
13. // **************** ERRORES ********************************
14. // primero y quitarPrimero sobre una cola vacia
15.
16. public interface Cola
17. {
18. void insertar (Object x);
19. Object primero() throws DesbordamientoInferior;
20. Object quitarPrimero() throws DesbordamientoInferior;
21. boolean esVacia();
22. void vaciar();
23. }
41
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Antes de iniciar el tema siguiente, que trata sobre las listas, es importante detenerse a
estudiar un poco el concepto de referencias. Esto por cuanto los TDA anteriores, Pilas y
Colas, trabajan generalmente sobre vectores (arreglos unidimensionales). Los arreglos
constituyen TDA estáticos como sabemos y las listas, árboles y grafos se representan
generalmente pormedio de eslabones conectados mediante variables denominadas
referencias. Debe indicarse que los grafos, aunque se representen mediante referencias
que le aportan dinamismo pueden ser representados también a través de arreglos
bidimensionales.
42
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Una referencia en Java es una variable que guarda la dirección de memoria en la que se
almacena un objeto. Una referencia siempre contiene la dirección de memoria en la que
un objeto está guardado, a menos que no referencie a ningún objeto. En este caso,
almacena la referencia nula (Null). Java no permite referencias a variables primitivas.
Listas enlazadas
Las listas enlazadas suelen denominarse también listas encadenadas. Este tipo de
TDA puede definirse como una estructura de datos que tiene una organización lineal, y
se caracteriza porque cada uno de sus elementos tiene que indicar dónde se encuentra
el siguiente elemento de la lista. Una lista enlazada se gestiona a través de memoria
dinámica (utilizando nodos de datos y punteros), pero también mediante memoria
estática (en vectores bidimensionales). Sin embargo, esta segunda opción representa
un derroche importante de memoria.
En la figura siguiente se representa una lista enlazada, mediante punteros.
En la representación del TDA lista enlazada anterior podemos observar que existen
cuatro nodos que contienen dos campos esenciales: el primero, donde se guarda el dato
(A, B, C y D) y, el segundo, sus correspondientes campos de apuntador. Así, A tiene el
campo donde guarda el valor A y otro campo donde almacena la dirección al siguiente
nodo (B).
Posición siguiente
Posición Elemento
elemento
0 A 1
1 B 2
2 C 3
3 D Nulo
43
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Las pilas y colas se pueden implementar en listas enlazadas. A este tipo de listas se les
denomina simple porque solamente se pueden ingresar datos por el fondo (en caso de
las colas) y por el tope (en el caso de las pilas). La eliminación se realiza por el frente
(en caso de las colas) y por el tope (en el caso de las pilas). Sin embargo, esos TDA se
manejan adecuadamente en arreglos unidimensionales y es funcionalmente adecuado.
Sin embargo, cuando los datos deben insertarse en cualquier parte, o eliminarse de
cualquier posición, el concepto de lista enlazada cambia su funcionalidad. En este caso,
las listas amplían el concepto de nodos enlazados a listas enlazadas, doblemente
enlazadas o listas circulares.
Las pilas y colas también pueden ser implementadas mediante listas enlazadas
mediante referencias. La ventaja de alojar estas estructuras en listas enlazadas es que
el exceso de gasto de memoria en que se incurre se reduce a una referencia por
elemento, mientras que si se almacenara en arreglos se exigiría un espacio mayor,
incluyendo los espacios vacíos. En Java, esta desventaja no es tan relevante, dado que
los espacios vacíos del vector representan referencias nulas, las cuales ocupan muy
poco espacio.
Una pila puede implementarse en Java donde la cima (tope) de la misma está
representada por el primer elemento.
Las siguientes condiciones deben cumplirse para gestionar la pila mediante listas
enlazadas:
44
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Debe recordarse que cada nodo tiene un único campo de enlace, una variable de
referencia contiene una dirección al primer nodo; cada nodo (excepto el último) enlaza
con el nodo siguiente, y el enlace del último nodo es nulo (null) para indicar que es el
final de la lista.
Cuando se trata el tema de punteros, en realidad se está hablando de variables de
referencia. Una variable de referencia en Java guarda la dirección de memoria en la
que se almacena un objeto.
Árboles
Un árbol es un conjunto de nodos y aristas. Las aristas son las referencias que
conectan pares de nodos. Un árbol organiza los datos en una estructura en forma
jerárquica o de niveles. Su característica principal es que mantiene una relación de uno
a muchos (1:n) entre sus elementos. Por ejemplo, mediante árboles podemos
representar un árbol genealógico, un organigrama, los directorios de un sistema
operativo, entre otros.
Nodo
Nodo
Arista
Arista
45
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Existen conceptos que deben considerarse en la estructura árbol. Las mismas son:
1. Profundidad de un nodo: Es la longitud del camino que va desde la raíz hasta el
nodo.
2. Altura de un nodo: Es la longitud del camino que va desde el nodo hasta la hoja
más profunda bajo él.
3. Tamaño de un nodo: Es igual al número de descendientes que tiene
(incluyéndose).
Árboles generales:
Un árbol general está constituido por nodos y aristas que se correlacionan. Un árbol
general, como los demás tipos de árboles, inicia con un nodo raíz, y de ahí se despliega
hacia los demás nodos. En la figura No. 4 puede observarse un árbol general,
constituido por nodos y aristas que unen estos nodos.
Árboles binarios:
Un árbol binario es aquel en el cual cada nodo no puede tener más de dos hijos. En
este caso, un nodo padre tiene dos nodos hijos: el hijo izquierdo y el hijo derecho. Estos
hijos pueden, a su vez, ser vacíos o tener otro par de nodos o solo un hijo (izquierdo o
derecho). En la figura siguiente se muestra un árbol binario.
46
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Los árboles binarios son muy utilizados en el diseño de compiladores, dado que
mediante estos se pueden construir expresiones, las cuales se almacenan en sus
nodos; la ruta de ejecución se representa mediante las aristas que los une. A este uso
se le denomina árbol de expresiones. Otro uso es para implementar un algoritmo
simple pero relativamente eficiente de compresión de datos. Se le denomina árbol de
codificación de Huffman.
47
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
El nodo raiz es el 5.
El hijo derecho de 5 es 8. El hijo derecho de 6 es 7.
El hijo izquierdo de 5 es 3. El hijo izquierdo de 8 es 6.
55
El nodo padre de 2 y 4 es 3. El nodo padre de 7 es 6.
Los nodos hojas son 1,4,7 y 10.
33 88
Los hermanos son (2 y 4), (6 y 9).
Los ancestros de 7 son 6,8 y 5.
22 44 66 99
Los descendientes de 8 son 6, 7, 9 y 10.
El subárbol derecho de 5 es el que tiene la raiz 8.
11 77 10
10 El subárbol izquierdo de 5 es el que tiene raiz 3.
El nodo del nivel cero es 5.
Los nodos del nivel 1 son 3 y 8.
Los nodos del nivel 2 son 2, 4, 6 y 9.
Los nodos del nivel 3 son 1, 7 y 10.
Árboles y recursividad:
Dado que la definición de un árbol se realiza mediante recursión, así también las demás
rutinas que los gestionan también. El hecho de que un método se llame repetidamente
a sí mismo se conoce como recursión.
La recursión trabaja dividiendo un problema en subproblemas. Un programa llama a un
método con uno o más parámetros que describen un problema. Si el método detecta
que los valores no representan la forma más simple del problema, se llama a sí mismo
con valores de parámetros modificados que describen un subproblema cercano a esa
forma.
Para entender la recursión, consideremos un método que suma todos los enteros desde
1 hasta algún límite superior.
48
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
El programa anterior es correcto dado que logra determinar el total de todos los números
desde 1 hasta límite. Sin embargo, mediante la recursión es posible realizar esta misma
suma de la siguiente forma:
49
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
También se puede calcular la altura de un nodo (longitud del camino que va desde el
nodo hasta la hoja más profunda bajo él) utilizando recursividad. El siguiente fragmento
de programa representa este caso:
1. /**
2. Devuelve altura del árbol binario con raíz en a.
3. */
4. static int altura (NodoBinario a)
5. {
6. if (a == null)
7. return -1;
8. else
9. return 1 + Math.max(altura(a.izquierdo), altura(a.derecho));
10. }
Recorrido de árboles
Cuando se utiliza la recursión o recursividad para calcular el tamaño o la altura de un
árbol, estamos recorriendo todos los nodos que lo componen. En este caso, se está
recorriendo el árbol. Existen varios algoritmos que se utilizan para realizar los recorridos
en un árbol. A continuación se presentan varios algoritmos conocidos:
Recorrido en postorden
En el recorrido postorden, el nodo se procesa después de haber procesado
recursivamente sus hijos. Dos ejemplos son los fragmentos de programa de tamaño y
altura, que se utilizaron para determinar el tamaño y la altura de un árbol binario.
El recorrido postorden mantiene una pila que almacena los nodos ya visitados. La cima
de la pila indica el nodo que actualmente está siendo visitado. En este caso, se pueden
realizar cualesquiera de las siguientes operaciones: hacer una llamada recursiva al hijo
izquierdo, hacer una llamada recursiva al hijo derecho o procesar el nodo actual. Por
consecuencia, cada nodo se colocará en la pila tres veces, y se marca como el nodo
actual que ha de ser visitado una vez que se desapila por tercera vez.
Este recorrido es útil para implementar el destructor de un árbol binario (eliminación de
todos los nodos).
50
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
++
aa *
-- d
d
b
b cc
Recorrido en preorden
En el recorrido preorden, primero se procesa el nodo y después se procesan sus hijos.
Es útil para reconstruir un ABB (Árbol Binario de Búsqueda). Las secuencias lógicas
para este recorrido son:
1. Visitar el nodo raíz del árbol.
2. Recorrer en preorden el subárbol izquierdo del nodo raíz.
3. Recorrer en preorden el subárbol derecho del nodo raíz.
51
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
1. void imprimirPreorden()
2. {
3. System.out.println( dato ); //nodo
4. if ( izquierdo ¡= null )
5. izquierdo.imprimirPreorden( ) // izquierdo
6. if ( derecho ¡= null )
7. derecho.imprimirPreorden( ) // derecho
8. }
9.
10. void imprimirPostorden()
11. {
12. if ( izquierdo ¡= null )
13. izquierdo.imprimirPostorden( ) // izquierdo
14. if ( derecho ¡= null )
15. derecho.imprimirPostorden( ) // derecho
16. System.out.println( dato ); //nodo
17. }
18. void imprimirOrdenSim()
19. {
20. if ( izquierdo ¡= null )
21. izquierdo.imprimirOrdenSim( ) // izquierdo
22. System.out.println( dato ); //nodo
23. if ( derecho ¡= null )
24. derecho.imprimirOrdenSim( ) // derecho
25. }
52
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
cada elemento del ABB, los elementos menores estarán a su izquierda, y los mayores a
su derecha.
A continuación, se muestra una figura de un árbol binario de búsqueda (ABB):
88
55 44
33
33 99
11 88
33
66 99 11 22
55 77
La idea básica del algoritmo de búsqueda consiste en comparar la información del nodo
con la del valor buscado. Si no son iguales, el apuntador de búsqueda se mueve a la
izquierda o a la derecha del valor buscado, según sea menor o mayor, comenzando por
la raíz y hasta que se encuentre o no el valor.
El algoritmo se puede describir de la siguiente manera:
1. Coloque un apuntador auxiliar en la raíz del árbol.
2. Mientras no se haya encontrado el valor que se busca, y el apuntador auxiliar no
este vacío (fuera del árbol):
53
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
13
13
Buscar
Buscar el
el 13
13
12
12
77 21
21
44 99 16
16 25
25
22 88 13
13 19
19
54
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
55
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
38. /**
39. Remueve desde el árbol. No se hace nada si x no es encontrado
40. @param x es el item a remover.
41. */
42. public void remove( AnyType x )
43. {
44. root = remove( x, root );
45. }
46. /**
47. Encuentra el elemento más pequeño en el árbol.
48. @return el elemento más pequeño o nulo si no lo encuentra.
49. */
50. public AnyType findMin( )
51. {
52. if( isEmpty( ) )
53. throw new UnderflowException( );
54. return findMin( root ).element;
55. }
56. /**
57. Encuentra el elemento más grande en el árbol.
58. @return el elemento más grande o nulo si no lo encuentra.
59. */
60. public AnyType findMax( )
61. {
62. if( isEmpty( ) )
63. throw new UnderflowException( );
64. return findMax( root ).element;
65. }
66. /**
67. Encuentra un elemento en el árbol.
68. @param x es el elemento a buscar
56
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
57
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
100. /**
101. Método interno para insertar en un sub árbol.
102. @param x es el elemento a insertar
103. @param t es el node raíz en el sub árbol.
104. @return la nueva raíz del sub árbol
105. */
106. private BinaryNode<AnyType> insert( AnyType x, BinaryNode<AnyType> t )
107. {
108. if( t == null )
109. return new BinaryNode<AnyType>( x, null, null );
110. int compareResult = x.compareTo( t.element );
111. if( compareResult < 0 )
112. t.left = insert( x, t.left );
113. else if( compareResult > 0 )
114. t.right = insert( x, t.right );
115. else; // Duplicado; Nada que hacer
116. return t;
117. }
118. /**
119. Método interno para eliminar de un sub árbol
120. @param x es el elemento a eliminar
121. @param t es el nodo raíz del sub árbol
122. @return la nueva raíz del sub árbol
123. */
124. private BinaryNode<AnyType> remove( AnyType x, BinaryNode<AnyType> t )
125. {
126. if( t == null )
127. return t; // Elemento no encontrado; Nada que hacer
128. int compareResult = x.compareTo( t.element );
129. if( compareResult < 0 )
130. t.left = remove( x, t.left );
58
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
59
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
60
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
61
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
62
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Operaciones
Las operaciones que se pueden realizar sobre un ABB son las de inserción y
eliminación. Todo nuevo nodo se insertará como nodo hoja en el ABB, en el lugar que le
corresponda según el proceso de búsqueda.
En el caso de la inserción, se realizará una búsqueda binaria con la idea de colocar el
valor en una posición adecuada. Observe el ejemplo presentado en la figura siguiente:
Buscar
Buscar el
15
15
el 15
12
12 12
12
15
12
12
77 21
21 77 21
21
77 21
21
44 99 25
25 44 99 25
25
44 99 25
25
22 88 22
16
16 88 16
16
22 88 16
16
13
13 19
19 13
13 19
19
13
13 19
19
63
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
12
12 12
12
77 21
21 77 21
21
44 99 16
16 44 99 16
16
22 88 13
13 19
19 22 13
13 19
19
Figura No. 18: Eliminación en un ABB cuando el nodo por borrar es una hoja
64
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
2. El nodo por borrar tiene sólo un hijo. En este caso, el padre del que se va a
borrar puede apuntar directamente al nodo hijo del que se eliminará. Obsérvese
la siguiente figura que demuestra este caso:
Eliminar
Eliminar el
Paso 1) Buscar el elemento 21
el 21
21
12
12 12
12
77 21
21 77 16
16
44 99 16
16 44 99 13 19
13 19
22 88 13
13 19
19 22 88
Figura No. 19: Eliminación en un ABB cuando el nodo por borrar tiene un hijo
3. El nodo por borrar tiene dos hijos. Puesto que el padre del que se va a borrar no
puede heredar dos apuntadores, se busca un valor sustituto del valor por borrar y
el nodo no se borra físicamente. Se puede escoger como sustituto al predecesor
del que se eliminará (el valor mayor de todos los valores menores); o bien, de los
nodos del subárbol izquierdo el de más a la derecha), y se elimina físicamente el
nodo donde se encuentre. Se puede asegurar que la baja física del nodo
sustituto cae en alguno de los dos primeros casos. De igual manera, se puede
considerar al sucesor como valor sustituto.
65
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
EEl
12 Paso 2) Buscar el sustituto
liimm
Paso 1) Buscar el elemento 12 12
iinn
aar
r ee
ll 11
21
22
77 21
12
12
44 99 16
16
77 21
21
22 88 13
13 19
19
44 99 16
16
Predecesor Sucesor
99
22 88 13
13 19
19
77 21
21
22 13
13 19
19
Figura No. 20: Eliminación en un ABB cuando el nodo a borrar tiene dos hijos
El algoritmo para llevar a cabo las operaciones anteriores está compuesto de dos
partes. La primera se encarga de localizar el nodo por borrar y la segunda borra el nodo
encontrado.
66
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
AVL
Un árbol AVL es un árbol de búsqueda que trata de mantenerse lo más balanceado
posible, conforme se realizan las operaciones de inserción y eliminación. En los árboles
AVL se debe cumplir el hecho que para cualquier nodo del árbol, la diferencia en las
alturas de sus subárboles no exceda una unidad.
A continuación, la figura muestra los árboles que son AVL y aquellos que no lo son,
considerando la diferencia en las alturas de sus subárboles.
67
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Los nodos de un árbol AVL guardan un valor entre 1 y -1, lo que se conoce como Factor
de Balanceo (FB). Representa la diferencia entre las alturas de sus árboles. Un FB
igual a cero en un nodo significa que las alturas de sus subárboles son iguales. Un FB
positivo significa que el subárbol derecho es más grande que el izquierdo. Un FB
negativo, representa que el subárbol izquierdo es más grande que el derecho.
Para mantener un árbol balanceado se debe aplicar uno de los cuatro esquemas de
balanceos denominados simple o doble. El balanceo simple (izquierda o RSI) y derecha
(RSD) implica el movimiento de tres apuntadores. Véase la siguiente figura que
demuestra este tipo de rotación:
Resto
Resto del
del Árbol
Árbol Resto
Resto del
del Árbol
Árbol
Rotació
Rotación Simple
+ Nodo Pivote 0
B
B A
A
0 A
A 0 Ajustar FB en ruta
B
B
de búsqueda
1 3
0
2 3 1 2 Nuevo Nodo
Nuevo Nodo
68
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
En la figura anterior se tiene una rotación simple izquierda de un árbol AVL. Los
triángulos representan subárboles de cualquier altura (la misma para todos). La rotación
hace un balanceo a partir del nodo pivote y el resto del árbol no se afecta. Observe que
el valor A es mayor que B y hay congruencia después de la rotación. La imagen de la
RSD se obtiene viendo este esquema a través de un espejo.
Resto
Resto del
del Árbol
Árbol Resto
Resto del
del Árbol
Árbol
Rotació
Rotación Doble
+ B
B Nodo Pivote
0
C
C
0
0 A
A
B
B 0+ A
A
0
C
1 C
2 3
2 3 4 1 0 0 4
Nuevo Nodo
Nuevo Nodo
En la figura anterior, se tiene una rotación doble izquierda de un árbol AVL. Los
triángulos 1 y 4 representan subárboles de cualquier altura; los triángulos 2 y 3 son
subárboles con una altura menor en un nivel, con respecto a 1 y 4. La rotación hace un
balanceo a partir del nodo pivote. El resto del árbol no se ve afectado. Observe que el
valor C es mayor que B y menor que A, por lo que hay congruencia después de la
rotación. El esquema de RDD se obtiene viendo este esquema a través de un espejo.
El algoritmo general para la inserción de un nodo en un árbol AVL es el siguiente:
1. Insertar el nodo como en un ABB (rutina de inserción).
2. Buscar el nodo pivote. Colocar los apuntadores P1, P2, P3 y P4, donde:
• P1 = Apuntador al nodo padre del nodo pivote
• P2 = Apuntador al nodo pivote
69
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
• P3 = Apuntador al nodo hijo del nodo pivote, que es la raíz del subárbol más
grande.
• P4 = Apuntador al nodo hijo del nodo apuntado por P3, que sigue en la ruta de
búsqueda del nuevo nodo.
3. Si no existe nodo pivote (P2 apunta a vacío), entonces modificar los FB desde la
raíz hasta el nuevo nodo (rutina que modifica los FB).
Si el nuevo nodo se insertó en el subárbol más pequeño del nodo pivote,
entonces modificar los FB desde el nodo pivote hasta el nuevo (rutina que
modifica los FB).
Si no es así, verificar el tipo de rotación:
Si es rotación simple, entonces se deben modificar los apuntadores y FB
(rutina que realiza la rotación simple).
Si no, entonces deben modificarse los apuntadores y FB (rutina que realiza
la rotación doble).
2. Si la información del nuevo nodo es menor que la información apuntada por P2:
Hijo Izquierdo de P2 = Hijo Derecho de P3
Hijo Derecho de P3 = P2
Modificar el FB desde el hijo izquierdo de P3 hasta el padre del nuevo
nodo
Si no
Hijo Derecho de P2 = Hijo Izquierdo de P3
Hijo Izquierdo de P3 = P2
70
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
71
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
72
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
24. */
25. public AvlTree( )
26. {
27. root = null;
28. }
29. /**
30. Inserta en el árbol; los duplicados son ignorados
31. @param x es el elemento a insertar
32. */
33. public void insert( AnyType x )
34. {
35. root = insert( x, root );
36. }
37. /**
38. Elimina en el árbol. No se hace nada si x no es encontrado
39. @param x es el elemento a borrar
40. */
41. public void remove( AnyType x )
42. {
43. System.out.println( "Lo siento, remove no implementado! " );
44. }
45. /**
46. Buscando el elemento más pequeño en el árbol.
47. @return el elemento más pequeño o nulo si está vacío.
48. */
49. public AnyType findMin( )
50. {
51. if( isEmpty( ) )
52. throw new UnderflowException( );
53. return findMin( root ).element;
54. }
73
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
55. /**
56. Buscando el elemento más grande en el árbol.
57. @retorna el elemento más grande o nulo si está vacío.
58. */
59. public AnyType findMax( )
60. {
61. if( isEmpty( ) )
62. throw new UnderflowException( );
63. return findMax( root ).element;
64. }
65. /**
66. Busca un elemento en el árbol
67. @param x es el elemento a buscar
68. @return true si x es encontrado
69. */
70. public boolean contains( AnyType x )
71. {
72. return contains( x, root );
73. }
74. /**
75. Logicamente vacia el árbol
76. */
77. public void makeEmpty( )
78. {
79. root = null;
80. }
81. /**
82. Comprueba si el árbol está vacío.
83. @return true si está vacío, false en otro caso.
84. */
85. public boolean isEmpty( )
74
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
86. {
87. return root == null;
88. }
89. /**
90. Imprime el contenido del árbol en forma ordenada
91. */
92. public void printTree( )
93. {
94. if( isEmpty( ) )
95. System.out.println( "Arbol Vacío" );
96. else
97. printTree( root );
98. }
99. /**
100. Método interno para insertar un elemento en el árbol
101. @param x es el elemento a insertar
102. @param t es el nodo raíz del árbol
103. @return la nueva raíz del árbol
104. */
105. private AvlNode<AnyType> insert( AnyType x, AvlNode<AnyType> t )
106. {
107. if( t == null )
108. return new AvlNode<AnyType>( x, null, null );
109. int compareResult = x.compareTo( t.element );
110. if( compareResult < 0 )
111. {
112. t.left = insert( x, t.left );
113. if( height( t.left ) - height( t.right ) == 2 )
114. if( x.compareTo( t.left.element ) < 0 )
115. t = rotateWithLeftChild( t );
116. else
75
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
117. t = doubleWithLeftChild( t );
118. }
119. else if( compareResult > 0 )
120. {
121. t.right = insert( x, t.right );
122. if( height( t.right ) - height( t.left ) == 2 )
123. if( x.compareTo( t.right.element ) > 0 )
124. t = rotateWithRightChild( t );
125. else
126. t = doubleWithRightChild( t );
127. }
128. else
129. ; // Duplicado; nada que hacer.
130. t.height = Math.max( height( t.left ), height( t.right ) ) + 1;
131. return t;
132. }
133. /**
134. Método interno para encontrar el elemento más pequeño en el árbol.
135. @param t es el nodo raíz en el árbol
136. @return el nodo con el elemento más pequeño del árbol
137. */
138. private AvlNode<AnyType> findMin( AvlNode<AnyType> t )
139. {
140. if( t == null )
141. return t;
142. while( t.left != null )
143. t = t.left;
144. return t;
145. }
146. /**
147. Método interno para encontrar el elemento más grande del árbol
76
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
77
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
179. /**
180. Método interno para imprimir el árbol en forma ordenada
181. @param t es el nodo raíz del árbol
182. */
183. private void printTree( AvlNode<AnyType> t )
184. {
185. if( t != null )
186. {
187. printTree( t.left );
188. System.out.println( t.element );
189. printTree( t.right );
190. }
191. }
192. /**
193. Retorna el tamaño del nodo t, o -1 si es nulo
194. */
195. private int height( AvlNode<AnyType> t )
196. {
197. return t == null ? -1 : t.height;
198. }
199. /**
200.
201. Rota el nodo del ábol binario con el hijo izquierdo
202. Para las árboles AVL, esto es una rotación simple para el caso 1.
203. Actualiza y retorna la nueva raíz
204. */
205. private AvlNode<AnyType> rotateWithLeftChild( AvlNode<AnyType> k2 )
206. {
207. AvlNode<AnyType> k1 = k2.left;
208. k2.left = k1.right;
209. k1.right = k2;
78
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
79
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
241. node de un árbol binario con rotación doble: primero el hijo derecho
242. cuando este es el hijo izquierdo entonces el nodo k1 es el nuevo hijo derecho
243. Para las árboles AVL, esto es una rotación simple para el caso 3
244. Actualiza y retorna la nueva raíz
245. */
246. private AvlNode<AnyType> doubleWithRightChild( AvlNode<AnyType> k1 )
247. {
248. k1.right = rotateWithLeftChild( k1.right );
249. return rotateWithRightChild( k1 );
250. }
251. private static class AvlNode<AnyType>
252. {
253. // Constructores
254. AvlNode( AnyType theElement )
255. {
256. this( theElement, null, null );
257. }
258. AvlNode( AnyType theElement, AvlNode<AnyType> lt, AvlNode<AnyType> rt )
259. {
260. element = theElement;
261. left = lt;
262. right = rt;
263. height = 0;
264. }
265. AnyType element; // El dato en el nodo
266. AvlNode<AnyType> left; // hijo izquierdo
267. AvlNode<AnyType> right; // hijo derecho
268. int height; // tamaño
269. }
270. /** La raíz del árbol. */
271. private AvlNode<AnyType> root;
80
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Árboles Rojinegros
“Los árboles rojinegros son una buena alternativa a los árboles AVL. Los detalles de
la implementación producen un código más eficiente, ya que las rutinas de inserción y
eliminación emplean un solo recorrido descendente. No se permite que haya nodos
consecutivos de color rojo, y todos los caminos deben tener el mismo número de nodos
negros.” Mark Allen [pp. 492]
81
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
30
30
70
70
15
15
60
60 85
85
10
10 20
20
50
50 65
65 80
80 90
90
55
40
40 55
55
Debe considerarse que los elementos que se inserten en el árbol deben ser de color
rojo. Si el padre también es rojo debemos colorear de nuevo y/o realizar rotaciones para
eliminar los nodos rojos consecutivos. Asimismo, si el hermano del padre es negro, la
situación se arregla con una rotación simple o doble, al igual que en los árboles AVL.
A continuación, se muestra la implementación de árboles rojinegros en Java:
1. // Clase RedBlackTree (árbol rojinegro)
2. //
3. // CONSTRUCCION: sin parámetros
4. //
5. // *****************OPERACIONES PUBLICAS*******************
6. // void insert( x ) --> Inserta x
7. // void remove( x ) --> Remueve x (sin implementar)
8. // boolean contains( x ) --> Retorna true si x es encontrado
9. // Comparable findMin( ) --> Retorna el elemento más pequeño
10. // Comparable findMax( ) --> Retorna el elemento más grande
82
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
11. // boolean isEmpty( ) --> Retorna true si el árbol está vacío, sin false
12. // void makeEmpty( ) --> Remueve todos los elementos del árbol
13. // void printTree( ) --> Imprime todos los elementos
14. // ******************ERRORES*******************************
15. /**
16. Implementa un árbol rojinegro
17. Note que todas las búsquedas están basadas en el método compareTo
18. @author Mark Allen Weiss
19. */
20. public class RedBlackTree<AnyType extends Comparable<? super AnyType>>
21. {
22. /**
23. Construyendo el árbol
24. */
25. public RedBlackTree( )
26. {
27. nullNode = new RedBlackNode<AnyType>( null );
28. nullNode.left = nullNode.right = nullNode;
29. header = new RedBlackNode<AnyType>( null );
30. header.left = header.right = nullNode;
31. }
32. /**
33. Compare los elementos y t.element1, usando el método compareTo
34. Esta rutina debe ser llamada, desde una cabecera
35. Si no es posible para t ser la cabecera, use el método compareTo directamente
36. */
37. private final int compare( AnyType item, RedBlackNode<AnyType> t )
38. {
39. if( t == header )
a. return 1;
40. else
83
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
84
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
59. }
60. /**
61. Remoción desde el árbol
62. @param x the item to remove.
63. */
64. public void remove( AnyType x )
65. {
66. throw new UnsupportedOperationException( );
67. }
68. /**
69. Encontrar el elemento más pequeño del árbol
70. @return el elemento más pequeño o null si el árbol está vacío
71. */
72. public AnyType findMin( )
73. {
74. if( isEmpty( ) )
a. throw new UnderflowException( );
75. RedBlackNode<AnyType> itr = header.right;
76. while( itr.left != nullNode )
a. itr = itr.left;
77. return itr.element;
78. }
79. /**
80. Encontrar el elemento más grande en el árbol
81. @return el elemento más grande o null si el árbol está vacío
82. */
83. public AnyType findMax( )
84. {
85. if( isEmpty( ) )
a. throw new UnderflowException( );
86. RedBlackNode<AnyType> itr = header.right;
85
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
86
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
109. }
110. /**
111. Imprime los elementos del árbol en forma ordenada
112. */
113. public void printTree( )
114. {
115. printTree( header.right );
116. }
117. /**
118. Método interno para imprimir un sub árbol en orden
119. @param t es el nodo raíz del árbol.
120. */
121. private void printTree( RedBlackNode<AnyType> t )
122. {
123. if( t != nullNode )
124. {
a. printTree( t.left );
b. System.out.println( t.element );
c. printTree( t.right );
125. }
126. }
127. /**
128. Examina si el árbol está lógicamente vacío
129. @return true si está vacío sino false
130. */
131. public boolean isEmpty( )
132. {
133. return header.right == nullNode;
134. }
135. /**
136. Rutina interna que es llamada durante una inserción
87
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
88
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
89
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
184. {
a. // Constructores
185. RedBlackNode( AnyType theElement )
186. {
a. this( theElement, null, null );
187. }
90
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
207. {
208. RedBlackTree<Integer> t = new RedBlackTree<Integer>( );
209. final int NUMS = 400000;
210. final int GAP = 35461;
211. System.out.println( "Comprobando (no más salidas!)" );
212. for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS )
a. t.insert( i );
213. if( t.findMin( ) != 1 || t.findMax( ) != NUMS - 1 )
a. System.out.println( "Error en FindMin o FindMax!" );
214. for( int i = 1; i < NUMS; i++ )
a. if( !t.contains( i ) )
b. System.out.println( "Error1 Encontrado !" );
215. }
216. }
AA-Árboles
En los árboles rojinegros es bastante complicada la operación eliminar dada la gran
cantidad de rotaciones necesarias. Los árboles AA son el método elegido cuando se
necesitan árboles equilibrados. En ellos se permite una implementación más inmediata
y se requieren eliminaciones.
A continuación, se presenta el algoritmo para implementar un árbol AA en Java:
1. // AATree class
2. //
3. // CONSTRUCCION: sin inicializador
4. //
5. // ******************OPERACIONES PUBLICAS*********************
6. // void insert( x ) --> Inserta x
7. // void remove( x ) --> Remueve x
8. // boolean contains( x ) --> Retorna true si x es encontrado
9. // Comparable findMin( ) --> Retorna el elemento más pequeño
10. // Comparable findMax( ) --> Retorna el elemento más grande
11. // boolean isEmpty( ) --> Retorna true si el árbol está vacío, sino false
91
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
92
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
42. */
43. public void remove( AnyType x )
44. {
45. deletedNode = nullNode;
46. root = remove( x, root );
47. }
48. /**
49. Encontrar el elemento más pequeño en el árbol
50. returna el elementno más pequeño o throw UnderflowException si está vacío
51. */
52. public AnyType findMin( )
53. {
54. if( isEmpty( ) )
55. throw new UnderflowException( );
56. AANode<AnyType> ptr = root;
57. while( ptr.left != nullNode )
58. ptr = ptr.left;
59. return ptr.element;
60. }
61. /**
62. Encontrar el elemento más grande en el árbol
63. returna el elemento más grande o throw UnderflowException si está vacío
64. */
65. public AnyType findMax( )
66. {
67. if( isEmpty( ) )
68. throw new UnderflowException( );
69. AANode<AnyType> ptr = root;
70. while( ptr.right != nullNode )
71. ptr = ptr.right;
72. return ptr.element;
93
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
73. }
74. /**
75. Encontrar un elemento en el árbol
76. x es el elemento a buscar
77. retorna true si x es encontrado
78. */
79. public boolean contains( AnyType x )
80. {
81. AANode<AnyType> current = root;
82. nullNode.element = x;
83. for( ; ; )
84. {
a. int compareResult = x.compareTo( current.element );
85. if( compareResult < 0 )
a. current = current.left;
86. else if( compareResult > 0 )
a. current = current.right;
87. else if( current != nullNode )
a. return true;
88. else
a. return false;
89. }
90. }
91. /**
92. Pone el árbol lógicamente vacío
93. */
94. public void makeEmpty( )
95. {
96. root = nullNode;
97. }
98. /**
94
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
95
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
96
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
97
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
176. return t;
177. }
178. /**
179. Rotar el nodo del árbol binario con el hijo izquierdo
180. */
181. private AANode<AnyType> rotateWithLeftChild( AANode<AnyType> k2 )
182. {
183. AANode<AnyType> k1 = k2.left;
184. k2.left = k1.right;
185. k1.right = k2;
186. return k1;
187. }
188. /**
189. Rotar el nodo del árbol binario con el hijo derecho.
190. */
191. private AANode<AnyType> rotateWithRightChild( AANode<AnyType> k1 )
192. {
193. AANode<AnyType> k2 = k1.right;
194. k1.right = k2.left;
195. k2.left = k1;
196. return k2;
197. }
198. private static class AANode<AnyType>
199. {
200. // Constructor
201. AANode( AnyType theElement, AANode<AnyType> lt, AANode<AnyType> rt )
202. {
203. element = theElement;
204. left = lt;
a. right = rt;
205. level = 1;
98
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
206. }
207. AnyType element; // El dato en el nodo
208. AANode<AnyType> left; // hijo izquierdo
209. AANode<AnyType> right; // hijo derecho
210. int level; //nivel
211. }
212. private AANode<AnyType> root;
213. private AANode<AnyType> nullNode;
214. private AANode<AnyType> deletedNode;
215. private AANode<AnyType> lastNode;
216. //Programa de prueba:
217. public static void main( String [ ] args )
218. {
219. AATree<Integer> t = new AATree<Integer>( );
220. final int NUMS = 40000;
221. final int GAP = 307;
222. System.out.println( "Comprobando…)" );
223. t.insert( NUMS * 2 );
224. t.insert( NUMS * 3 );
225. for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS )
226. t.insert( i );
227. System.out.println( "Inserción completada" );
228. t.remove( t.findMax( ) );
229. for( int i = 1; i < NUMS; i+= 2 )
230. t.remove( i );
231. t.remove( t.findMax( ) );
232. System.out.println( "Remoción completada" );
233. if( t.findMin( ) != 2 || t.findMax( ) != NUMS - 2 )
234. System.out.println( "Error en FindMin o FindMax!" );
235. for( int i = 2; i < NUMS; i+=2 )
236. if( !t.contains( i ) )
99
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
B-Árboles
Un árbol B es un tipo especial de árbol con determinadas propiedades que lo hacen útil
para guardar y acceder eficientemente grandes cantidades de información en memoria
secundaria. De igual forma que en un árbol ABB, la búsqueda de un elemento requiere
del recorrido de un camino, desde la raíz del árbol hacia alguna de las hojas. Estos
árboles están completamente balanceados, por lo que se garantiza eficiencia en los
algoritmos de búsqueda.
Una definición general del árbol B es la siguiente:
1. Todas las hojas en el árbol están bajo el mismo nivel.
2. Cada nodo contiene entre n y 2n elementos (excepto la raíz que tiene entre 1 y
2n).
3. Si un nodo tiene m elementos, el nodo contendrá 0 ó m + 1 hijos.
4. Los elementos de un nodo del árbol están ordenados linealmente en el nodo.
5. Los elementos del árbol B están organizados siguiendo las propiedades de un
ABB; es decir, los elementos menores a la izquierda y las mayores a la derecha
del nodo original.
La siguiente figura muestra un árbol b de orden 2. La cantidad máxima de elementos
que puede tener un nodo es 4, el número mínimo es 2 (excepto la raíz) y la cantidad de
hijos que tendría un nodo depende de la cantidad de elementos del nodo, pero podrá
variar entre 0, 2, 3, 4 ó 5 hijos.
32,
32, 38,
38, 43
43
10,
10, 20,
20, 25
25 32,
32, 34
34 40,
40, 42
42 44,
44, 50,
50, 56
56
Árbol B de orden 2
Cantidad máxima de elementos = 4, mínimo = 2
100
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Tablas Hash
Un conjunto es una colección de objetos. Computacionalmente, un conjunto se define
como una agrupación finita de objetos, con características comunes, que no presentan
relación alguna entre sí. Una tabla hashing sirve para mapear todos los posibles
valores de llaves de un conjunto.
Para determinar la llave de un determinado valor en un conjunto podría utilizarse:
f (llave) = posición_tabla(direccion base)
Las funciones utilizadas para hacer la conversión reciben el nombre de funciones
hashing.
Cuando se realizan las conversiones de llaves, lógicamente se pueden presentar
colisiones. Estas colisiones se puden resolver mediante las metodologٌías de
direccionamiento abierto o encadenamiento. Entre las funciones de direccionamiento
abierto se pueden realizar pruebas como Prueba Lineal, Prueba Cuadrática, Prueba
Aleatoria, Prueba de doble hashing.
A continuación se muestra la implementación hashing en Java:
// Clase Hashing de Prueba Cuadrática
//
// CONSTRUCCIÓN: un tamaño o un defecto inicial aproximado de 101
//
// ******************OPERACIONES PÚBLICAS*********************
// bool insert( x ) --> Inserta x
// bool remove( x ) --> Remueve x
// bool contains( x ) --> Retorna true si x es encontrada
// void makeEmpty( ) --> Remueve todos los elementos
/**
* Implementación de pruebas de hashing
* Observe que todas las búsqueds están basados en un método similar
* @author Mark Allen Weiss
*/
public class QuadraticProbingHashTable<AnyType>
{
/**
* Construyendo la tabla hash
*/
101
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
public QuadraticProbingHashTable( )
{
this( DEFAULT_TABLE_SIZE );
}
/**
* Construyendo la tabla hash
*/
public QuadraticProbingHashTable( int size )
{
allocateArray( size );
makeEmpty( );
}
/**
* Incluyendo en la tabla hash. Si el elemento existe
* no hace nada
* x es el elemento a insertar
*/
public void insert( AnyType x )
{
// Insertar x como activo
int currentPos = findPos( x );
if( isActive( currentPos ) )
return;
array[ currentPos ] = new HashEntry<AnyType>( x, true );
if( ++currentSize > array.length / 2 )
rehash( );
}
/**
102
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
103
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
return currentPos;
}
/**
* Remoción de la tabla hash
* x es el elemento a remover
*/
public void remove( AnyType x )
{
int currentPos = findPos( x );
if( isActive( currentPos ) )
array[ currentPos ].isActive = false;
}
/**
* Buscar el elemento en la tabla hash
* x es el elemento a buscar
* retorna el elemento buscado
*/
public boolean contains( AnyType x )
{
int currentPos = findPos( x );
return isActive( currentPos );
}
/**
* Retorna true sif currentPos existe y si está activa
* currentPos es el resultado de la llamada a findPos.
* retorna true si currentPos esta activa.
*/
private boolean isActive( int currentPos )
{
104
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
105
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
{
element = e;
isActive = i;
}
}
/**
* Método interno para asignar el arreglo
* arraySize es el tamaño del arreglo
*/
private void allocateArray( int arraySize )
{
array = new HashEntry[ arraySize ];
}
/**
* Método interno para encontrar un número primo tan grande como n
* n es el número que inicia (debe ser positivo).
* retorna un número primo tran grande como n.
*/
private static int nextPrime( int n )
{
if( n % 2 == 0 )
n++;
for( ; !isPrime( n ); n += 2 )
;
return n;
106
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
/**
* método interno para probar si un número es primo
* No es un algoritmo eficiente
* n es el número para probar
* retorna el resultado del test
*/
private static boolean isPrime( int n )
{
if( n == 2 || n == 3 )
return true;
if( n == 1 || n % 2 == 0 )
return false;
for( int i = 3; i * i <= n; i += 2 )
if( n % i == 0 )
return false;
return true;
}
// Menu simple
public static void main( String [ ] args )
{
QuadraticProbingHashTable<String> H = new
QuadraticProbingHashTable<String>( );
final int NUMS = 400000;
final int GAP = 37;
System.out.println( "Probando... (no más salidas…)" );
for( int i = GAP; i != 0; i = ( i + GAP ) % NUMS )
H.insert( ""+i );
107
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
108
Universidad Estatal a Distancia (UNED) – Estructura de Datos
Material Complementario
Bibliografía
Referencia WEB:
109