UNIVERSIDAD TECNOLÓGICA DE PANAMÁ

FACULTAD DE INGENIERÍA DE SISTEMAS COMPUTACIONALES


DESARROLLO DE SOFTWARE


ESTRUCTURA DE DATOS II


Eficiencia de algoritmos de búsqueda y ordenamiento

Profesora: Doris Cueto

Integrantes
Franklin Maestre 8-887-1788
José Gutiérrez 8-872-2166
Israel Quintero 8-890-844

Grupo: 1LS121


Fecha: 16-06-2014

Índice
Introducción ........................................................................................................................................ 3
1. Consideraciones de eficiencia de los algoritmos de ordenamiento y búsquedas. Notación de la
Gran O (Big O). .................................................................................................................................... 4
2. Comparación de la eficiencia de los algoritmos de ordenamientos: Selección, Inserción y
Burbuja. ............................................................................................................................................... 5
3. Algoritmos de ordenamiento y su eficiencia Quicksort .................................................................. 6
4. Algoritmos de ordenamiento y su eficiencia Heapsort ................................................................... 6
5. Comparación de la eficiencia de los algoritmos de búsqueda Secuencial y Binaria ....................... 7
6. Algoritmo de búsqueda y su eficiencia de cadena Knuth-Morris-Pratt .......................................... 9
7. Algoritmo de Boyer-Moore, búsqueda de patrones ..................................................................... 10
8. Técnicas de cálculo de direcciones y comparaciones Hashing ..................................................... 13
9. MÉTODOS PARA RESOLVER EL PROBLEMA DE LAS COLISIONES ................................................... 16
Conclusión ......................................................................................................................................... 19











Introducción
Una de las tareas que realizan más frecuentemente las computadoras en el
procesamiento de datos es la ordenación y búsqueda.
El estudio de diferentes métodos de ordenación es una tarea intrínsecamente
interesante desde un punto de vista teórico y, naturalmente, práctico.
La ordenación es una operación consistente en disponer un conjunto de datos en
algún determinado orden con respecto a uno de los campos de elementos del
conjunto. La Búsqueda es una operación que consiste en recuperar un dato
deseado.
Para estas operaciones existen numeroso algoritmos cada uno creado para una
tarea específica en este trabajo analizaremos los algoritmos de ordenamiento de
Selección, Burbuja, Inserción, Quicksort y Heapsort y algoritmos de búsqueda
Secuencial, Binaria, cadena Knuth-Morris-Pratt y cadena Boyer-Moore
1. Consideraciones de eficiencia de los algoritmos de
ordenamiento y búsquedas. Notación de la Gran O (Big O).
A) Algoritmos de ordenamiento: es una operación consistente en disponer un
conjunto estructura de datos en algún determinado orden con respecto a uno de
los campos de elementos del conjunto.

Una colección de datos (estructura) puede ser almacenada en un archivo, un array
(vector o tabla), un array de registros, una lista enlazada o un árbol. Cuando los
datos están almacenados en un array, una lista enlazada o un árbol, se denomina
ordenación interna.

La eficiencia es el factor que mide la calidad y rendimiento de un algoritmo. En el
caso de la operación de ordenación, dos criterios se suelen seguir a la hora de
decidir qué algoritmo de entre los que resuelven la ordenación es el más eficiente:

1) tiempo menor de ejecución en computadora.
2) menor número de instrucciones.

Sin embargo, no siempre es fácil efectuar estas medidas: puede no disponerse de
instrucciones para medida de tiempo —aunque no sea éste el caso del lenguaje C,
y las instrucciones pueden variar, dependiendo del lenguaje y del propio estilo del
programador. Por esta razón, el mejor criterio para medir la eficiencia de un
algoritmo es aislar una operación específica clave en la ordenación y contar el
número de veces que se realiza. Así, en el caso de los algoritmos de ordenación,
se utilizará como medida de su eficiencia el número de comparaciones entre
elementos efectuados. El algoritmo de ordenación A será más eficiente que el B, si
requiere menor número de comparaciones.

