Sie sind auf Seite 1von 16

Tabla hash

Una tabla hash, mapa hash, tabla de dispersin o tabla fragmentada es una estructura de
datos que asocia llaves o claves con valores. La operacin principal que soporta de manera
eficiente es la bsqueda: permite el acceso a los elementos (telfono y direccin, por ejemplo)
almacenados a partir de una clave generada (usando el nombre o nmero de cuenta, por
ejemplo). Funciona transformando la clave con una funcin hash en un hash, un nmero que
identifica la posicin (casilla o cubeta) donde la tabla hash localiza el valor deseado.
Un ejemplo prctico para ilustrar que es una tabla hash es el siguiente: Se necesita organizar
los peridicos que llegan diariamente de tal forma que se puedan ubicar de forma rpida,
entonces se hace de la siguiente forma - se hace una gran caja para guardar todos los
peridicos (una tabla), y se divide en 31 contenedores (ahora es una "hash table" o tabla
fragmentada), y la clave para guardar los peridicos es el da de publicacin (ndice). Cuando
se requiere buscar un peridico se busca por el da que fue publicado y as se sabe en que
zcalo (bucket) est. Varios peridicos quedarn guardados en el mismo zcalo (es decir
colisionan al ser almacenados), lo que implica buscar en la sub-lista que se guarda en cada
zcalo. De esta forma se reduce el tamao de las bsquedas de O(n) a, en el mejor de los
casos, O(1) y, en el peor, a O(log(n)).

Ejemplo de tabla hash.

Las tablas hash se suelen implementar sobre vectores de una dimensin, aunque se pueden
hacer implementaciones multi-dimensionales basadas en varias claves. Como en el caso de
los arrays, las tablas hash proveen tiempo constante de bsqueda promedio O(1),1 sin
importar el nmero de elementos en la tabla. Sin embargo, en casos particularmente malos el
tiempo de bsqueda puede llegar a O(n), es decir, en funcin del nmero de elementos.
Comparada con otras estructuras de arrays asociadas, las tablas hash son ms tiles cuando
se almacenan grandes cantidades de informacin.
Las tablas hash almacenan la informacin en posiciones pseudo-aleatorias, as que el acceso
ordenado a su contenido es bastante lento. Otras estructuras como rboles binarios autobalanceables tienen un tiempo promedio de bsqueda mayor (tiempo de bsqueda O(log n)),
pero la informacin est ordenada en todo momento.

#include<stdio.h>
1. #include<stdlib.h>
2.
3. #define MAXC 10//MAXIMO TAMAO DE UNA CADENA
4. #define MAXA 10//TAMAO DE LA TABLA
5.
6. struct nodo
7. {
8.

char *cadena;

9.

struct nodo *siguiente;

10.

};

11.
12.

int clave (char cadenaux[MAXC])//OBTIENE LA SUMA DE LOS


VALORES ASCII DE CADA CARACTER DE LA CADENA

13.

14.

int clave=0, ascii, i=0;

15.
16.

while((ascii=cadenaux[i++])!='')

17.

clave+=ascii;

18.
19.
20.

return clave;
}

21.

int hash (int clave)//SE DETERMINA LA POSICIO EN LA QUE SE


GUARDARA LA CADENA

22.

23.

int posicion=clave%MAXA;

24.
25.
26.

return posicion;
}

27.
28.

void insertar(struct nodo **ptabla, char


cadena[MAXC])//INSERTAR NUEVO ELEMENTO EN UNA LISTA

29.

30.

struct nodo *nuevo = (struct nodo*) malloc(sizeof(struct


nodo));//CREAMOS EL NUEVO NODO

31.

nuevo->cadena = cadena;//GUARDAMOS CADENA

32.

nuevo->siguiente = NULL;//COMO SE VA A INSERTAR AL FINAL,


SERA EL QUE APUNTE A NULL

33.

struct nodo *actual=*ptabla;//CREAMOS UN PUNTERO AUXILIAR


A NODO

34.
35.

if (*ptabla==NULL)

36.

37.

*ptabla=nuevo;//SI LISTA VACIA, ENTONCES: NUEVO ES EL


PRIMER ELEMENTO

38.

39.

else

40.

41.

while (actual->siguiente != NULL)

42.

43.

printf("n %s n", actual->cadena);

44.

actual = actual->siguiente;//SI NO ESTA VACIA, SE


RECORRE LA LISTA

45.

46.

actual->siguiente =nuevo;//EL ULTIMO NODO AHORA


ANTECEDE AL NUEVO

47.

48.

49.
50.

void mostrar(struct nodo *ptabla)//IMPRIMIR LA TABLA

51.

52.

struct nodo *actual=ptabla;//ACTUAL ES UN PUNTERO


AUXILIAR PARA RECORRER LA LISTA

53.
54.

while (actual!=NULL)//MIENTRAS NO SEA EL FINAL DE LA


LISTA

55.

56.

printf("[ %s ]->", actual->cadena);//IMPRIME EL DATO


DEL NODO CORRESPONDIENTE

57.

actual = actual->siguiente;//AVANZAMOS AL SIGUIENTE


NODO

58.

59.

printf("NULLnn");

60.

61.
62.

main()

63.

64.

struct nodo *ptabla[MAXA];//ARREGLO DE PUNTEROS PARA


NODOS

65.

char cadenaux[MAXC];//ARREGLO AUXILIAR PARA GUARDAR


CADENA INTRODUCIDA

66.

int op, clavecadena, pos;//VARIABLES USADAS PARA MENU Y


POSICION EN EL ARREGLO

67.
68.

for(pos=0;pos<MAXA;pos++) ptabla[pos]=NULL;

69.
70.

do

71.

72.

printf("n*********************************n");

73.

printf("nnTABLA HASHnn

74.

t1.- Guardar una cadenan

75.

t2.- Buscar una candenan

76.

t3.- Borrar una cadenan

77.

t0.- Salir.ttt");

78.

scanf("%i", &op);

79.

printf("n*********************************n");

80.
81.

switch(op)

82.

83.

case 1:

84.

printf("nIntroduce cadenan");

85.

fflush(stdin);

86.

gets(cadenaux);

87.

clavecadena=clave(cadenaux);

88.

pos=hash(clavecadena);

89.

insertar(&(ptabla[pos]), cadenaux);

90.

for(pos=0;pos<MAXA;pos++)
mostrar(ptabla[pos]);

91.

break;

92.

93.
94.

}while(op!=0);
}

95.
96.

Quiero implementar tablas hash en C, se me ocurri declarar un arreglo de punteros


para los nodos de listas enlazadas.
Uso listas enlazadas para solucionar los problemas de colisin.
La funcin hash que utilizo es: Dada una cadena, obtengo la suma de los valores ascii
de cada caracter de la cadena, al resultado le aplico la operacin: resultado
%tamao_lista (mdulo), lo que resulte sera la posicin donde se guarde el dato.
Hasta ahora slo he hecho las funciones para insertar un nodo y para mostrar la tabla,
pero tengo un problema:
En una tabla de tamao 10
Supongamos que inserto la cadena "A"

la suma de los valores ascii de cada caracter es 65


65%10=5, entonces la cadena "A" se guardar en la posicin 5.
hasta ah todo perfecto. Si introduzco otra cadena "A" se guarda en la misma posicin
pero en la lista anidada.
Si imprimen la tabla podrn ver que todo parece estar bien.
Ahora si introduzco una cadena "B", resulta que se guardar en la posicin 6; y as
ocurre, la cadena se guarda en la posicin indicada, pero si imprimo de nuevo la tabla,
resulta que todas las cadenas en la tabla son "B".
y si introdujera otra distinta, todas se convierten en la ltima.
Dejo mi cdigo para que si pueden me indiquen qu hago mal, porque por ms que le
doy vueltas no veo mi error.
ejecuten el progrma y hagan las operaciones que les digo para que vean bien el
problema.
Agradezco mucho me ayuden a entender.

Conceptos de hashing
a) Clave: La clave contiene el valor que permite ubicar, mediante la funcin Hash, la posicino
registro que contiene el resto de informacin asociada. Normalmente la clave es el campo que
identifica en forma nica la informacin. Por ejemplo:

Cdula de Identidad

Registro de Informacin Fiscal

Placa o Matrcula de Vehculo

