Вы находитесь на странице: 1из 26

Instituto Politecnico Nacional

Escuela Superior de Computo

Estructuras de datos

Practica 3: Diccionario con hashing abierto

Grupo: 1CM7

Equipo: Quick Coding

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.

2. Planteamiento del problema


Con la implementacion del TAD lista realizar la implementacion de una tabla hash abierta, capaz de soportar
el almacenamiento de palabras y sus definiciones (Diccionario).
El programa debera ser capaz, como mnimo, de: cargar un archivo de texto con palabras asociadas a sus
definiciones, agregar palabras nuevas con su definicion, modificar una definicion al archivo, eliminar una palabra
y una opcion para salir de la ejecucion del programa. Otros puntos extras que dan valor agregado a la calificacion
(los cuales se implementaron) son: que el usuario pueda exportar en determinado momento la lista de palabras
de un archivo, mostrar por pantalla las palabras que empiecen con una letra, buscar una palabra con base a
una frase asociada a la definicion, buscar con base a una subcadena de la palabra y exportar una definicion a
un archivo. Se deben de proponer dos funciones hash.

3. Diseno y funcionamiento de la solucion


La manera en la que se penso en como abordar fue que, dado la forma en como estaban las palabras en el
archivo, pasar las palabras a una cadena y asociarlas con su definicion, posteriormente, agrupar las palabras
con base a alguna caracterstica y es aqu donde se usa el concepto del hashing [2]. Describamos dos formas de
hacer funciones hash.

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

Algorithm 1 Hash (string word)


1: return mod (word[0] - A, 26)

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:

Algorithm 2 Hash (string word)


1: int i, n = 0
2: for i = 1 to word.size do
3: n n + word[i]
4: end for
5: return mod (n, 26)

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

73 a diferencia de fgets () , ponemos el caracter nulo . Otra distincion