Los métodos de ordenación se suelen dividir en dos grandes grupos:
• Directos: burbuja, selección, inserción.
• Indirectos: (avanzados) Shell, ordenación rápida, ordenación por mezcla,
Radixsort.

B) Algoritmo de búsqueda: El proceso de encontrar un elemento específico de un
array se denomina búsqueda. En esta sección se examinarán dos técnicas de
búsqueda: búsqueda lineal o secuencial, la técnica más sencilla, y búsqueda
binaria o dicotómica, la técnica más eficiente.

Al igual que sucede con las operaciones de ordenación cuando se realizan
operaciones de búsqueda es preciso considerar la eficiencia (complejidad) de los
algoritmos empleados en la búsqueda. El grado de eficiencia en una búsqueda
será vital cuando se trata de localizar una información en una lista o tabla en
memoria, o bien en un archivo de datos.

2. Comparación de la eficiencia de los algoritmos de
ordenamientos: Selección, Inserción y Burbuja.

A) Ordenación por selección: El algoritmo se apoya en sucesivas pasadas que
intercambian el elemento más pequeño sucesivamente con el primer elemento de
la lista, A[0] en la primera pasada. En síntesis, se busca el elemento más pequeño
de la lista y se intercambia con A[0], primer elemento de la lista.

Los pasos del algoritmo son:
1. Seleccionar el elemento más pequeño de la lista A; intercambiarlo con el primer
elemento A[0]. Ahora la entrada más pequeña está en la primera posición del
vector.

2. Considerar las posiciones de la lista A[1], A[2], A[3]..., seleccionar el elemento
más pequeño e intercambiarlo con A[1]. Ahora las dos primeras entradas de A
están en orden.

3. Continuar este proceso encontrado o seleccionando el elemento más pequeño
de los restantes elementos de la lista, intercambiándolos adecuadamente.

El análisis del algoritmo de selección es sencillo y claro, ya que requiere un
número fijo de comparaciones que sólo dependen del tamaño de la lista o vector
(array) y no de la distribución inicial de los datos.

B) Ordenación por Inserción: el método de ordenación por inserción es similar al
proceso típico de ordenar tarjetas de nombres (cartas de una baraja) por orden
alfabético, que consiste en insertar un nombre en su posición correcta dentro de
una lista o archivo que ya está ordenado.

El algoritmo correspondiente a la ordenación por inserción contempla los
siguientes pasos:

1. El primer elemento A[0] se considera ordenado; es decir, la lista inicial consta
de un elemento.

2. Se inserta A[1] en la posición correcta, delante o detrás de A[0], dependiendo
de que sea menor o mayor.

3. Por cada bucle o iteración i(desde i=1 hasta n-1) se explora la sub-lista A[i-
1]..A[0] buscando la posición correcta de inserción; a la vez se mueve hacia
abajo(a la derecha en la sub-lista)una posición todos los elementos mayores que
el elemento que el elemento a insertar A[i], para dejar bacía esa posición.

4. Insertar el elemento a la posición correcta.

El análisis del algoritmo de inserción se determinó que la complejidad del
algoritmo es complejidad cuadrática.

C) Ordenación por burbuja: es un sencillo algoritmo de ordenamiento. Funciona
revisando cada elemento de la lista que va a ser ordenada con el siguiente,
intercambiándolos de posición si están en el orden equivocado.


¿Cuál es la eficiencia del algoritmo de ordenación de la burbuja? Dependerá de la
versión utilizada. En la versión más simple se hacen n − 1 pasadas y n − 1
comparaciones en cada pasada. Por consiguiente, el número de comparaciones
es (n− 1) * (n − 1) = n2− 2n + 1, es decir, la complejidad o(n2).
3. Algoritmos de ordenamiento y su eficiencia Quicksort