b) Funcin Hash: Es un algoritmo o transformacin que, aplicado a la clave, devuelve la


posicin del destino en donde podemos ubicar o recuperar el elemento que contiene dicha
clave. Normalmente consta de tres partes:

1. Transformacin: Si la clave no es numrica se convierte en un nmero. Con


frecuenciase utiliza el valor ASCII de cada carcter y luego se aplican operaciones
matemticas para obtener un nmero entero.
2. Generacin: El nmero generado se procesa con un algoritmo que trata deuniformizar
la distribucin de las claves en el rango de direcciones.

3. Compresin: Se comprime el nmero obtenido multiplicndolo por un factor para


adecuarlo a la capacidad de almacenamiento disponible.La funcin Hash debe
definirse al momento de disear el sistema y su seleccin tiene gran incidencia en
rendimiento del sistema. Una buena funcin Hash debe tener las siguientes
caractersticas:

Sencilla, de manera que sea fcil de codificar y minimice el tiempo de clculo.

Distribucin Uniforme de las direcciones tratando que la generacin distribuya en


forma aleatoria las claves y evite agrupamientos.

La idea es seleccionar una funcin que permita obtener una distribucin con el mayor grado
de

uniformidad

posible

para

evitar

colisiones.

El codigo implementado consiste en crear un archivo llamado dispersion.txt donde se gurdan


los respetivos registros en su posicion de acuuerdo a la clave generada por la funcion
hashing(); que manipula los caracteres de la clave mediante codigo ASCII y devuelve un
entero que seria el numero de registro. Si al devolver la funcion hashing se repite(hay una
colision) el numero de registro, este registro pasa a ser insertado en el archivo colisiones.txt
Otro punto importante es que cada registro escrito en el archivo siempre tiene un puntero
(llamado SR) que guarda el numero de registro del siguiente creando asi una lista. Alli en la
imagen podemos apreciar la estructura de como se guarda los registros en el archivo.

Finalmente aclaro que para este programa considere como clave como el nombre de una
persona y la data su apellido, ustedes pueden acomodarle de acuerdo a sus necesidades.

Implementacion en C++
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
using namespace std;
struct registro{
int

nr;

char clave[8];
char data[8];
int sr;
}r, a, s;
struct encabezado{
int nrs;
}ed, ec;

/// encabezado de dispersion y colisiones

FILE *fdd, *fdc;


int lr, le;
int fh( char *clave )
{
int nr = 0;
for(int i=0; i<strlen(clave); i++)
{
nr += int(clave[i]);
}
nr = nr%10 + 1;
return nr;
}
/********************** Funcion Escribir ***********************/
void escribir()

{
int

pos, x;

char rpt;
bool band;

fdd = fopen("dispersion.dat", "w+");


if(fdd==NULL){
cout << " No se pudo crear dispersion.dat" << endl;
return;
}
fdc = fopen("colisiones.dat", "w+");
if(fdc==NULL){
cout << " No se pudo crear colisiones.dat" << endl;
return;
}
/// Inicializando variables
ed.nrs = 0;
ec.nrs = 0;
fwrite(&ed, le, 1, fdd);
fwrite(&ec, le, 1, fdc);
/// Bucle para insertar varios registros
do
{
fflush(stdin);
cout << " Clave: "; gets(r.clave);
cout << " Data : "; gets(r.data);
fflush(stdin);
r.sr = -1;
r.nr = fh(r.clave);
cout << " Clave = "<< r.nr << endl;
pos = (r.nr-1)*lr + le;

fseek(fdd, pos, 0);


fread(&s, lr, 1, fdd);
if(strcmp(s.clave, "")==0)
{
fseek(fdd, pos, 0);
fwrite(&r, lr, 1, fdd);
++ed.nrs;
}
else
{
band = false;
x = s.sr;
/// entramos al archivo de colisiones
while(x != -1)
{
band = true;
pos = (x-1)*lr + le;
fseek(fdc, pos, 0);
fread(&s, lr, 1, fdc);
a = s;
x = s.sr;
}
/// Listas de en el archivo de colision
if(band==true)
{
r.nr = ++ec.nrs;
a.sr = r.nr;
fseek(fdc, pos, 0);
fwrite(&a, lr, 1, fdc);
fseek(fdc, 0, 2);
fwrite(&r, lr, 1, fdc);
}
if(band==false)
{
r.nr = ++ec.nrs;

s.sr = r.nr;
fseek(fdd, pos, 0);
fwrite(&s, lr, 1, fdd);
fseek(fdc, 0, 2);
fwrite(&r, lr, 1, fdc);
}
}
cout << " Mas registros [s/n] : "; cin >> rpt; cout << endl;
}while(rpt!='n');
fseek(fdd, 0, 0);
fwrite(&ed, le, 1, fdd);

/// actualizamos la cabezera del

archivo DISPERSION
fseek(fdc, 0, 0);
fwrite(&ec, le, 1, fdc);

/// actualizamos la cabezera del

archivo COLISIONES
fclose(fdd);
fclose(fdc);
}
/********************** Funcion Leer ***********************/
void buscar()
{
int

pos, x, nr;

char v_clave[10];
bool band;
fdd = fopen("dispersion.dat", "r");
if(fdd==NULL){
cout << " No se pudo abrir disperson.dat" << endl; return;
}
fdc = fopen("colisiones.dat", "r");
if(fdc==NULL){
cout << " No se pudo abrir colisiones.dat " << endl; return;
}

fflush(stdin);
cout << " Ingrese clave : "; gets(v_clave);
nr = fh(v_clave);
pos = (nr-1)*lr + le;
fseek(fdd, pos, 0);
fread(&r, lr, 1, fdd);
if(strcmp(v_clave, r.clave)==0)
{
cout << " Su data es: " << r.data << endl;
return;
}
else
{
band = false;
x = r.sr;
while( x != -1 )
{
pos = (x-1)*lr + le;
fseek(fdc, pos, 0);
fread(&r, lr, 1, fdc);
if(strcmp(v_clave, r.clave)==0)
{
band = true;
cout << " Su data es : " << r.data << endl;
break;
}
}
if(band == false)
{
cout << " No esta registrado..!" << endl;
}
}
fclose(fdd);

fclose(fdc);
}
void mostrar_archivos()
{
fdd = fopen("dispersion.dat", "r");
if(fdd==NULL){
cout << " No se pudo abrir disperson.dat" << endl; return;
}
fdc = fopen("colisiones.dat", "r");
if(fdc==NULL){
cout << " No se pudo abrir colisiones.dat " << endl; return;
}
fread(&ed, le, 1, fdd);
cout << " Longitud Registro

: " << lr << endl;

cout << " Longitud de encabezado: " << le << endl;


cout << "\nArchivo dispersion.txt \n";
cout << "----------------------------------- \n";
cout << "

NR

CLAVE

DATA

SR

\n";

while( fread(&s, lr, 1, fdd)!=NULL)


{
cout << setw(4) << s.nr << setw(10) << s.clave << setw(10);
cout << s.data << setw(6) << s.sr << endl;
}
fread(&ed, le, 1, fdc);
cout << "\nArchivo colisiones.txt \n";
cout << "----------------------------------- \n";
cout << "

NR

CLAVE

DATA

SR

\n";

while( fread(&s, lr, 1, fdc)!=NULL)


{
cout << setw(4) << s.nr << setw(10) << s.clave << setw(10);
cout << s.data << setw(6) << s.sr << endl;
}

fclose(fdd);
fclose(fdc);
}
void menu()
{
cout << "\t\t METODO DE DISPERSION - HASHING \n\n";
cout << "\t 1. Escribir

\n";

cout << "\t 2. Buscar Registro

\n";

cout << "\t 3. Mostrar Archivo

\n";

cout << "\t 4. Salir

\n";

cout << "\t >> Ingrese opcion:

";

}
/********************** Funcion Principal ***********************/
int main()
{
int op;
lr = sizeof(struct registro);
le = sizeof( struct encabezado);
do
{
menu(); cin >> op;
cout<<endl;
switch(op)
{
case 1:
escribir(); break;
case 2:
buscar(); break;
case 3:
mostrar_archivos();
case 4:
exit(0);

}
cout <<"\n\n ";
system("pause"); system("cls");
}while(op>0);
return 0;
}

Das könnte Ihnen auch gefallen