Encuentra las k palabras más frecuentes de un archivo

Dado un libro de palabras. Suponga que tiene suficiente memoria principal para acomodar todas las palabras. Diseñe una estructura de datos para encontrar las K palabras máximas que ocurren. La estructura de datos debe ser dinámica para que se puedan agregar nuevas palabras. 
Una solución simple es usar Hashing . Hash todas las palabras una por una en una tabla hash. Si una palabra ya está presente, incremente su conteo. Finalmente, recorra la tabla hash y devuelva las k palabras con recuentos máximos.
Podemos usar Trie y Min Heappara obtener las k palabras más frecuentes de manera eficiente. La idea es usar Trie para buscar palabras existentes agregando nuevas palabras de manera eficiente. Trie también almacena el recuento de ocurrencias de palabras. Se utiliza un Min Heap de tamaño k para realizar un seguimiento de k palabras más frecuentes en cualquier momento (el uso de Min Heap es el mismo que usamos para encontrar k elementos más grandes en esta publicación). 
Trie y Min Heap están vinculados entre sí almacenando un campo adicional en Trie ‘indexMinHeap’ y un puntero ‘trNode’ en Min Heap. El valor de ‘indexMinHeap’ se mantiene como -1 para las palabras que actualmente no están en Min Heap (o actualmente no se encuentran entre las k palabras más frecuentes). Para las palabras que están presentes en Min Heap, ‘indexMinHeap’ contiene el índice de la palabra en Min Heap. El puntero ‘trNode’ en Min Heap apunta al Node hoja correspondiente a la palabra en Trie.
A continuación se muestra el proceso completo para imprimir las k palabras más frecuentes de un archivo.
Lea todas las palabras una por una. Para cada palabra, insértela en Trie. Aumenta el contador de la palabra, si ya existe. Ahora, también necesitamos insertar esta palabra en el montón mínimo. Para la inserción en el montón mínimo, surgen 3 casos:
1.La palabra ya está presente. Simplemente aumentamos el valor de frecuencia correspondiente en el montón mínimo y llamamos a minHeapify() para el índice obtenido por el campo «indexMinHeap» en Trie. Cuando se intercambian los Nodes del montón mínimo, cambiamos el índice minHeap correspondiente en el Trie. Recuerde que cada Node del montón mínimo también tiene un puntero al Node de hoja Trie.
2. El minHeap no está lleno. Insertaremos la nueva palabra en el montón mínimo y actualizaremos el Node raíz en el Node del montón mínimo y el índice del montón mínimo en el Node hoja de Trie. Ahora, llama a buildMinHeap().
3. El montón mínimo está lleno. Surgen dos subcasos. 
…. 3.1 La frecuencia de la nueva palabra insertada es menor que la frecuencia de la palabra almacenada en el encabezado del montón mínimo. Hacer nada.
…. 3.2La frecuencia de la nueva palabra insertada es mayor que la frecuencia de la palabra almacenada en el encabezado del montón mínimo. Reemplace y actualice los campos. Asegúrese de actualizar el índice de montón mínimo correspondiente de la «palabra que se reemplazará» en Trie con -1, ya que la palabra ya no está en el montón mínimo.
4. Finalmente, Min Heap tendrá las k palabras más frecuentes de todas las palabras presentes en el archivo dado. Entonces solo necesitamos imprimir todas las palabras presentes en Min Heap. 
 

CPP

// A program to find k most frequent words in a file
#include <stdio.h>
#include <string.h>
#include <ctype.h>
 
# define MAX_CHARS 26
# define MAX_WORD_SIZE 30
 
// A Trie node
struct TrieNode
{
    bool isEnd; // indicates end of word
    unsigned frequency;  // the number of occurrences of a word
    int indexMinHeap; // the index of the word in minHeap
    TrieNode* child[MAX_CHARS]; // represents 26 slots each for 'a' to 'z'.
};
 
// A Min Heap node
struct MinHeapNode
{
    TrieNode* root; // indicates the leaf node of TRIE
    unsigned frequency; //  number of occurrences
    char* word; // the actual word stored
};
 
// A Min Heap
struct MinHeap
{
    unsigned capacity; // the total size a min heap
    int count; // indicates the number of slots filled.
    MinHeapNode* array; //  represents the collection of minHeapNodes
};
 
// A utility function to create a new Trie node
TrieNode* newTrieNode()
{
    // Allocate memory for Trie Node
    TrieNode* trieNode = new TrieNode;
 
    // Initialize values for new node
    trieNode->isEnd = 0;
    trieNode->frequency = 0;
    trieNode->indexMinHeap = -1;
    for( int i = 0; i < MAX_CHARS; ++i )
        trieNode->child[i] = NULL;
 
    return trieNode;
}
 
// A utility function to create a Min Heap of given capacity
MinHeap* createMinHeap( int capacity )
{
    MinHeap* minHeap = new MinHeap;
 
    minHeap->capacity = capacity;
    minHeap->count  = 0;
 
    // Allocate memory for array of min heap nodes
    minHeap->array = new MinHeapNode [ minHeap->capacity ];
 
    return minHeap;
}
 
// A utility function to swap two min heap nodes. This function
// is needed in minHeapify
void swapMinHeapNodes ( MinHeapNode* a, MinHeapNode* b )
{
    MinHeapNode temp = *a;
    *a = *b;
    *b = temp;
}
 