74 es que solo se puede guardar el string el usuario , con el teclado .
75
76 Notese que fgets () tiene 3 parametros , aqui dos , digamos que por
defecto tiene el
77 modo stdin si la comparamos con fgets () en el tercer parametro . */
78 void
79 strscan ( char *s , int lim ) {
80 int i = 0 , c = 0 ;
81
82 while ( i < lim && ( c = getchar () ) != \ n ) {
83 *( s + i ) = c ;
84 i ++;
85 }
86
87 *( s + i ) = \0 ;
88 }
89
90 /* Funcion que muestra las colisiones en la tabla hash .
91 la variable l sirve para dar un salto de linea cada 3 veces que se
muestren las
92 colisiones de una palabra . */
93 void
94 showCollisions ( lista * t ) {
95 int i = 0;
96
97 printf ( " Estadisticas :\ nLongitud de la tabla hash : %d \ n " , TAMHASH ) ;
98 for ( i = 0; i < TAMHASH ; i ++) {
99 printf ( " %d colisiones en el indice %d . " , Size (& t [ i ]) , i ) ;
100 if (( i + 1) % 3 == 0) {
101 printf ( " \ n " ) ;
102 } else
103 printf ( " \ t " ) ;
104 }
105 printf ( " \ n " ) ;
106 }
107
108 /* Embutimos en un elemento e los arreglos de caracteres . */
109 void
110 fillElement ( elemento *e , char nombre [] , char definicion []) {
111 strncpy (e - > nombre , nombre , TAMNOM ) ;
112 strncpy (e - > definicion , definicion , TAMDEF ) ;
113 }
114
115 /* Inserta alfabeticamente en un arreglo de listas un elemento que
contenga un campo nombre . */
116 int
117 insertAlpha ( lista *t , elemento e ) {
118 int i = 0 , indice = hash ( e . nombre ) ;
119 lista * subl = & t [ indice ];
120 nodo * pos = t [ indice ]. frente ;
121
122 while ( i < Size ( subl ) && strncmp ( e . nombre , pos - > e . nombre , TAMNOM ) >
0) {
123 pos = Following ( subl , pos ) ;

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

173 /* Puesto que el archivo tiene el formato :


174 Palabra : definicion . \ n
175 se sabe que la palabra abarca desde su primera letra hasta los
dos puntos . */
176 while ( i < TAMNOM && ( c = fgetc ( fp ) ) != : && c != \ n && c !=
EOF )
177 if ( c != \ r )
178 nombre [ i ++] = c ;
179 if ( i > 0) {
180 nombre [ i ++] = \0 ;
181 c = fgetc ( fp ) ;
182 i = 0;
183 /* De manera similar , la definicion abarca desde su primera
letra hasta el salto
184 * de linea . */
185 while ( i < TAMDEF && ( c = fgetc ( fp ) ) != \ n && c != EOF )
186 if ( c != \ r )
187 def [ i ++] = c ;
188 def [ i ++] = \0 ;
189 /* Insertamos la palabra a la tabla hash . */
190 fillElement (& e , nombre , def ) ;
191 // AddEnd (& t [ hash ( nombre ) ] , e ) ;
192 insertAlpha (t , e ) ;
193 }
194 }
195 archivoCargado = true ;
196 fclose ( fp ) ;
197 showCollisions ( t ) ;
198 }
199
200 /* Funcion que imprime todas las palabras del archivo . */
201 void
202 printAvailable ( lista * l ) {
203 bool b = false ;
204 int i = 0 , contador = 0;
205
206 /* Nos aseguramos que exista una palabra , como minimo . */
207 for ( i = 0; i < TAMHASH ; i ++)
208 if ( l [ i ]. frente ) {
209 b = true ;
210 break ;
211 }
212
213 if ( b ) {
214 i = 0;
215 nodo * ptr = NULL ;
216
217 for ( i = 0; i < TAMHASH ; i ++) {
218 ptr = l [ i ]. frente ;
219
220 /* Imprimimos la palabra , si existe almenos una palabra
221 con un caracter en la fila i , se entra al bucle , si no
222 no entra , asi nos aseguramos de evadir el error SIGSEGV .
*/
223

ESCOM-IPN 6
Practica 3: Diccionario con hashing abierto 7

224 while ( ptr ) {


225 printf ( " %d . - %s \ n " , ++ contador , ptr - > e . nombre ) ;
226 ptr = ptr - > siguiente ;
227 }
228 }
229 }
230 else
231 puts ( " No se ha cargado ningun archivo .\ n " ) ;
232 }
233
234 /* Funcion que imprime una palabra solicitada , si existe . */
235 void
236 showDefinition ( lista * t ) {
237 char comp [ TAMNOM ];
238 int indice = 0 , i = 0 , contador = 1;
239 nodo * ptr = NULL ;
240
241 printf ( " Escriba la palabra a buscar : " ) ;
242 strscan ( comp , TAMNOM ) ;
243
244 /* Obtenemos el indice correspondiente a la palabra . */
245 indice = hash ( comp ) ;
246 ptr = t [ indice ]. frente ;
247
248 /* Procedemos a buscar la palabra , si existe se imprimira la palabra
249 con su correspondiente definicion , si no existe se muestra por
250 pantalla que no existe la palabra buscada . */
251 while ( ptr ) {
252 if (! strcmp ( comp , ptr - > e . nombre ) ) {
253 printf ( " %s : %s \ n " , ptr - > e . nombre , ptr - > e . definicion ) ;
254 printf ( " Iteraciones para encontrar la palabra : %d . \ n " ,
contador ) ;
255 return ;
256 }
257 ptr = ptr - > siguiente ;
258 contador ++;
259 }
260
261 printf ( " La palabra \" % s \" no se encuentra en el diccionario . \ n " ,
comp ) ;
262 }
263
264 /* Funcion que imprime todas las palabras disponibles con la letra
inicial propuesta . */
265 void
266 searchLetter ( lista * t ) {
267 char letra ;
268 int i = 0 , contador = 0;
269
270 printf ( " Letra : " ) ;
271 letra = getchar () ;
272
273 for ( i = 0; i < TAMHASH ; i ++) {
274 nodo * ptr = t [ i ]. frente ;
275

ESCOM-IPN 7
Practica 3: Diccionario con hashing abierto 8

276 while ( ptr ) {


277 if ( ptr - > e . nombre [0] == letra )
278 printf ( " %d . - %s \ n " , ++ contador , ptr - > e . nombre ) ;
279 ptr = ptr - > siguiente ;
280 }
281
282 }
283
284 if ( contador == 0)
285 puts ( " No se encuentra ninguna palabra con esa letra .\ n " ) ;
286 }
287
288 /* Agregamos una palabra , tanto al archivo como a la lista . */
289 void
290 addWord ( lista * l ) {
291 char nombre [ TAMNOM ] , definicion [ TAMDEF ] , parrafo [ TAMNOM + TAMDEF +
10];
292 elemento e ;
293 int iteraciones ;
294 FILE * fp = fopen ( nombreArchivo , " ab + " ) ;
295 if (! fp ) {
296 printf ( " \ n El archivo %s no existe . \ n " , nombreArchivo ) ;
297 return ;
298 }
299 printf ( " Palabra nueva : " ) ;
300 strscan ( nombre , TAMNOM ) ;
301
302 printf ( " Definicion : " ) ;
303 strscan ( definicion , TAMDEF ) ;
304
305 /* Hacemos que el primer caracter sea mayus . si la primera letra es
alfabetica . */
306 nombre [0] = toupper ( nombre [0]) ;
307 sprintf ( parrafo , " %s : %s " , nombre , definicion ) ;
308 /* Escribimos nuestra palabra al final de nuestro archivo , si daniar
la palabra
309 anterior . */
310 fprintf ( fp , " \ n %s " , parrafo ) ;
311 fillElement (& e , nombre , definicion ) ;
312 // AddEnd (& l [ hash ( nombre ) ] , e ) ;
313 iteraciones = insertAlpha (l , e ) ;
314 printf ( " Se usaron %d iteraciones . \ n " , iteraciones ) ;
315
316 fclose ( fp ) ;
317 }
318
319 /* Funcion que recibe la lista * y un string s , en la funcion solo nos
importa la primera letra
320 del string . Como extra cambia el caracter s [0] a mayuscula , en case de
que sea alfanumerico
321 este caracter , obviamente . */
322 bool
323 existWord ( lista *t , char s []) {
324 int indice = 0;
325

ESCOM-IPN 8
Practica 3: Diccionario con hashing abierto 9

326 /* Obtenemos el indice de s [0]. Se sabe que existe un valor


correspondiente puesto que ya paso
327 la condicion anterior . */
328 indice = hash ( s ) ;
329 nodo * ptr = t [ indice ]. frente ;
330
331 /* Buscamos en nuestra fila i - esima de nuestra tabla , si existe ,
retornamos true */
332 while ( ptr ) {
333 if (! strncmp (s , ptr - > e . nombre , TAMNOM ) )
334 return true ;
335 ptr = ptr - > siguiente ;
336 }
337
338 return false ;
339 }
340
341 /* Borra la palabra p , tanto en la tabla como en el archivo , si existe .
*/
342 void
343 deleteWord ( lista * t ) {
344 char pbuscada [ TAMNOM ];
345 int contador = 0;
346
347 printf ( " \ nIngrese la palabra a borrar : " ) ;
348 strscan ( pbuscada , TAMNOM ) ;
349
350 /* Comprobamos que exista la palabra y , si existe , procedemos
borramos y
351 escribimos el archivo , saltandonos la palabra no deseada . */
352 if ( existWord (t , pbuscada ) ) {
353 FILE * fp = fopen ( nombreArchivo , " wb " ) ;
354 nodo * ptr = NULL ;
355 int i = 0;
356 for ( i = 0; i < TAMHASH ; i ++) {
357 ptr = t [ i ]. frente ;
358 while ( ptr ) {
359 if ( strncmp ( ptr - > e . nombre , pbuscada , TAMNOM ) )
360 fprintf ( fp , " %s : %s \ n " , ptr - > e . nombre , ptr - > e .
definicion ) ;
361 else
362 Remove (& t [ hash ( ptr - > e . nombre ) ] , ptr ) ;
363 ptr = ptr - > siguiente ;
364 if ( i == hash ( pbuscada ) )
365 contador ++;
366 }
367 }
368 fclose ( fp ) ;
369 printf ( " Se usaron %d iteraciones .\ n " , contador ) ;
370 }
371 else
372 puts ( " No se encuentra la palabra ingresada .\ n " ) ;
373 }
374
375 /* Funcion que cambia la definicion de una palabra . */

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

425 char nombre [50];


426
427 printf ( " \ nNombre del archivo (. txt ) : " ) ;
428 strscan ( nombre , 40) ;
429 sprintf ( nombre , " %s . txt " , nombre ) ;
430
431 FILE * fp = fopen ( nombre , " wb " ) ;
432 if (! fp ) {
433 printf ( " \ nEl archivo %s no existe . \ n " , nombre ) ;
434 return ;
435 }
436
437 for ( i = 0; i < TAMHASH ; i ++) {
438 ptr = t [ i ]. frente ;
439 while ( ptr ) {
440 fprintf ( fp , " %s : %s \ n " , ptr - > e . nombre , ptr - > e . definicion ) ;
441 ptr = ptr - > siguiente ;
442 cont ++;
443 }
444 }
445 printf ( " Se exportaron %d palabras a %s . \ n " , cont , nombre ) ;
446
447 fclose ( fp ) ;
448 }
449
450 /* Funcion que exporta una palabra con su definicion a un archivo de
texto .
451 * Problema : Se guarda basura al final del archivo creado . */
452 void
453 exportDefinition ( lista * t ) {
454 char nombre [ TAMNOM ];
455
456 printf ( " \ nNombre de la palabra a exportar : " ) ;
457 strscan ( nombre , TAMNOM ) ;
458
459 if ( existWord (t , nombre ) ) {
460 char n om br eA rc hi vo Nu ev o [50];
461 nodo * ptr = t [ hash ( nombre ) ]. frente ;
462 int cont = 1;
463
464 printf ( " Nombre del archivo (. txt ) : " ) ;
465 strscan ( nombreArchivoNuevo , 40) ;
466 sprintf ( nombreArchivoNuevo , " %s . txt " , no mb re Ar chi vo Nu ev o ) ;
467 FILE * fp = fopen ( nombreArchivoNuevo , " wb " ) ;
468 if (! fp ) {
469 printf ( " \ nEl archivo %s no existe .\ n " , nom br eA rc hi vo Nu evo ) ;
470 return ;
471 }
472 while ( ptr ) {
473 if (! strncmp ( nombre , ptr - > e . nombre , TAMNOM ) ) {
474 fprintf ( fp , " %s : %s " , ptr - > e . nombre , ptr - > e . definicion ) ;
475 puts ( " Palabra exportada exitosamente : D . " ) ;
476 printf ( " Se requirieron %d iteraciones para localizar la
palabra %s . \ n " , cont , nombre ) ;
477 break ;

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

525 nodo * ptr ;


526 int i , j , noHay = true , cont = 1;
527
528 printf ( " \ nFrase : " ) ;
529 strscan ( frase , TAMNOM ) ;
530 for ( i = 0; i < TAMHASH ; i ++) {
531 ptr = t [ i ]. frente ;
532 while ( ptr ) {
533 if ( strstr ( ptr - > e . definicion , frase ) ) {
534 printf ( " %s : %s \ n " , ptr - > e . nombre , ptr - > e . definicion ) ;
535 printf ( " \" % s \" encontrada despues de %d pasos \ n \ n " , frase
, cont ) ;
536 noHay = 0;
537 }
538 ptr = ptr - > siguiente ;
539 cont ++;
540 }
541 }
542 if ( noHay )
543 printf ( " La frase \" %s \" no se encuentra en el diccionario .\ n " ,
frase ) ;
544 }
545
546 /* Pausa el programa hasta que no presionemos enter . */
547 void
548 wait () {
549 printf ( " Presiona ENTER para continuar .\ n " ) ;
550 while ( getchar () != \ n ) ;
551 }
552
553 /* Funcion que muestra las opciones disponibles para el programa . */
554 void
555 menu ( lista * dicc ) {
556 char aux [9];
557 int opcion ;
558
559 do {
560 puts ( " \ nDiccionario Hash \ n " ) ;
561
562 puts ( " 0. - Mostrar estadisticas \ n " ) ;
563
564 puts ( " 1. - Cargar archivo y sus definiciones " ) ;
565 puts ( " 2. - Agregar una palabra y su definicion " ) ;
566 puts ( " 3. - Mostrar la definicion de una palabra " ) ;
567 puts ( " 4. - Modificar una palabra " ) ;
568 puts ( " 5. - Eliminar una palabra " ) ;
569
570 puts ( " \ nOpciones para puntos extra " ) ;
571
572 puts ( " \ nOpciones de busqueda " ) ;
573 puts ( " 6. - Buscar por subcadena " ) ;
574 puts ( " 7. - Buscar palabras por su primer letra " ) ;
575 puts ( " 8. - Buscar por una frase " ) ;
576
577 puts ( " \ nOpciones de exportacion " ) ;

ESCOM-IPN 13
Practica 3: Diccionario con hashing abierto 14

578 puts ( " 9. - Exportar lista a un archivo de texto " ) ;


579 puts ( " 10. - Exportar una palabra con su definicion a un archivo " )
;
580
581 puts ( " \ nOpciones extra " ) ;
582 puts ( " 11. - Imprimir palabras disponibles " ) ;
583
584 puts ( " \ n12 . - Salir " ) ;
585
586 printf ( " \ nOpcion : " ) ;
587 fgets ( aux , 9 , stdin ) ;
588 sscanf ( aux , " %d " , & opcion ) ;
589
590 switch ( opcion ) {
591 case 0: showCollisions ( dicc ) ; break ;
592 case 1: loadFile ( dicc ) ; break ;
593 case 2: addWord ( dicc ) ; break ;
594 case 3: showDefinition ( dicc ) ; break ;
595 case 4: changeDefinition ( dicc ) ; break ;
596 case 5: deleteWord ( dicc ) ; break ;
597 case 6: searchSubstring ( dicc ) ; break ;
598 case 7: searchLetter ( dicc ) ; break ;
599 case 8: searchSentence ( dicc ) ; break ;
600 case 9: exportList ( dicc ) ; break ;
601 case 10: exportDefinition ( dicc ) ; break ;
602 case 11: printAvailable ( dicc ) ; break ;
603 case 12: puts ( " Pongame 10 profe : D \ n " ) ; return ;
604 default : puts ( " Opcion no valida " ) ; break ;
605 }
606 wait () ;
607 } while ( opcion != 12) ;
608 }
609
610 /* Raiz del programa */
611 int
612 main ( int argc , char * argv []) {
613 lista * dicc = ( lista *) calloc ( TAMHASH , sizeof ( lista ) ) ;
614 int i ;
615
616 menu ( dicc ) ;
617 for ( i = 0; i < TAMHASH ; i ++)
618 Destroy (& dicc [ i ]) ;
619
620 return 0;
621 }

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:

Mostremos consecutivamente lo que hace cada opcion:

5.1. Carga de archivos


El programa nos preguntara como se llama el archivo a cargar, una vez de damos el nombre del archivo el
programa lo cargara mostrando una estadstica de cuantas palabras colisionaron en la tabla hash:

5.2. Agregar palabra y definicion


Podremos agregar palabras y definiciones a nuestro diccionario:

ESCOM-IPN 15
Practica 3: Diccionario con hashing abierto 16

5.3. Mostrar palabra y definicion


Buscando la palabra existente en el diccionario, vemos:

5.4. Modificar la definicion de una palabra


Cambiando la palabra anadida en subseccion anterior, vemos:

Corroborando:

5.5. Eliminar palabras


Borrando la palabra anterior:

Corroborando:

5.6. Buscar por subcadenas


Al buscar:

ESCOM-IPN 16
Practica 3: Diccionario con hashing abierto 17

5.7. Mostrar palabras que empiezan con una letra en particular


Vemos:

5.8. Buscando frases


Tenemos:

ESCOM-IPN 17
Practica 3: Diccionario con hashing abierto 18

5.9. Exportando listas


Tenemos:

Corroborando:

5.10. Exportando palabras


Exportando:

ESCOM-IPN 18
Practica 3: Diccionario con hashing abierto 19

Donde la palabra se encuentra en:

Vemos que se exporto adecuadamente:

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

C, los acentos y la n no se llevan...

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

rapidas e implementar el programa en algun lenguaje que soporte acentos y la n.

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

131 if (l - > frente == NULL ) {


132 nuevo = ( posicion ) malloc ( sizeof ( nodo ) ) ;
133 if ( nuevo != NULL ) {
134 nuevo - > e = e ;
135 l - > frente = nuevo ;
136 l - > final = nuevo ;
137 nuevo - > anterior = NULL ;
138 nuevo - > siguiente = NULL ;
139 l - > tamano ++;
140 r = TRUE ;
141 }
142 return r ;
143 } else {
144 return InsertBefore (l , e , l - > frente ) ;
145 }
146 }
147
148 boolean AddEnd ( lista *l , elemento e ) {
149 if (l - > final == NULL ) {
150 return AddBeginning (l , e ) ;
151 } else {
152 return InsertAfter (l , e , l - > final ) ;
153 }
154 }
155
156 boolean Remove ( lista *l , posicion p ) {
157 boolean r = FALSE ;
158 if ( ValidatePosition (l , p ) ) {
159 if (p - > anterior == NULL ) {
160 l - > frente = p - > siguiente ;
161 } else {
162 p - > anterior - > siguiente = p - > siguiente ;
163 }
164 if (p - > siguiente == NULL ) {
165 l - > final = p - > anterior ;
166 } else {
167 p - > siguiente - > anterior = p - > anterior ;
168 }
169 free ( p ) ;
170 l - > tamano - -;
171 r = TRUE ;
172 }
173 return r ;
174 }
175
176 boolean Replace ( lista *l , posicion p , elemento e ) {
177 boolean r = FALSE ;
178 if ( ValidatePosition (l , p ) ) {
179 p->e = e;
180 r = TRUE ;
181 }
182 return r ;
183 }

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

Вам также может понравиться