Академический Документы
Профессиональный Документы
Культура Документы
Estructuras de datos
Grupo: 1CM7
Integrantes:
Lopez Manrquez Angel Profesor:
Ontiveros Salazar Alan Enrique Franco Martnez Edgardo Adrian
Varela Aguilar Luis Pavel
Practica 3: Diccionario con hashing abierto
1CM7
ESCOM-IPN
14 de junio de 2017
1. Introduccion
Funcion Hash:
Una funcion hash, normalmente conocida como hash [1], es un algoritmo matematico que transforma
cualquier bloque arbitrario de datos en una nueva serie de caracteres con una longitud fija. Independientemente
de la longitud de los datos de entrada, el valor hash de salida tendra siempre la misma longitud.
1. La primer forma de hacer la tabla es con base a los valores ASCII y contando con un ambiente ideal
en donde solo hay palabras tales que su primer letra son solo caracteres alfanumericos mayusculas (sin
contar la n), tenemos que el tamano de la tabla hash sera de 26. Ahora, nos fijamos en la primera letra
de la palabra para retornar un entero positivo para obtener una posicion en donde se van a agrupar al
conjunto de palabras, notemos que esto es bastante facil, puesto que solo tenemos que obtener el valor
ASCII de P [0] 0 A0 donde P [0] es el primer caracter de la palabra. Por otro lado, si consideramos las
palabras que pueden empezar por cualquier caracter, es decir, cualquier valor ASCII, vemos que nuestra
funcion hash puede tener errores tales como regresar valores que excedan el tamano de la tabla hash
o peor, podran haber valores negativos (por ejemplo, la n), aunque, esto es bastante facil de resolver,
simplemente obtenemos el modulo de la diferencia positivo, por lo que nuestra tabla hash queda como:
1
Practica 3: Diccionario con hashing abierto 2
2. Para la segunda tabla hash igual usamos los valores ASCII, con la diferencia de que aqu, retornamos el
valor de la suma de los caracteres de la palabra modulo 26, as, nuestra funcion hash queda como:
Esta funcion tiene la ventaja de que el hasheo es mas uniforme pero tiene mas costo y si el diccionario
tiene muchsimas palabras y de mayor longitud, el programa se alentara.
Para agrupar las palabras en la tabla basta con obtener un entero i con la funcion hash e insertar la palabra
con su definicion en la posicion i-esima de la tabla, a su vez, para consultar alguna palabra en la tabla basta
con obtener el valor hash de la palabra y consultar la tabla con base a este valor. El concepto de tabla hash
ayuda bastante a la creacion programa, puesto que ordena de una manera eficiente las palabras y las consultas
a las tablas son baratas [3].
4. Implementacion de la solucion
Veamos como se implementa la solucion al problema dado en C:
1 /* Diccionario usando tablas hash .
2
3 Equipo : Quick Coding
4 compilacion : gcc m . c Lista . c */
5
6 /* Algunas implementaciones que dan valor agregado a la califiacion son :
7 - El usuario puede exportar en determinado momento la lista de
palabras de un archivo . OK funcion exportList
8 Se puede buscar todas las palabras que empiecen con :
9 - Una letra . OK funcion : searchLetter
10 - Una frase . OK funcion : searchSentece
11 - Que contengan una subcadena . OK funcion : searchSubstring
12 - Exportar una definicion de un archivo . OK funcion :
exportDefinition
13
14 Puesto que vamos a trabajar con archivos , es importante que el archivo
tenga el formato
15
16 palabra1 : definicion1 \ n
17 palabra2 : definicion2 \ n
18 .
19 .
20 .
21 palabraN : defincionN \ n
22
23 para que la funcion loadFile () funcione apropiadamente . */
ESCOM-IPN 2
Practica 3: Diccionario con hashing abierto 3
24
25 # include < stdio .h >
26 # include < stdlib .h >
27 # include < string .h >
28 # include < stdbool .h >
29 # include < ctype .h >
30 # include " Lista . h "
31
32 char nombreArchivo [50];
33 bool archivoCargado = false ;
34
35 # define TAMHASH 26
36
37 /* Funcion que obtiene el modulo de a % b positivo . */
38 int
39 mod ( int a , int b ) {
40 int r = a % b ;
41 if ( r < 0)
42 r += b ;
43 return r ;
44 }
45
46 /* Funcion hash mejorada en la que , como argumento recibiremos un puntero
a un arreglo
47 * de char , solo es relevante key [0] y , con base a key [0] retornaremos un
digito en donde
48 * se corresponde . Como se muestra a continuacion :
49
50 A : 0 , B : 1 , ... , Z : 26.
51
52 El programa esta diseniado de tal forma que los caracteres de key [0]
sean tales que :
53
54 A <= key [0] <= Z notese que las letras son mayusculas
55
56 A pesar de su simpleza es muy , pero muy util . Que la funcion hash
reciba a un
57 caracter alfanumerico en mayusculas la primera letra del arreglo
favorece a la busqueda
58 del programa . */
59
60 /* int hash ( char * key ) { return mod ( key [0] - A , TAMHASH ) ; } */
61
62
63 int
64 hash ( char * st ) {
65 int i = 0 , acum = 0;
66 for ( i = 0; i < strlen ( st ) ; i ++)
67 acum += st [ i ];
68 return mod ( acum , TAMHASH ) ;
69 }
70
71
72 /* Funcion muy parecida a fgets (x , y , z ) , solo que al final del string s
,
ESCOM-IPN 3
Practica 3: Diccionario con hashing abierto 4
ESCOM-IPN 4
Practica 3: Diccionario con hashing abierto 5
124 i ++;
125 }
126 if ( pos != NULL )
127 InsertBefore ( subl , e , pos ) ;
128 else
129 AddEnd ( subl , e ) ;
130
131 return i ;
132 }
133
134 /* Funcion que carga el archivo y va llenando la tabla hash con base al
mismo . */
135 void
136 loadFile ( lista * t ) {
137 int c = n , i = 0;
138 char * nombre , * def ;
139 elemento e ;
140
141 /* Esta condicion sirve para saber si el usuario desea cargar otro
archivo . */
142 if ( archivoCargado ) {
143 char ans [9];
144 printf ( " \ nParece ser que el archivo %s ya ha sido cargado \ n " ,
nombreArchivo ) ;
145 printf ( " Desea cargar otro ? ( s / n ) : " ) ;
146 fgets ( ans , 9 , stdin ) ;
147 if ( ans [0] == s || ans [0] == S ) {
148 for ( i = 0; i < TAMHASH ; i ++)
149 Destroy (& t [ i ]) ;
150 /* Importante la declaracion lista *t , no basta con t = ...
*/
151 lista * t = ( lista *) calloc ( TAMHASH , sizeof ( lista ) ) ;
152 } else
153 return ;
154 }
155 printf ( " Nombre del archivo (. txt ) : " ) ;
156 strscan ( nombreArchivo , 40) ;
157 sprintf ( nombreArchivo , " %s . txt " , nombreArchivo ) ;
158 FILE * fp = fopen ( nombreArchivo , " rb " ) ;
159
160 if (! fp ) {
161 printf ( " El archivo %s no existe . \ n " , nombreArchivo ) ;
162 return ;
163 }
164
165 /* Recorremos el archivo con un bucle while , mientras que c no sea
EOF
166 ( es decir , no lleguemos al final del archivo ) vamos recorriendo el
167 archivo , caracter a caracter y vamos guardando en un string su
nombre
168 y definicion por separado . */
169 while (! feof ( fp ) ) {
170 nombre = ( char *) calloc ( TAMNOM , sizeof ( char ) ) ;
171 def = ( char *) calloc ( TAMDEF , sizeof ( char ) ) ;
172 i = 0;
ESCOM-IPN 5
Practica 3: Diccionario con hashing abierto 6
ESCOM-IPN 6
Practica 3: Diccionario con hashing abierto 7
ESCOM-IPN 7
Practica 3: Diccionario con hashing abierto 8
ESCOM-IPN 8
Practica 3: Diccionario con hashing abierto 9
ESCOM-IPN 9
Practica 3: Diccionario con hashing abierto 10
376 void
377 changeDefinition ( lista * t ) {
378 char nuevaDef [ TAMDEF ] , pBuscada [ TAMNOM ];
379 int i = 0 , contador = 0;
380
381 printf ( " \ nIngrese la palabra a cambiar : " ) ;
382 strscan ( pBuscada , TAMNOM ) ;
383
384 /* Comprobamos si existe la palabra */
385 if ( existWord (t , pBuscada ) ) {
386 FILE * fp = fopen ( nombreArchivo , " wb " ) ;
387 if (! fp ) {
388 printf ( " \ nEl archivo %s no existe . \ n " , nombreArchivo ) ;
389 return ;
390 }
391 nodo * ptr ;
392 /* Obtenemos la nueva definicion . */
393 printf ( " Nueva definicion : " ) ;
394 strscan ( nuevaDef , TAMDEF ) ;
395
396 /* Recorremos las 26 palabras y reescribimos todo el archivo ,
cuando nos
397 encontremos con la palabra a cambiar , escribimos la nueva
palabra y nos
398 saltamos la sobreescritura de la palabra anterior , asi como su
definicion . */
399 for ( i = 0; i < TAMHASH ; i ++) {
400 ptr = t [ i ]. frente ;
401 while ( ptr ) {
402 if (! strncmp ( pBuscada , ptr - > e . nombre , TAMNOM ) ) {
403 sprintf ( ptr - > e . definicion , " %s " , nuevaDef ) ;
404 fprintf ( fp , " %s : %s \ n " , pBuscada , nuevaDef ) ;
405 strncpy ( ptr - > e . definicion , nuevaDef , TAMDEF ) ;
406 printf ( " \ nSe realizaron %d iteraciones para localizar
la palabra " , contador + 1) ;
407 } else
408 fprintf ( fp , " %s : %s \ n " , ptr - > e . nombre , ptr - > e .
definicion ) ;
409 ptr = ptr - > siguiente ;
410 contador ++;
411 }
412 }
413
414 fclose ( fp ) ;
415 }
416 else
417 printf ( " La palabra \" % s \" no se encuentra \ n " , pBuscada ) ;
418 }
419
420 /* Exporta toda la lista a un archivo con el nombre que el usuario desee .
*/
421 void
422 exportList ( lista * t ) {
423 int i , cont = 0;
424 nodo * ptr = NULL ;
ESCOM-IPN 10
Practica 3: Diccionario con hashing abierto 11
ESCOM-IPN 11
Practica 3: Diccionario con hashing abierto 12
478 }
479 ptr = ptr - > siguiente ;
480 cont ++;
481 }
482 fclose ( fp ) ;
483 } else
484 printf ( " La palabra %s no se encuentra en el diccionario .\ n " ,
nombre ) ;
485 }
486
487 /* Funcion que busca todas las palabras disponibles , con su respectiva
definicion
488 que contengan una subcadena dada ( si existe ) . */
489 void
490 searchSubstring ( lista * t ) {
491 char substr [ TAMNOM ];
492 int i , n , N , cont = 1;
493 bool hayUna = false ;
494 nodo * ptr = NULL ;
495
496 printf ( " \ nEscriba la subcadena : " ) ;
497 strscan ( substr , TAMNOM ) ;
498 n = strlen ( substr ) ;
499
500 /* Con un bucle recorremos las 26 listas que como maximo puede tener
la tabla . */
501 for ( i = 0; i < TAMHASH ; i ++) {
502 ptr = t [ i ]. frente ;
503 while ( ptr ) {
504 N = strlen ( ptr - > e . nombre ) ;
505 if ( n <= N )
506 /* La funcion char * strstr ( char *A , char * B ) retorna
true si la subcadena B esta en A */
507 if ( strstr ( ptr - > e . nombre , substr ) ) {
508 printf ( " %s : %s \ n " , ptr - > e . nombre , ptr - > e . definicion )
;
509 printf ( " Iteraciones para localizar la subcadena \" % s
\": %d \ n \ n " , substr , cont ) ;
510 hayUna = 1;
511 }
512 ptr = ptr - > siguiente ;
513 cont ++;
514 }
515 }
516 if (! hayUna )
517 printf ( " No se encuentra ninguna palabra con la subcadena %s .\ n " ,
substr ) ;
518 }
519
520 /* Funcion que , pregunta alguna frase y muestra las palabras disponibles
en el diccionario
521 tales que su definicion contengan a la frase . */
522 void
523 searchSentence ( lista * t ) {
524 char frase [ TAMNOM ];
ESCOM-IPN 12
Practica 3: Diccionario con hashing abierto 13
ESCOM-IPN 13
Practica 3: Diccionario con hashing abierto 14
5. Funcionamiento
Compilando, tenemos
ESCOM-IPN 14
Practica 3: Diccionario con hashing abierto 15
Vemos que no se produce ningun mensaje de error o advertencia, ahora, al ejecutar el programa vemos el
menu:
ESCOM-IPN 15
Practica 3: Diccionario con hashing abierto 16
Corroborando:
Corroborando:
ESCOM-IPN 16
Practica 3: Diccionario con hashing abierto 17
ESCOM-IPN 17
Practica 3: Diccionario con hashing abierto 18
Corroborando:
ESCOM-IPN 18
Practica 3: Diccionario con hashing abierto 19
6. Errores detectados
Como errores estan los caracteres extranos de las palabras que contienen acentos o la letra n, por ejemplo,
al cargar un archivo y usar la opcion 11, vemos
7. Posibles mejoras
Algunas mejoras en las que aun no estan en las especificaciones del programa seran: una funcion que muestre
los archivos a cargar en el directorio disponible, hacer la tabla hash mas grande para que las consultas sean mas
ESCOM-IPN 19
Practica 3: Diccionario con hashing abierto 20
8. Conclusiones
8.1. Alan
Las funciones hash tienen como utilidad asignar un conjunto de claves a otro mas facil de manejar, en este
caso mapeamos las palabras a simples enteros que indicaron en que posicion del arreglo deben estar. El hasheo
dinamico nos permitio reducir considerablemente los tiempos de busqueda de cada palabra, particionando de
manera eficiente al conjunto de palabras en el arreglo de listas.
8.2. Angel
El concepto de tablas hash es algo bastante util para las ciencias de la computacion, dado que permite
organizar datos de una forma util para el programador. Ademas de lo anterior dicho, es capaz de reducir la
complejidad de busqueda para elementos almacenados en una tabla hash. Por otra parte, el concepto de listas
para la programacion tambien es util, por ejemplo, en el lenguaje C, es una mejora a los arreglos, puesto que
cada elemento puede tener multiples atributos, ademas de que ahorra espacio (si la lista es dinamica, claro esta).
8.3. Luis
Mediante una buena funcion hash eficiente se evitan el mayor numero de colisiones, en este caso para la
funcion de encontrar las definiciones o palabras de una manera rapida y eficaz, y entre mas grande sea la
busqueda y/o el archivo ahorrar tiempo y recursos.
Anexos
A. Lista.c
1 # include " Lista . h "
2
3 void Initialize ( lista * l ) {
4 l - > frente = NULL ;
5 l - > final = NULL ;
6 l - > tamano = 0;
7 return ;
8 }
9
10 void Destroy ( lista * l ) {
11 posicion tmp ;
12 while (l - > frente != NULL ) {
13 tmp = l - > frente - > siguiente ;
14 free (l - > frente ) ;
15 l - > frente = tmp ;
16 }
17 l - > final = NULL ;
18 l - > tamano = 0;
19 return ;
20 }
ESCOM-IPN 20
Practica 3: Diccionario con hashing abierto 21
21
22 posicion First ( lista * l ) {
23 return l - > frente ;
24 }
25
26 posicion Final ( lista * l ) {
27 return l - > final ;
28 }
29
30 boolean ValidatePosition ( lista *l , posicion p ) {
31 posicion pos = l - > frente ;
32 while ( pos != NULL && pos != p )
33 pos = pos - > siguiente ;
34 return pos == p ;
35 }
36
37 posicion Previous ( lista *l , posicion p ) {
38 if ( ValidatePosition (l , p ) ) return p - > anterior ;
39 return NULL ;
40 }
41
42 posicion Following ( lista *l , posicion p ) {
43 if ( ValidatePosition (l , p ) ) return p - > siguiente ;
44 return NULL ;
45 }
46
47 posicion Search ( lista *l , elemento e ) {
48 posicion pos = l - > frente ;
49 while ( pos != NULL && memcmp (& pos - >e , &e , sizeof ( elemento ) ) != 0)
50 pos = pos - > siguiente ;
51 return pos ;
52 }
53
54 int Size ( lista * l ) {
55 return l - > tamano ;
56 }
57
58 boolean IsEmpty ( lista * l ) {
59 return Size ( l ) == 0;
60 }
61
62 elemento Position ( lista *l , posicion p ) {
63 elemento e ;
64 if ( ValidatePosition (l , p ) ) e = p - > e ;
65 return e ;
66 }
67
68 posicion ElementPosition ( lista *l , int n ) {
69 posicion pos = NULL ;
70 int c = 1;
71 if ( n <= l - > tamano ) {
72 pos = l - > frente ;
73 while ( c < n ) {
74 pos = pos - > siguiente ;
75 c ++;
ESCOM-IPN 21
Practica 3: Diccionario con hashing abierto 22
76 }
77 }
78 return pos ;
79 }
80
81 elemento Element ( lista *l , int n ) {
82 elemento e ;
83 posicion pos = ElementPosition (l , n ) ;
84 if ( pos != NULL ) e = pos - > e ;
85 return e ;
86 }
87
88 boolean InsertBefore ( lista *l , elemento e , posicion p ) {
89 boolean r = FALSE ;
90 posicion nuevo = ( posicion ) malloc ( sizeof ( nodo ) ) ;
91 if ( nuevo != NULL ) {
92 nuevo - > e = e ;
93 nuevo - > siguiente = p ;
94 if (p - > anterior == NULL ) {
95 nuevo - > anterior = NULL ;
96 l - > frente = nuevo ;
97 } else {
98 nuevo - > anterior = p - > anterior ;
99 p - > anterior - > siguiente = nuevo ;
100 }
101 p - > anterior = nuevo ;
102 l - > tamano ++;
103 r = TRUE ;
104 }
105 return r ;
106 }
107
108 boolean InsertAfter ( lista *l , elemento e , posicion p ) {
109 boolean r = FALSE ;
110 posicion nuevo = ( posicion ) malloc ( sizeof ( nodo ) ) ;
111 if ( nuevo != NULL ) {
112 nuevo - > e = e ;
113 nuevo - > anterior = p ;
114 if (p - > siguiente == NULL ) {
115 nuevo - > siguiente = NULL ;
116 l - > final = nuevo ;
117 } else {
118 nuevo - > siguiente = p - > siguiente ;
119 p - > siguiente - > anterior = nuevo ;
120 }
121 p - > siguiente = nuevo ;
122 l - > tamano ++;
123 r = TRUE ;
124 }
125 return r ;
126 }
127
128 boolean AddBeginning ( lista *l , elemento e ) {
129 boolean r = FALSE ;
130 posicion nuevo ;
ESCOM-IPN 22
Practica 3: Diccionario con hashing abierto 23
ESCOM-IPN 23
Practica 3: Diccionario con hashing abierto 24
B. Lista.h
1 # ifndef Lista_h
2 # define Lista_h
3
4 # include < stdlib .h >
5 # include < string .h >
6
7 # define TRUE 1
8 # define FALSE 0
9 # define TAMNOM 100
10 # define TAMDEF 1000
11 # define TAMHASH 26
12
13 typedef char boolean ;
14
15 typedef struct {
16 char nombre [ TAMNOM ];
17 char definicion [ TAMDEF ];
18 struct nodo * siguiente ;
19 struct nodo * anterior ;
20 } elemento ;
21
22 typedef struct nodo {
23 elemento e ;
24 struct nodo * anterior ;
25 struct nodo * siguiente ;
26 } nodo ;
27
28 typedef struct {
29 nodo * frente ;
30 nodo * final ;
31 int tamano ;
32 } lista ;
33
34 typedef nodo * posicion ;
35
36 // Operaciones de construccion
37 void Initialize ( lista * l ) ;
38 void Destroy ( lista * l ) ;
39
40 // Operaciones de posicionamiento y busqueda
41 posicion First ( lista * l ) ;
42 posicion Final ( lista * l ) ;
43 posicion Previous ( lista *l , posicion p ) ;
44 posicion Following ( lista *l , posicion p ) ;
45 posicion Search ( lista *l , elemento e ) ;
46
47 // Operaciones de consulta
48 elemento Position ( lista *l , posicion p ) ;
49 boolean ValidatePosition ( lista *l , posicion p ) ;
50 elemento Element ( lista *l , int n ) ;
51 posicion ElementPosition ( lista *l , int n ) ;
52 int Size ( lista * l ) ;
53 boolean IsEmpty ( lista * l ) ;
ESCOM-IPN 24
Practica 3: Diccionario con hashing abierto 25
54
55 // Operaciones de modificacion
56 boolean AddBeginning ( lista *l , elemento e ) ;
57 boolean AddEnd ( lista *l , elemento e ) ;
58 boolean InsertBefore ( lista *l , elemento e , posicion p ) ;
59 boolean InsertAfter ( lista *l , elemento e , posicion p ) ;
60 boolean Remove ( lista *l , posicion p ) ;
61 boolean Replace ( lista *l , posicion p , elemento e ) ;
62
63 # endif
C. Instrucciones de compilacion
gcc m.c Lista.c -o dicc.exe
Referencias
[1] K. A. H. Tiwari, Cryptographic Hash Function: An Elevated View, ser. Ace series. McGraw-Hill Education
(India) Pvt Limited, 2010. [Online]. Available: https://books.google.com.mx/books?id=a YnrbXyCv8C
[2] H. C. A. V. Tilborg, Encyclopedia of Cryptography and Security. Technical Publications, 2008. [Online].
Available: https://books.google.com.mx/books?id=TpdNkiHai4IC
[3] (2017) Improved range summable random variable construction algorithms. [Online]. Available:
http://interactivepython.org/runestone/static/pythonds/BasicDS/InfixPrefixandPostfixExpressions.html
ESCOM-IPN 25