// This is the standard minHeapify function. It does one thing extra.
// It updates the minHapIndex in Trie when two nodes are swapped in
// in min heap
void minHeapify( MinHeap* minHeap, int idx )
{
    int left, right, smallest;
 
    left = 2 * idx + 1;
    right = 2 * idx + 2;
    smallest = idx;
    if ( left < minHeap->count &&
         minHeap->array[ left ]. frequency <
         minHeap->array[ smallest ]. frequency
       )
        smallest = left;
 
    if ( right < minHeap->count &&
         minHeap->array[ right ]. frequency <
         minHeap->array[ smallest ]. frequency
       )
        smallest = right;
 
    if( smallest != idx )
    {
        // Update the corresponding index in Trie node.
        minHeap->array[ smallest ]. root->indexMinHeap = idx;
        minHeap->array[ idx ]. root->indexMinHeap = smallest;
 
        // Swap nodes in min heap
        swapMinHeapNodes (&minHeap->array[ smallest ], &minHeap->array[ idx ]);
 
        minHeapify( minHeap, smallest );
    }
}
 
// A standard function to build a heap
void buildMinHeap( MinHeap* minHeap )
{
    int n, i;
    n = minHeap->count - 1;
 
    for( i = ( n - 1 ) / 2; i >= 0; --i )
        minHeapify( minHeap, i );
}
 
// Inserts a word to heap, the function handles the 3 cases explained above
void insertInMinHeap( MinHeap* minHeap, TrieNode** root, const char* word )
{
    // Case 1: the word is already present in minHeap
    if( (*root)->indexMinHeap != -1 )
    {
        ++( minHeap->array[ (*root)->indexMinHeap ]. frequency );
 
        // percolate down
        minHeapify( minHeap, (*root)->indexMinHeap );
    }
 
    // Case 2: Word is not present and heap is not full
    else if( minHeap->count < minHeap->capacity )
    {
        int count = minHeap->count;
        minHeap->array[ count ]. frequency = (*root)->frequency;
        minHeap->array[ count ]. word = new char [strlen( word ) + 1];
        strcpy( minHeap->array[ count ]. word, word );
 
        minHeap->array[ count ]. root = *root;
        (*root)->indexMinHeap = minHeap->count;
 
        ++( minHeap->count );
        buildMinHeap( minHeap );
    }
 
    // Case 3: Word is not present and heap is full. And frequency of word
    // is more than root. The root is the least frequent word in heap,
    // replace root with new word
    else if ( (*root)->frequency > minHeap->array[0]. frequency )
    {
 
        minHeap->array[ 0 ]. root->indexMinHeap = -1;
        minHeap->array[ 0 ]. root = *root;
        minHeap->array[ 0 ]. root->indexMinHeap = 0;
        minHeap->array[ 0 ]. frequency = (*root)->frequency;
 
        // delete previously allocated memory and
        delete [] minHeap->array[ 0 ]. word;
        minHeap->array[ 0 ]. word = new char [strlen( word ) + 1];
        strcpy( minHeap->array[ 0 ]. word, word );
 
        minHeapify ( minHeap, 0 );
    }
}
 
// Inserts a new word to both Trie and Heap
void insertUtil ( TrieNode** root, MinHeap* minHeap,
                        const char* word, const char* dupWord )
{
    // Base Case
    if ( *root == NULL )
        *root = newTrieNode();
 
    //  There are still more characters in word
    if ( *word != '\0' )
        insertUtil ( &((*root)->child[ tolower( *word ) - 97 ]),
                         minHeap, word + 1, dupWord );
    else // The complete word is processed
    {
        // word is already present, increase the frequency
        if ( (*root)->isEnd )
            ++( (*root)->frequency );
        else
        {
            (*root)->isEnd = 1;
            (*root)->frequency = 1;
        }
 
        // Insert in min heap also
        insertInMinHeap( minHeap, root, dupWord );
    }
}
 
 
// add a word to Trie & min heap.  A wrapper over the insertUtil
void insertTrieAndHeap(const char *word, TrieNode** root, MinHeap* minHeap)
{
    insertUtil( root, minHeap, word, word );
}
 
// A utility function to show results, The min heap
// contains k most frequent words so far, at any time
void displayMinHeap( MinHeap* minHeap )
{
    int i;
 
    // print top K word with frequency
    for( i = 0; i < minHeap->count; ++i )
    {
        printf( "%s : %d\n", minHeap->array[i].word,
                            minHeap->array[i].frequency );
    }
}
 
// The main function that takes a file as input, add words to heap
// and Trie, finally shows result from heap
void printKMostFreq( FILE* fp, int k )
{
    // Create a Min Heap of Size k
    MinHeap* minHeap = createMinHeap( k );
    
    // Create an empty Trie
    TrieNode* root = NULL;
 
    // A buffer to store one word at a time
    char buffer[MAX_WORD_SIZE];
 
    // Read words one by one from file.  Insert the word in Trie and Min Heap
    while( fscanf( fp, "%s", buffer ) != EOF )
        insertTrieAndHeap(buffer, &root, minHeap);
 
    // The Min Heap will have the k most frequent words, so print Min Heap nodes
    displayMinHeap( minHeap );
}
 
// Driver program to test above functions
int main()
{
    int k = 5;
    FILE *fp = fopen ("file.txt", "r");
    if (fp == NULL)
        printf ("File doesn't exist ");
    else
        printKMostFreq (fp, k);
    return 0;
}

Producción: 

your : 3
well : 3
and : 4
to : 4
Geeks : 6

El resultado anterior es para un archivo con el siguiente contenido. 

Welcome to the world of Geeks 
This portal has been created to provide well written well thought and well explained 
solutions for selected questions If you like Geeks for Geeks and would like to contribute 
here is your chance You can write article and mail your article to contribute at 
geeksforgeeks org See your article appearing on the Geeks for Geeks main page and help 
thousands of other Geeks

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *