You are on page 1of 17

CC3001 Algoritmos y Estructuras de Datos

Tarea 5

Diccionarios

Profesor de Ctedra:
Profesor Auxiliar:
Alumno:
Fecha:

Benjamin Bustos
Boris Romero
Daniel Rojas Vilar
24/11/2015

CC3001

Algoritmos y Estructuras de Datos

CC3001

Algoritmos y Estructuras de Datos

ndice de contenidos
1

Introduccin..................................................................................................................................... 3

Diseo de la solucin....................................................................................................................... 3

2.1

Implementacin con Arreglo Ordenado.....................................................................................3

2.2

Implementacin con Tabla de Hash..........................................................................................4

2.3

Comparacin............................................................................................................................ 4

Implementacin............................................................................................................................... 4
3.1

Implementacin con Arreglo Ordenado.....................................................................................4

3.2

Implementacin con Tabla de Hash..........................................................................................5

3.3

Comparacin............................................................................................................................ 6

Resultados y conclusiones.............................................................................................................. 7

Anexos............................................................................................................................................. 8
5.1

Parte 1...................................................................................................................................... 8

5.1.1

Programa principal..............................................................................................................8

5.1.2

Heap................................................................................................................................... 9

5.2

Parte 2.................................................................................................................................... 11

5.2.1

Programa principal............................................................................................................ 11

5.2.2

Nodo................................................................................................................................. 12

5.2.3

TablaHash......................................................................................................................... 12

5.3

Parte 3.................................................................................................................................... 14

CC3001

Algoritmos y Estructuras de Datos

1 Introduccin
El objetivo de esta tarea es utilizar dos implementaciones distintas del TDA Diccionario para
resolver un problema particular, y hacer un anlisis de eficiencia para ambos mtodos. El problema a
estudiar es el de crear una funcin que, dado un diccionario de largo m guardado en un String D y un
texto en un String T, retorne el nmero de palabras en T que aparecen en D.
El primer mtodo utilizado corresponde a pasar el diccionario a un arreglo ordenado, para
luego revisar palabra por palabra el texto, utilizando bsqueda binaria para verificar si se encuentra en
D (Parte 1).
El segundo mtodo consiste en usar una tabla de hash para ordenar el diccionario, en la que
despus se buscan las palabras de T, usando como funcin de hash la suma numrica de los valores
de los caracteres, mdulo el tamao de D, y manejando las colisiones mediante encadenamiento
(Parte 2).
Finalmente, se desea comparar la eficiencia de ambos mtodos, por lo que se implementa una
funcin COMPARA(D,T) que mide los tiempos de ejecucin de las dos funciones anteriores (que
llamaremos SCORE_ARREGLO(D,T) y SCORE_HASH(D,T) respectivamente), para todos los prefijos de
D (es decir, los m sub-diccionarios Dk que incluyen slo las k primeras palabras de D, para k[1,...,m]).
Los resultados se presentan finalmente tabulados en STDOUT (Parte 3).

2 Diseo de la solucin
2.1 Implementacin con Arreglo Ordenado
Se implementa una clase Heap que maneja Strings y permite obtener siempre el mayor en
trminos lexicogrficos, utilizando el mtodo predefinido compareTo(). SCORE_ARREGLO(D,T) utiliza
un objeto de esta clase para ordenar D, insertando una por una todas las palabras del diccionario en
el Heap, y luego extrayndolas en orden decreciente (sacando siempre el mximo) para construir un
arreglo ordenado en orden creciente.
Luego se recorre el texto T, revisando para cada palabra si sta se encuentra en D. De ser as,
se aumenta en uno un contandor, que finalmente se retorna. La bsqueda en D se realiza con la
estrategia de bsqueda binaria, posible gracias al trabajo de ordenamiento previo: se llama una
funcin buscar(D, palabra) que retorna true si palabra est en el arreglo diccionario, y false si no.
Esta funcin utiliza ndices i y j, al comienzo iguales a 0 y m-1 respectivamente, que marcan el
subconjunto de diccionario sobre el que se realiza la bsqueda. En cada iteracin se toma el punto
4

CC3001

Algoritmos y Estructuras de Datos