El algoritmo quicksort ordena un vector V eligiendo entre sus elementos un valor clave P que
actúa como pivote, organiza tres secciones, izquierda-P-derecha, todos los elementos a la
izquierda deberán ser menores a P, y los de la derecha mayores, los ordena sin tener que hacer
ningún tipo de mezcla para combinarlos, ¿cómo elegimos el pivote?.
1. Método 1: Lo ideal sería que el pivote fuera la mediana del vector para que las partes izquierda
y derecha tuvieran el mismo tamaño.
2. Método 2: recorremos el vector con un índice i desde 0 a n-1, y otro índice j inversamente y
cuando se crucen, es decir, tenga el mismo valor, ese se seleccionara como pivote.
Como se puede suponer, la eficiencia del algoritmo depende de la posición en la que
termine el pivote elegido.
4. Algoritmos de ordenamiento y su eficiencia Heapsort
El ordenamiento por montículos (heapsort en inglés) es
un algoritmo de ordenamiento no recursivo, no estable, con complejidad
computacional
Este algoritmo consiste en almacenar todos los elementos del vector a ordenar en
un montículo (heap), y luego extraer el nodo que queda como nodo raíz del
montículo (cima) en sucesivas iteraciones obteniendo el conjunto ordenado. Basa
su funcionamiento en una propiedad de los montículos, por la cual, la cima
contiene siempre el menor elemento (o el mayor, según se haya definido el
montículo) de todos los almacenados en él. El algoritmo, después de cada
extracción, recoloca en el nodo raíz o cima, la última hoja por la derecha del último
nivel. Lo cual destruye la propiedad heap del árbol. Pero, a continuación realiza un
proceso de "descenso" del número insertado de forma que se elige a cada
movimiento el mayor de sus dos hijos, con el que se intercambia. Este
intercambio, realizado sucesivamente "hunde" el nodo en el árbol restaurando la
propiedad montículo del arbol y dejándo paso a la siguiente extracción del nodo
raíz.
Algoritmo Lógico.
1. Se construye el montículo inicial a partir del arreglo original.
2. Se intercambia la raíz con el último elemento del montículo.
3. El último elemento queda ordenado.
4. El último elemento se saca del montículo, no del arreglo.
5. Se restaura el montículo haciendo que el primer elemento baje a laposición que
le corresponde, si sus hijos son menores.
6. La raíz vuelve a ser el mayor del montículo.
7. Se repite el paso 2 hasta que quede un solo elemento en el montículo.


Con esto concluimos que la eficacia del método de ordenamiento Heapsort
depende de la data que se maneja, entre más diferente y desordenada mejor.

5. Comparación de la eficiencia de los algoritmos de búsqueda
Secuencial y Binaria
Los procesos de búsqueda involucran recorrer un arreglo completo con el fin de
encontrar algo. Lo más común es buscar el menor o mayor elemento (cuando se
puede establecer un orden), o buscar el índice de un elemento determinado.
• Búsqueda Secuencial: Consiste en ir comparando el elemento que se busca
con cada elemento del arreglo hasta cuándo se encuentra.



Ventajas Desventajas
La principal ventaja es que este método
funciona más efectivamente con datos
desordenados

No es estable ya que se comporta de
manera ineficaz con datos del mismo
valor

Su desempeño es en promedio tan
bueno como el Quicksort y se comporta
mejor que este en los peores casos

Método más complejo

No necesita memoria adicional
Ejemplos de algoritmos:
Búsqueda del menor
menor = a[0];
for (i=1;i<n;i++)
if ( a[i]<menor )
menor=a[i];
Búsqueda del mayor
mayor= a[n-1];
for (i=0;i<n-1;i++)
if ( a[i]>mayor )
mayor=a[i];

 Búsqueda Binaria: En el caso anterior de búsqueda se asume que los