medio M entre ambos lmites y se compara el elemento en ese ndice con palabra: si es igual,
significa que est en diccionario, por lo que retorna true; si palabra es menor, contina la bsqueda
actualizando j=M-1; si palabra es mayor, contina actualizando i=M+1. Finalmente, si se llega a un
conjunto vaco sin encontrar la palabra buscada, se retorna false.

2.2 Implementacin con Tabla de Hash


Se implementa una clase TablaHash que maneja objetos tipo Nodo. stos ltimos tienen una
implementacin sencilla que slo considera un String palabra y una referencia a un Nodo siguiente.
La clase TablaHash posee una funcin hash(String palabra) que calcula su valor recorriento el String
palabra y sumando los valores numricos de sus caracteres, para luego calcular el residuo al dividir
por m, que corresponde al tamao de la tabla (y por lo tanto al nmero de palabras en D).
Esta funcin es utilizada por un mtodo insertar(String palabra) que inserta el String palabra
en la TablaHash. sta primero calcula el valor de la funcin de hash para palabra y revisa la casilla
correspondiente en la tabla. Si est vaca, crea un Nodo nuevo que contenga la palabra y lo inserta
en la casilla. De lo contrario, recorre la lista enlazada correspondiente hasta el final y concatena el
nuevo Nodo.
Un ltimo mtodo buscar(String palabra) permite saber si palabra se encuentra en la tabla de
hash. Para eso nuevamente calcula el valor de la funcin de hash para palabra y revisa la casilla
correspondiente en la tabla. Si est vaca retorna false, dado que no se encuentra la palabra. De lo
contrario, recorre la lista correspondiente en forma secuencial, retornando true si encuentra la
palabra, o false si llega hasta el final sin encontrarla.
SCORE_HASH(D,T) crea un objeto de clase TablaHash en el que inserta todas las palabras de

D utilizando el mtodo insertar(String palabra). Luego recorre T, buscando cada palabra en la tabla
de hash usando buscar(String palabra), e incrementando un contador cada vez que una palabra de T
se encuentre en la tabla, el que finalmente se retorna.

2.3 Comparacin
COMPARA(D,T) convierte D a un arreglo sin cambiar su orden, y usa un String subDiccionario

que inicialmente corresponde slo a la primera palabra de D. Luego itera, llamando en cada caso a
SCORE_ARREGLO(subDiccionario, T) y SCORE_HASH(subDiccionario, T) y guardando en variables el
momento en el que se llaman y en que terminan de ejecutarse, utilizando el mtodo
System.nanoTime(), que entrega el tiempo actual del sistema en nanosegundos. Con estos datos
calcula el tiempo de ejecucin de ambos mtodos y los imprime tabulados en la pantalla. Al final de
5

CC3001

Algoritmos y Estructuras de Datos

cada ciclo concatena la siguiente palabra de D al String subDiccionario, terminando cuando llega a la
ltima palabra.

3 Implementacin
3.1 Implementacin con Arreglo Ordenado
public static int SCORE_ARREGLO(String D, String T) {
String[] diccionario=D.split(" "); //arreglo desordenado con palabras del diccionario
//palabras en D se separan por espacios
int m=diccionario.length; //largo de D
//ordenar diccionario con Heapsort
Heap cola=new Heap(m); //crear Heap vaco de tamao igual al largo de D
for (int j=0; j<m; j++) //pasar todas las palabras al Heap
cola.insertar(diccionario[j]);
//ordenar de menor a mayor
for (int j=m-1; j>=0; j--) {
String palabra=cola.extraerMax();
diccionario[j]=palabra;
}
//recorrer T
String[] texto=T.split(" ");
int n=texto.length;
int k=0; //contador de apariciones
for (int j=0; j<n; j++) {
if (buscar(diccionario,texto[j]))
k++; //la palabra buscada est en el diccionario
}
return k;
}
public static boolean buscar(String[] D, String palabra) {
//buscar palabra en diccionario ordenado D usando bsqueda binaria
//retorna true si se encuentra, false si no
int i=0; //lmite inferior
int j=D.length-1; //lmite superior
while (i<=j) { //mientras el conjunto no sea vaco
int m=(i+j)/2;
if (D[m].compareTo(palabra)==0)
return true; //se encontr la palabra
else if (D[m].compareTo(palabra)>0)
j=m-1; //seguir buscando en la primera mitad
else
i=m+1; //seguir buscando en la segunda mitad
}
return false; //no se encontr
}
//La implementacin del Heap es anloga a la de los apuntes del curso, y puede revisarse en Anexos

3.2 Implementacin con Tabla de Hash


public static int SCORE_HASH(String D, String T) {
//arreglo desordenado con palabras del diccionario
String[] diccionario=D.split(" ");

CC3001

Algoritmos y Estructuras de Datos


int m=diccionario.length;
//construir tabla
TablaHash tabla=new TablaHash(m);
for (int j=0; j<m; j++)
tabla.insertar(diccionario[j]);
//recorrer texto
String[] texto=T.split(" ");
int n=texto.length;
int k=0; //contador de apariciones
for (int j=0; j<n; j++) {
if (tabla.buscar(texto[j]))
k++; //se encontr la palabra
}
return k;

Adems se presenta la implementacin de los mtodos de la clase TablaHash:


int hash(String palabra) {
int suma=0;
int l=palabra.length();
for (int j=0; j<l; j++) { //sumar valores de caracteres
suma+=(int)palabra.charAt(j);
}
int h=suma % m; //sacar residuo
return h;
}
void insertar(String palabra) {
int i=hash(palabra); //calcular funcin de hash para a palabra
if (tabla[i]==null) //casilla est vaca
tabla[i]=new Nodo(palabra);
else { //ocupada
Nodo aux=tabla[i];
while (aux.siguiente!=null) { //recorrer hasta el final
aux=aux.siguiente;
}
aux.siguiente=new Nodo(palabra); //insertar al final
}
}
boolean buscar(String palabra) {
int i=hash(palabra); //calcular funcin de hash para a palabra
if (tabla[i]==null) //casilla vaca
return false; //no se encuentra la palabra
else {
Nodo aux=tabla[i];
while (aux!=null) {
if (aux.palabra.equals(palabra))
return true; //se encontro la palabra en la tabla
aux=aux.siguiente;
}
}
//se recorrio toda la lista sin encontrar la palabra
return false;
}

3.3 Comparacin
public static void COMPARA(String D, String T) {
String[] diccionario=D.split(" ");
int m=diccionario.length;
//probar con todos los sub-diccionarios

CC3001

Algoritmos y Estructuras de Datos

String subDiccionario=diccionario[0]; //slo primera palabra


int j=1;
while (true) {
long t0=System.nanoTime();//guardar tiempo antes y despus de ejecutar cada mtodo
Parte1.SCORE_ARREGLO(subDiccionario, T);
long t1=System.nanoTime();
Parte2.SCORE_HASH(subDiccionario, T);
long t2=System.nanoTime();
float tiempo1=(float)(t1-t0)/(1000*1000); //calcular tiempo transcurrido con cada mtodo
float tiempo2=(float)(t2-t1)/(1000*1000); //pasar de nanosegundos a milisegundos
//imprimir resultados en la pantalla
System.out.printf("%d\t%f\t%f\n",j,tiempo1,tiempo2);
if (j==m) //si se probo con todos los sub-diccionarios
break;
subDiccionario+=" "+diccionario[j++]; //agregar la siguiente palabra del diccionario
}

4 Resultados y conclusiones
Anlisis de eficiencia (diccionario D de largo m y texto T de largo n):
a) Implementacin con arreglo ordenado:

Ordenar D usando Heapsort: insertar y extraer cada elemento de D en el Heap una vez
=> O(m logm).

Recorrer T, buscando cada palabra en D usando bsqueda binaria: O(n logm).

TOTAL: O((n+m) logm).

b) Implementacin con tabla de hash: m elementos en una tabla de tamao m => =1.

Insertar los m elementos de D en la tabla: mismo costo que bsqueda infructuosa.


Segn los apuntes del curso: Cn= =1 => insertar todos toma tiempo O(m).

Recorrer T, buscando cada palabra en la tabla de hash: costo aproximadamente lineal


para cada bsqueda => O(n).

TOTAL: O(n+m).
Esto coincide con los resultados entregados por la funcin COMPARA(D,T), en los que se
observa que los tiempos de ejecucin del mtodo implementado con un arreglo ordenado crecen ms
rpidamente con el tamao de D que los del mtodo que utiliza la tabla de hash, alcanzndose
8

CC3001

Algoritmos y Estructuras de Datos

diferencia significativas para diccionarios largos. Sin embargo, para diccionarios con pocas palabras
estas diferencias son casi imperceptibles, e incluso se da el caso en que el primer mtodo resulta
ms rpido que el segundo.

CC3001

Algoritmos y Estructuras de Datos

5 Anexos
5.1 Parte 1
5.1.1 Programa principal
package cc3001.tarea5.rojas_daniel;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Parte1 {
public static boolean buscar(String[] D, String palabra) {
//buscar palabra en diccionario D usando busqueda binaria
//retorna true si se encuentra, false si no

int i=0;
int j=D.length-1;
while (i<=j) { //mientras el conjunto no sea vacio
int m=(i+j)/2;
if (D[m].compareTo(palabra)==0)
//se encontro la palabra
return true;
else if (D[m].compareTo(palabra)>0)
//seguir buscando en la primera mitad
j=m-1;
else
//seguir buscando en la segunda mitad
i=m+1;
}
//no se encontro
return false;

public static int SCORE_ARREGLO(String D, String T) {


//arreglo desordenado con palabras del diccionario
//palabras en D se separan por espacios
String[] diccionario=D.split(" ");
int m=diccionario.length;
//ordenar diccionario con Heapsort
//crear Heap vacio de tamano igual al largo de D
Heap cola=new Heap(m);
//pasar todas las palabras al Heap
for (int j=0; j<m; j++)
cola.insertar(diccionario[j]);

10

CC3001

Algoritmos y Estructuras de Datos


//ordenar de menor a mayor
for (int j=m-1; j>=0; j--) {
String palabra=cola.extraerMax();
diccionario[j]=palabra;
}
//recorrer T
String[] texto=T.split(" ");
int n=texto.length;
int k=0; //contador de apariciones
for (int j=0; j<n; j++) {
if (buscar(diccionario,texto[j]))
//la palabra buscada esta en el diccionario
k++;
}
return k;

}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader (new InputStreamReader(System.in));
String input;
String output = "";
//leemos una linea completa a la vez
while (( input = in.readLine () ) != null) {
String[] entrada = input.split("\\|");
output += SCORE_ARREGLO(entrada[0],entrada[1]) + "\n";
}
System.out.print(output);
System.out.flush();
in.close();
}

5.1.2 Heap
package cc3001.tarea5.rojas_daniel;
public class Heap {
int n; //tamano del Heap
String[] a;
Heap(int m) {
a=new String[m+1]; //la primera posicin no se usa
n=0;
}
boolean estaVacio() {
if (n==0)
return true;
else
return false;
}

11

CC3001

Algoritmos y Estructuras de Datos

void insertar(String nuevo) {


a[++n]=nuevo; //agregar al final
//nuevo "trepa" hasta la posicion que le corresponde
for(int j=n; j>1 && a[j].compareTo(a[j/2])>0; j/=2) {
//intercambiamos con el padre
String t=a[j];
a[j]=a[j/2];
a[j/2]=t;
}
}
String extraerMax() {
String max=a[1]; //La variable max lleva el maximo
a[1]=a[n--]; //Movemos el ultimo a la raiz y achicamos el heap
//"hundir" la raiz hasta la posicion que le corresponde
int j=1;
while(2*j<=n) //mientras tenga algun hijo
{
int k=2*j; //el hijo izquierdo
if(k+1<=n && a[k+1].compareTo(a[k])>0)
k=k+1; //el hijo derecho es el mayor
//k guarda el mayor hijo
if(a[j].compareTo(a[k])>0)
break; //es mayor que ambos hijos
//lo intercambiamos con el mayor hijo
String t=a[j];
a[j]=a[k];
a[k]=t;
j=k;
}
return max;
}

12

CC3001

Algoritmos y Estructuras de Datos

5.2 Parte 2
5.2.1 Programa principal
package cc3001.tarea5.rojas_daniel;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Parte2 {
public static int SCORE_HASH(String D, String T) {
//arreglo desordenado con palabras del diccionario
String[] diccionario=D.split(" ");
int m=diccionario.length;
//construir tabla
TablaHash tabla=new TablaHash(m);
for (int j=0; j<m; j++)
tabla.insertar(diccionario[j]);
//recorrer texto
String[] texto=T.split(" ");
int n=texto.length;
int k=0; //contador de apariciones
for (int j=0; j<n; j++) {
if (tabla.buscar(texto[j]))
k++;
}
return k;
}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader (new InputStreamReader(System.in));
String input;
String output = "";
//leemos una linea completa a la vez
while (( input = in.readLine () ) != null) {
String[] entrada = input.split("\\|");
output += SCORE_HASH(entrada[0],entrada[1]) + "\n";
}
System.out.print(output);
System.out.flush();
in.close();
}

13

CC3001

Algoritmos y Estructuras de Datos

5.2.2 Nodo
package cc3001.tarea5.rojas_daniel;
public class Nodo {
String palabra;
Nodo siguiente;
Nodo(String p) {
palabra=p;
siguiente=null;
}
}

5.2.3 TablaHash
package cc3001.tarea5.rojas_daniel;
public class TablaHash {
int m;
Nodo[] tabla;
TablaHash(int largo) {
tabla=new Nodo[largo];
m=largo;
}
int hash(String palabra) {
int suma=0;
int l=palabra.length();
//sumar valores de caracteres
for (int j=0; j<l; j++) {
suma+=(int)palabra.charAt(j);
}
//sacar residuo
int h=suma % m;
return h;
}

14

CC3001

Algoritmos y Estructuras de Datos

void insertar(String palabra) {


int i=hash(palabra);
if (tabla[i]==null) //casilla esta vacia
tabla[i]=new Nodo(palabra);
else { //ocupada
Nodo aux=tabla[i];
//recorrer hasta el final
while (aux.siguiente!=null) {
aux=aux.siguiente;
}
//insertar al final
aux.siguiente=new Nodo(palabra);
}
}
boolean buscar(String palabra) {
int i=hash(palabra);
if (tabla[i]==null) //casilla vacia
return false; //no se encuentra la palabra
else {
Nodo aux=tabla[i];
while (aux!=null) {
if (aux.palabra.equals(palabra))
//se encontro la palabra en la tabla
return true;
aux=aux.siguiente;
}
}
//se recorrio toda la lista sin encontrar la palabra
return false;
}
}

15

CC3001

Algoritmos y Estructuras de Datos

5.3 Parte 3
package cc3001.tarea5.rojas_daniel;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Parte3 {
public static void COMPARA(String D, String T) {
String[] diccionario=D.split(" ");
int m=diccionario.length;
//probar con todos los sub-diccionarios
String subDiccionario=diccionario[0]; //solo primera palabra
int j=1;
while (true) {
//guardar tiempo antes y despues de ejecutar cada metodo
long t0=System.nanoTime();
Parte1.SCORE_ARREGLO(subDiccionario, T);
long t1=System.nanoTime();
Parte2.SCORE_HASH(subDiccionario, T);
long t2=System.nanoTime();
//calcular tiempo transcurrido con cada metodo
float tiempo1=(float)(t1-t0)/(1000*1000);
float tiempo2=(float)(t2-t1)/(1000*1000);
//imprimir resultados en la pantalla
System.out.printf("%d\t%f\t%f\n",j,tiempo1,tiempo2);
if (j==m) //si se probo con todos los sub-diccionarios
break;
//agregar la siguiente palabra del diccionario
subDiccionario+=" "+diccionario[j++];
}
}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader (new InputStreamReader(System.in));
String input;
//leemos una linea completa a la vez
while (( input = in.readLine () ) != null) {
String[] entrada = input.split("\\|");
COMPARA(entrada[0],entrada[1]);
}

System.out.flush();
in.close();

16

CC3001

Algoritmos y Estructuras de Datos

17

You might also like