elementos están en cualquier orden. En el peor de los casos deben
hacerse n operaciones de comparación. Una búsqueda más eficiente
puede hacerse sobre un arreglo ordenado. Una de éstas es la Búsqueda
Binaria. La Búsqueda Binaria, compara si el valor buscado está en la mitad
superior o inferior. En la que esté, subdivido nuevamente, y así
sucesivamente hasta encontrar el valor.

Ejemplo de algoritmo:
b= 17;
i= 0;
j= tamaño-1;
do {
k= (i+j)/2;
if (b<=v[k] )
i=k+1;
if (b>=v[k] )
j= k-1; } while (i<=j);
Búsqueda de elemento
encontrado=-1;
for (i=0;i<n;i++)
if ( a[i]==elemento_buscado
)
encontrado=i;

Comparación: La búsqueda binaria es superiormente eficiente que la búsqueda secuencial,
aunque en arreglos pequeños ambos métodos son relativamente equivalentes, esto se debe a que
recorre el arreglo haciendo comparaciones con el valor que se espera encontrar acortando su
tiempo de ejecución, también hay que tomar en consideración que para poder realizar la búsqueda
de forma binaria se debe ordenar el arreglo.
6. Algoritmo de búsqueda y su eficiencia de cadena Knuth-
Morris-Pratt
El algoritmo KMP, trata de localizar la posición de comienzo de una cadena,
dentro de otra. Antes que nada con la cadena a localizar se precalcula una tabla
de saltos (conocida como tabla de fallos) que después al examinar entre si las
cadenas se utiliza para hacer saltos cuando se localiza un fallo.
Supongamos una tabla 'F' ya precalculada, y supongamos que la cadena a buscar
esté contenida en el array 'P()', y la cadena donde buscamos esté contenida en un
array 'T()'. Entonces ambas cadenas comienzan a compararse usando un puntero
de avance para la cadena a buscar, si ocurre un fallo en vez de volver a la
posición siguiente a la primera coincidencia, se salta hacia donde sobre la tabla,
indica el puntero actual de avance de la tabla. El array 'T' utiliza un puntero de
avance absoluto que considera donde se compara el primer carácter de ambas
cadenas, y utiliza como un puntero relativo (sumado al absoluto) el que utiliza para
su recorrido el array 'P'. Se dan 2 situaciones:
Mientras existan coincidencias el puntero de avance de 'P', se va
incrementando y si alcanza el final se devuelve la posición actual del
puntero del array 'T'
Si se da un fallo, el puntero de avance de 'T' se actualiza hasta, con la
suma actual del puntero de 'P' + el valor de la tabla 'F' apuntado por el
mismo que 'P'. A continuación se actualiza el puntero de 'P', bajo una de 2
cicunstancias; Si el valor de 'F' es mayor que -1 el puntero de 'P', toma el
valor que indica la tabla de salto 'F', en caso contrario vuelve a recomenzar
su valor en 0.

EFICIENCIA:
Los casos óptimos se denotan porque son todos ceros, o lo que es lo mismo, no se repiten
caracteres desde el principio.
El peor caso se da cuando la cadena se compone de 1 único carácter.

7. Algoritmo de Boyer-Moore, búsqueda de patrones

El algoritmo de Boyer-Moore, considerado el algoritmo más eficiente en la búsqueda de patrones
en cadena de caracteres, se basa en desplazar la ventana de comparación lo máximo posible.
El algoritmo se desplaza dentro de la cadena de búsqueda de izquierda a derecha, y dentro del
patrón de derecha a izquierda. La mayor eficiencia se consigue minimizando el número de
comparaciones entre caracteres, desplazando lo máximo posible la venta de comparación, a costa
de una computación previa.
Notación

y: cadena dónde se busca.
x: patrón de búsqueda.
| y | = n, longitud de y.
| x | = m, longitud de x.
j: posición en y desde dónde se prueba la coincidencia.
i: posición en x de comparación, dónde se produce una no coincidencia , y[j+i] <>
x[i], y[j+i] = b, x[i] = a.
u: coincidencia en la comparación, sufijo de x, u = y[j+i+..j+m] = x[i+1..m-1].
v: prefijo de x.
s: salto del patrón para la siguiente comparación.
Al producirse una ocurrencia del patrón, o un error en la comparación de un carácter, se calcula el
desplazamiento máximo del patrón a lo largo de la cadena de búsqueda.
Partimos de una situación en que no hay coincidencia, existe diferencia entre y[j+i] y x[i], pero las
posiciones de x siguientes a i sí coinciden con sus asociadas en y, u = y[j+i+..j+m] = x[i+1..m-1];
hacer notar que u es sufijo de x.
El desplazamiento de x a lo largo de y se limita a causa del carácter en y que produjo la no
coincidencia, y[i+j] (1), y los caracteres de x posteriores a i (2), sufijo de x que tenía coincidencia
parcial con y.

(1) Teniendo en cuenta el carácter que produjo la no coincidencia en y, y[i+j] = b, el
desplazamiento máximo, s, será la distancia entre la aparición más a la derecha de b en x[0..m-2] y
la longitud de x, m. La nueva j sería j’=j+s, lo que se consigue es alinear las dos coincidencias de b
en x e y, desde dónde es posible que se produzca una coincidencia del patrón. Se considera el
intervalo 0..m-2, porque si se da el caso de que b es igual al último carácter de x, el
desplazamiento sería 0, y podría provocar un bucle infinito debido a que el patrón no varía su
posición.
(1)

(2) Teniendo en cuenta los caracteres posteriores a i en x (u, sufijo de x), que coinciden de forma
parcial con y, hay que alinear u lo más a la derecha posible de x, sin que esté precedido por x[i] = a
(2.a); al no estar u ya precedido por x[i] = a <> x[i-s] = c, en la nueva posición de x respecto de y,
sabemos que existe la coincidencia u precedida por c, es posible que se produzca una ocurrencia
en y. Si no se encuentra la situación anterior, se tratará de alinear el mayor sufijo posible de x con
un prefijo v también de x (2.b); como u coincide parcialmente en y, al buscar el prefijo v de x que
también es sufijo de x, v también está en y. Si no se producen ninguno de los dos casos anteriores,
el patrón se podrá desplazar toda su longitud.
(2.a)

(2.b)

El desplazamiento de x a lo largo de y será el máximo desplazamiento entre los dos anteriores, (1)
y (2).


Código
- StringMatchingBM.java: Implementación en Java del algoritmo de Boyer-Moore.
- StringMatchingBF.java: Implementación en Java del algoritmo de fuerza bruta.
- StringMatchingTest.java: Clase en Java empleada para realizar las pruebas de rendimiento.
Resultado de las pruebas
100 tests --> BM: 70 millis (18462 comparisons)
100 tests --> BF: 50 millis (73898 comparisons)

1000 tests --> BM: 310 millis (187974 comparisons)
1000 tests --> BF: 341 millis (777391 comparisons)

10000 tests --> BM: 2424 millis (1877086 comparisons)
10000 tests --> BF: 2872 millis (8021317 comparisons)

100000 tests --> BM: 22760 millis (18809679 comparisons)
100000 tests --> BF: 34268 millis (79647647 comparisons)

8. Técnicas de cálculo de direcciones y comparaciones Hashing
Definición:
Hasta ahora las técnicas de localización de registros vistas, emplean un proceso de búsqueda que
implica cierto tiempo y esfuerzo. El siguiente método nos permite encontrar directamente el registro
buscado.
La idea básica de este método consiste en aplicar una función que traduce un conjunto de posibles
valores llave en un rango de direcciones relativas. Un problema potencial encontrado en este
proceso, es que tal función no puede ser uno a uno; las direcciones calculadas pueden no ser
todas únicas, cuando R(k
1
)= R(k
2
)
Pero: K
1
diferente de K
2
decimos que hay una colisión. A dos llaves diferentes que les
corresponda la misma dirección relativa se les llama sinónimos.
A las técnicas de cálculo de direcciones también se les conoce como:
 Técnicas de almacenamiento disperso
 Técnicas aleatorias
 Métodos de transformación de llave - a- dirección
 Técnicas de direccionamiento directo
 Métodos de tabla Hash
 Métodos de Hashing

Pero el término más usado es el de hashing. Al cálculo que se realiza para obtener una dirección a
partir de una llave se le conoce como función hash.



Ventaja
1. Se pueden usar los valores naturales de la llave, puesto que se traducen internamente a
direcciones fáciles de localizar
2. Se logra independencia lógica y física, debido a que los valores de las llaves son
independientes del espacio de direcciones
3. No se requiere almacenamiento adicional para los índices.
Desventajas
1. No pueden usarse registros de longitud variable
2. El archivo no está clasificado
3. No permite llaves repetidas
4. Solo permite acceso por una sola llave
Costos
 Tiempo de procesamiento requerido para la aplicación de la función hash
 Tiempo de procesamiento y los accesos E/S requeridos para solucionar las colisiones.





La eficiencia de una función hash depende de:
1. La distribución de los valores de llave que realmente se usan
2. El número de valores de llave que realmente están en uso con respecto al tamaño del espacio
de direcciones
3. El número de registros que pueden almacenarse en una dirección dad sin causar una colisión
4. La técnica usada para resolver el problema de las colisiones

Las funciones hash más comunes son:
 Residuo de la división
 Medio del cuadrado
 Pliegue














HASHING POR RESIDUO DE LA DIVISIÓN
La idea de este método es la de dividir el valor de la llave entre un numero apropiado, y después
utilizar el residuo de la división como dirección relativa para el registro (dirección = llave módulo
divisor).
Mientras que el valor calculado real de una dirección relativa, dados tanto un valor de llave como el
divisor, es directo; la elección del divisor apropiado puede no ser tan simple. Existen varios factores
que deben considerarse para seleccionar el divisor:
1. El rango de valores que resultan de la operación “llave % divisor”, va desde cero hasta el
divisor 1. Luego, el divisor determina el tamaño del espacio de direcciones relativas. Si se sabe
que el archivo va a contener por lo menos n registros, entonces tendremos que hacer que
divisor > n, suponiendo que solamente un registro puede ser almacenado en una dirección
relativa dada.
2. El divisor deberá seleccionarse de tal forma que la probabilidad de colisión sea minimizada.
¿Cómo escoger este número? Mediante investigaciones se ha demostrado que los divisores
que son números pares tienden a comportase pobremente, especialmente con los conjuntos
de valores de llave que son predominantemente impares. Algunas investigaciones sugieren
que el divisor deberá ser un número primo. Sin embargo, otras sugieren que los divisores no
primos trabajan también como los divisores primos, siempre y cuando los divisores no primos
no contengan ningún factor primo menor de 20. Lo más común es elegir el número primo más
próximo al total de direcciones.



Independientemente de que tan bueno sea el divisor, cuando el espacio de direcciones de un
archivo está completamente lleno, la probabilidad de colisión crece dramáticamente. La saturación
de archivo de mide mediante su factor de carga, el cual se define como la relación del número de
registros en el archivo contra el número de registros que el archivo podría contener si estuviese
completamente lleno.

Todas las funciones hash comienzan a trabajar probablemente cuando el archivo esta casi lleno.
Por lo general el máximo factor de carga que puede tolerarse en un archivo para un rendimiento
razonable es de entre el 70 % y 80 %.
HASHING POR MEDIO DEL CUADRADO
En esta técnica, la llave es elevada al cuadrado, después algunos dígitos específicos se extraen de
la mitad del resultado para constituir la dirección relativa. Si se desea una dirección de n dígitos,
entonces los dígitos se truncan en ambos extremos de la llave elevada al cuadrado, tomando n
dígitos intermedios. Las mismas posiciones de n dígitos deben extraerse para cada llave.
Utilizando esta función hashing el tamaño del archivo resultante es de 10
n
donde n es el número de
dígitos extraídos de los valores de la llave elevada al cuadrado.




HASHING POR PLIEGUE
En esta técnica el valor de la llave es particionada en varias partes, cada una de las cuales
(Excepto la última) tiene el mismo número de dígitos que tiene la dirección relativa objetivo. Estas
particiones son después plegadas una sobre otra y sumadas. El resultado, es la dirección relativa.
Igual que para el método del medio del cuadrado, el tamaño del espacio de direcciones relativas es
una potencia de 10.

COMPARACIÓN ENTRE LAS FUNCIONES HASH
Aunque alguna otra técnica pueda desempeñarse mejor en situaciones particulares, la técnica del
residuo de la división proporciona el mejor desempeño. Ninguna función hash se desempeña
siempre mejor que las otras. El método del medio del cuadrado puede aplicarse en archivos con
factores de cargas bastantes bajas para dar generalmente un buen desempeño. El método de
pliegues puede ser la técnica más fácil de calcular pero produce resultados bastante erráticos, a
menos que la longitud de la llave se aproximadamente igual a la longitud de la dirección.
Si la distribución de los valores de llaves no es conocida, entonces el método del residuo de la
división es preferible. Note que el hashing puede ser aplicado a llaves no numéricas. Las
posiciones de ordenamiento de secuencia de los caracteres en un valor de llave pueden ser
utilizadas como sus equivalentes “numéricos”. Alternativamente, el algoritmo hash actúa sobre las
representaciones binarias de los caracteres.
Todas las funciones hash presentadas tienen destinado un espacio de tamaño fijo. Aumentar el
tamaño del archivo relativo creado al usar una de estas funciones, implica cambiar la función hash,
para que se refiera a un espacio mayor y volver a cargar el nuevo archivo.
9. MÉTODOS PARA RESOLVER EL PROBLEMA DE LAS
COLISIONES
Considere las llaves K
1
y K
2
que son sinónimas para la función hash R. Si K
1
es almacenada
primero en el archivo y su dirección es R(K
1
), entonces se dice que K
1
esta almacenado en su
dirección de origen.



Existen dos métodos básicos para determinar dónde debe ser alojado K
2
:
 Direccionamiento abierto.- Se encuentra entre dirección de origen para K
2
dentro del archivo.
 Separación de desborde (Área de desborde).- Se encuentra una dirección para K
2
fuera del
área principal del archivo, en un área especial de desborde, que es utilizada exclusivamente
para almacenar registro que no pueden ser asignados en su dirección de origen


Los métodos más conocidos para resolver colisiones son:

Sondeo lineal
Que es una técnica de direccionamiento abierto. Este es un proceso de búsqueda secuencial
desde la dirección de origen para encontrar la siguiente localidad vacía. Esta técnica es también
conocida como método de desbordamiento consecutivo.
Para almacenar un registro por hashing con sondeo lineal, la dirección no debe caer fuera del
límite del archivo, En lugar de terminar cuando el límite del espacio de dirección se alcanza, se
regresa al inicio del espacio y sondeamos desde ahí. Por lo que debe ser posible detectar si la
dirección base ha sido encontrada de nuevo, lo cual indica que el archivo está lleno y no hay
espacio para la llave.
Para la búsqueda de un registro por hashing con sondeo lineal, los valores de llave de los registros
encontrados en la dirección de origen, y en las direcciones alcanzadas con el sondeo lineal, deberá
compararse con el valor de la llave buscada, para determinar si el registro objetivo ha sido
localizado o no.

El sondeo lineal puede usarse para cualquier técnica de hashing. Si se emplea sondeo lineal para
almacenar registros, también deberá emplearse para recuperarlos.

Doble hashing
En esta técnica se aplica una segunda función hash para combinar la llave original con el resultado
del primer hash. El resultado del segundo hash puede situarse dentro del mismo archivo o en un
archivo de sobreflujo independiente; de cualquier modo, será necesario algún método de solución
si ocurren colisiones durante el segundo hash.
La ventaja del método de separación de desborde es que reduce la situación de una doble colisión,
la cual puede ocurrir con el método de direccionamiento abierto, en el cual un registro que no está
almacenado en su dirección de origen desplazara a otro registro, el que después buscará su
dirección de origen. Esto puede evitarse con direccionamiento abierto, simplemente moviendo el
registro extraño a otra localidad y almacenando al nuevo registro en la dirección de origen ahora
vacía.
Puede ser aplicado como cualquier direccionamiento abierto o técnica de separación de desborde.
Para ambas métodos para la solución de colisiones existen técnicas para mejorar su desempeño
como:
1.- Encadenamiento de sinónimos
Una buena manera de mejorar la eficiencia de un archivo que utiliza el cálculo de direcciones, sin
directorio auxiliar para guiar la recuperación de registros, es el encadenamiento de sinónimos.
Mantener una lista ligada de registros, con la misma dirección de origen, no reduce el número de
colisiones, pero reduce los tiempos de acceso para recuperar los registros que no se encuentran
en su localidad de origen. El encadenamiento de sinónimos puede emplearse con cualquier técnica
de solución de colisiones.
Cuando un registro debe ser recuperado del archivo, solo los sinónimos de la llave objetivo son
accesados.
2.- Direccionamiento por cubetas
Otro enfoque para resolver el problema de las colisiones es asignar bloques de espacio (cubetas),
que pueden acomodar ocurrencias múltiples de registros, en lugar de asignar celdas individuales a
registros. Cuando una cubeta es desbordada, alguna nueva localización deberá ser encontrada
para el registro. Los métodos para el problema de sobrecupo son básicamente el mismo que los
métodos para resolver colisiones.
COMPARACIÓN ENTRE SONDEO LINEAL Y DOBLE HASHING
De ambos métodos resultan distribuciones diferentes de sinónimos en un archivo relativo. Para
aquellos casos en que el factor de carga es bajo (< 0.5), el sondeo lineal tiende a agrupar los
sinónimos, mientras que el doble hashing tiende a dispersar los sinónimos más ampliamente a
través del espacio de direcciones.
El doble hashing tiende a comportarse casi también como el sondeo lineal con factores de carga
pequeños (< 0.5), pero actúa un poco mejor para factores de carga mayores. Con un factor de
carga > 80 %, el sondeo lineal por lo general resulta tener un comportamiento terrible, mientras que
el doble hashing es bastante tolerable para búsquedas exitosas pero no así en búsquedas no
exitosas.


Conclusión
-Algunas veces la eficiencia de un programa es algo transparente para los
usuarios y a veces para el desarrollador joven, pues la diferencia en tiempo de
ejecución entre un programa eficiente y uno no eficiente y la cantidad de recursos
que utilizan suelen ser irrelevantes por el tipo de aplicaciones que se programan.
Pero es ciertamente es un tema de mucha importancia en especial en niveles más
altos de programación, cuando la lógica y el código se domine solo queda
optimizar. Es muy interesante investigar diferentes algoritmos con particularidades
diferentes aunque cuenten con el mismo fin como por ejemplo la búsqueda
secuencial y Binaria, las 2 hacen los mismo pero tienen sus beneficios e
inconvenientes, pues la búsqueda binaria requiere que se ordenen los elementos
a analizar lo que requiere programación extra, la búsqueda secuencial es más
sencilla y no requiere que se ordenen los elementos pero en el peor de los casos
comparar todos los elementos presentes. Entonces cae en el programador decidir
que algoritmo le beneficia a su aplicación.