Ottimizzazione di una funzione che sembra essere eseguita molto lentamente quando ci sono molti nomi utente nel file

0

Ho scritto un piccolo programma, circa 10.500 linee e tutto funziona perfettamente.

Si tratta di un gioco matematico, che ha il processo di accesso e registrazione e tutti i dati sono memorizzati sul computer dell'utente in più file di testo. Ha supporto per più utenti.

Ho scritto una funzione che consente all'utente di cercare un altro utente nel database e, se il nome utente non viene trovato, il programma tenta di trovare il nome utente nel file che assomiglia a quello immesso e fornisce suggerimenti.

Tuttavia, questa funzione sembra essere eseguita molto lentamente quando ci sono molti nomi utente nel file.

Come posso ottimizzarlo?

// Function to generate suggestions
void Suggestions (char passed[])
{
    /**
        In the case that the administrator makes an error while searching for a user,
        tghe program attempts to determine the username in the database which closest
        matches the username that wa entered
    */

    // Vaiables
    char sname[MAX], record[MAX];
    int w, x, y, z;
    char abs = 'N', f = 'N';
    int len = 0, temp = 0;

    // Sets them all to 0
    w = x = y = z = 0

    taken user[MAX];

    // Attempts to open file
    ptrRead = fopen("UserNames.smq", "r");

    if(ptrRead == NULL)
    {
        printf("\n\nThe file was not found ...\n\n\n");
    }
    else
    {
        // Copies the incorrect username passed to the function
        strcpy(sname, passed);

        // Encrypts the passed name 
        for(x = 0; x < strlen(passed); x++)
        {
            sname[x] += key;
        }

        // Sets x to 0
        x = 0;

        // Reads all of file with the usernames 
        while(!feof(ptrRead))
        {
            fgets(record, MAX - 1, ptrRead);

            // Compares the strings
            if(strcmp(record, sname) == 0)
            {
                // Sets found to yes
                f = 'Y';

                // Breaks our of loop
                break;
            }
            // End if
        }
        // End while


        if(f == 'N')
        {
            // Rewinds the file pointer
            rewind(ptrRead);

            // Reads the data of the file and calculate various contents
            while(!feof(ptrRead))
            {
                // Sets temp to 0
                temp = 0;

                // Gets the username
                fgets(record, MAX - 1, ptrRead);

                // Copes the information
                strcpy(user[x].userName, record);

                // Calculate the length
                len = strlen(user[x].userName) - strlen(sname);

                // Determines if the name is valid for testing
                if(len == -2 || len == -1 || len == 0 || len == 1 || len == 2)
                {
                    /**
                        This if statement limits the number of work trhe program does by eliminating
                        the usernames with a difference in string length grater than 2 or less than - 2
                    */

                    // Counts the number of letters common in a sequence
                    for(w = 0; w < strlen(user[x].userName); w++)
                    {
                        /**
                            It does not matter which string length the for-loops runs for because
                            when the average is calculated, the same result appears both ways
                        */

                        // Compares both letters
                        if(user[x].userName[w] == sname[w])
                        {
                            /**
                                If both letters at the current index are the same, then temp will be
                                increased by the value 1. If not, then temo will not increase. This gets
                                the number of letter the two names have in common in a sequence.
                            */

                            temp++;
                        }
                        // End if
                    }
                    /* End for */

                    // Calculates the average letters in common
                    user[x].lettersInCommom = (float) temp / ((strlen(user[x].userName) + strlen(sname)) / 2) * 100.0;

                    // Sets temp to 0
                    temp = 0;

                    // Calculates the number of letters the have in common
                    for(y = 0; y < strlen(sname); y++)
                    {
                        /*
                            Runs the loop until the string length of the incorrect username - Just for fun
                        */
                        for(w = 0; w < strlen(user[x].userName) ; w++)
                        {
                            /**
                                This for loop runs for the entire string lenght of the username in the file
                            */

                            // Compares the letters
                            if(user[x].userName[w] == sname[y])
                            {
                                /**
                                    Compares the characters at the current index. If they are the same,
                                    then temp increase by 1. The purpose of these nested loops is to
                                    check the number of letters the two name have in common in general,
                                    and not just in a sequence.
                                */
                                temp++;  // Increments temp
                            }
                        }
                    }

                    // Calculates the average letters in common in general
                    if(strlen(user[x].userName) > strlen(sname))
                    {
                        user[x].lettersInGeneral = (float) temp / (float) strlen(sname)  * 100.0;
                    }
                    else
                    {
                        user[x].lettersInGeneral = (float) temp / (float) strlen(user[x].userName)  * 100.0;
                    }

                    // Sets temp to 0
                    temp = 0;

                    // Checks if both names begins with the same letter
                    if(sname[0] == user[x].userName[0])
                    {
                        user[x].beginsWithFirst = 100.0;   // Assign 100
                    }
                    else
                    {
                        user[x].beginsWithFirst = 0.0;      // Assign 0
                    }

                    // Checks if the names ends with the same letter
                    if(sname[strlen(sname) - 1] == user[x].userName[strlen(user[x].userName) -1])
                    {
                        user[x].endsWithLast = 100.0;       // Assign 100
                    }
                    else
                    {
                        user[x].endsWithLast = 0.0;         // Assign 0
                    }
                }

                /**
                    Calculates the rank. The rank is an overall percentage that represents the average similarity
                    that the username in the file has with the incorrect username entered. Similar usernames
                    normally have a rank of over 70%
                */

                user[x].rank = (user[x].lettersInCommom + user[x].lettersInGeneral + user[x].beginsWithFirst + user[x].endsWithLast) / 4.0;

                // Increments x
                x++;
            }

            // Closes the file
            fclose(ptrRead);

            // Sets temp to 0
            temp = 0;

            for(z = 0; z < x; z++)
            {
                /*
                    Runs  until the number of usernames in the file is reached
                */
                if(user[z].rank > 70.00 && user[z].rank < 200.00)
                {
                    // Increments temp by 1 if conditon is met
                    temp++;
                }
            }

            if(temp > 0)
            {
                temp = 0;  // Resets temp

                /*
                    This is done to determine whether or not to print the contents in this if statement.
                    If no suggestion were found then printing "Did you mean" would be a waste of processing.
                */

                // Clears the screen
                system("cls");

                printf("\n\t\t\t\tOoops!");
                printf("\n\t\t\t*********************\n\n");
                printf("\nLooks like you made an error in your search. ");

                printf("Did you mean: \n\n");

                // For all the usernames
                for(z = 0; z < x; z++)
                {
                    // Checks the rank
                    if(user[z].rank > 70.00 && user[z].rank < 200.00)
                    {
                        /* Increments temp */
                        temp++;

                        for(w = 0; w < strlen(user[z].userName); w++)
                        {
                            // Decrypts the name
                            user[z].userName[w] -= key);
                        }

                        if(key > 2)
                        {
                            /**
                                This removes a weird looking character that always shows at the end
                                of the username when the key is greater than 2.
                            */

                            user[z].userName[strlen(user[z].userName) - 1] = '
// Function to generate suggestions
void Suggestions (char passed[])
{
    /**
        In the case that the administrator makes an error while searching for a user,
        tghe program attempts to determine the username in the database which closest
        matches the username that wa entered
    */

    // Vaiables
    char sname[MAX], record[MAX];
    int w, x, y, z;
    char abs = 'N', f = 'N';
    int len = 0, temp = 0;

    // Sets them all to 0
    w = x = y = z = 0

    taken user[MAX];

    // Attempts to open file
    ptrRead = fopen("UserNames.smq", "r");

    if(ptrRead == NULL)
    {
        printf("\n\nThe file was not found ...\n\n\n");
    }
    else
    {
        // Copies the incorrect username passed to the function
        strcpy(sname, passed);

        // Encrypts the passed name 
        for(x = 0; x < strlen(passed); x++)
        {
            sname[x] += key;
        }

        // Sets x to 0
        x = 0;

        // Reads all of file with the usernames 
        while(!feof(ptrRead))
        {
            fgets(record, MAX - 1, ptrRead);

            // Compares the strings
            if(strcmp(record, sname) == 0)
            {
                // Sets found to yes
                f = 'Y';

                // Breaks our of loop
                break;
            }
            // End if
        }
        // End while


        if(f == 'N')
        {
            // Rewinds the file pointer
            rewind(ptrRead);

            // Reads the data of the file and calculate various contents
            while(!feof(ptrRead))
            {
                // Sets temp to 0
                temp = 0;

                // Gets the username
                fgets(record, MAX - 1, ptrRead);

                // Copes the information
                strcpy(user[x].userName, record);

                // Calculate the length
                len = strlen(user[x].userName) - strlen(sname);

                // Determines if the name is valid for testing
                if(len == -2 || len == -1 || len == 0 || len == 1 || len == 2)
                {
                    /**
                        This if statement limits the number of work trhe program does by eliminating
                        the usernames with a difference in string length grater than 2 or less than - 2
                    */

                    // Counts the number of letters common in a sequence
                    for(w = 0; w < strlen(user[x].userName); w++)
                    {
                        /**
                            It does not matter which string length the for-loops runs for because
                            when the average is calculated, the same result appears both ways
                        */

                        // Compares both letters
                        if(user[x].userName[w] == sname[w])
                        {
                            /**
                                If both letters at the current index are the same, then temp will be
                                increased by the value 1. If not, then temo will not increase. This gets
                                the number of letter the two names have in common in a sequence.
                            */

                            temp++;
                        }
                        // End if
                    }
                    /* End for */

                    // Calculates the average letters in common
                    user[x].lettersInCommom = (float) temp / ((strlen(user[x].userName) + strlen(sname)) / 2) * 100.0;

                    // Sets temp to 0
                    temp = 0;

                    // Calculates the number of letters the have in common
                    for(y = 0; y < strlen(sname); y++)
                    {
                        /*
                            Runs the loop until the string length of the incorrect username - Just for fun
                        */
                        for(w = 0; w < strlen(user[x].userName) ; w++)
                        {
                            /**
                                This for loop runs for the entire string lenght of the username in the file
                            */

                            // Compares the letters
                            if(user[x].userName[w] == sname[y])
                            {
                                /**
                                    Compares the characters at the current index. If they are the same,
                                    then temp increase by 1. The purpose of these nested loops is to
                                    check the number of letters the two name have in common in general,
                                    and not just in a sequence.
                                */
                                temp++;  // Increments temp
                            }
                        }
                    }

                    // Calculates the average letters in common in general
                    if(strlen(user[x].userName) > strlen(sname))
                    {
                        user[x].lettersInGeneral = (float) temp / (float) strlen(sname)  * 100.0;
                    }
                    else
                    {
                        user[x].lettersInGeneral = (float) temp / (float) strlen(user[x].userName)  * 100.0;
                    }

                    // Sets temp to 0
                    temp = 0;

                    // Checks if both names begins with the same letter
                    if(sname[0] == user[x].userName[0])
                    {
                        user[x].beginsWithFirst = 100.0;   // Assign 100
                    }
                    else
                    {
                        user[x].beginsWithFirst = 0.0;      // Assign 0
                    }

                    // Checks if the names ends with the same letter
                    if(sname[strlen(sname) - 1] == user[x].userName[strlen(user[x].userName) -1])
                    {
                        user[x].endsWithLast = 100.0;       // Assign 100
                    }
                    else
                    {
                        user[x].endsWithLast = 0.0;         // Assign 0
                    }
                }

                /**
                    Calculates the rank. The rank is an overall percentage that represents the average similarity
                    that the username in the file has with the incorrect username entered. Similar usernames
                    normally have a rank of over 70%
                */

                user[x].rank = (user[x].lettersInCommom + user[x].lettersInGeneral + user[x].beginsWithFirst + user[x].endsWithLast) / 4.0;

                // Increments x
                x++;
            }

            // Closes the file
            fclose(ptrRead);

            // Sets temp to 0
            temp = 0;

            for(z = 0; z < x; z++)
            {
                /*
                    Runs  until the number of usernames in the file is reached
                */
                if(user[z].rank > 70.00 && user[z].rank < 200.00)
                {
                    // Increments temp by 1 if conditon is met
                    temp++;
                }
            }

            if(temp > 0)
            {
                temp = 0;  // Resets temp

                /*
                    This is done to determine whether or not to print the contents in this if statement.
                    If no suggestion were found then printing "Did you mean" would be a waste of processing.
                */

                // Clears the screen
                system("cls");

                printf("\n\t\t\t\tOoops!");
                printf("\n\t\t\t*********************\n\n");
                printf("\nLooks like you made an error in your search. ");

                printf("Did you mean: \n\n");

                // For all the usernames
                for(z = 0; z < x; z++)
                {
                    // Checks the rank
                    if(user[z].rank > 70.00 && user[z].rank < 200.00)
                    {
                        /* Increments temp */
                        temp++;

                        for(w = 0; w < strlen(user[z].userName); w++)
                        {
                            // Decrypts the name
                            user[z].userName[w] -= key);
                        }

                        if(key > 2)
                        {
                            /**
                                This removes a weird looking character that always shows at the end
                                of the username when the key is greater than 2.
                            */

                            user[z].userName[strlen(user[z].userName) - 1] = '%pre%';
                        }

                        // Prints decrypted user name as is
                        printf("\n(%d)\t%s", temp, user[z].userName);
                    }
                }

                // Allows the admin to search again
                ViewSingleUser();
            }
            else
            {
                // Prints error
                printf("\n\nWe were unable to detect any possible matches ...");
            }
        }
    }
}
// Function ends here
'; } // Prints decrypted user name as is printf("\n(%d)\t%s", temp, user[z].userName); } } // Allows the admin to search again ViewSingleUser(); } else { // Prints error printf("\n\nWe were unable to detect any possible matches ..."); } } } } // Function ends here
    
posta raheemmcdonald 26.08.2016 - 05:08
fonte

1 risposta

1

suggerimenti generali

Considererei (sperando che tu stia usando Linux e GCC , che è un eccellente ambiente di sviluppo):

sul tuo codice

(non sappiamo come viene chiamata la tua funzione Suggestion e cosa dovrebbe realmente fare)

Tieni presente che i loop nidificati sembrano sospetti.

Utilizza perror o strerror(errno) in caso di fallimento di fopen quindi codice:

ptrRead = fopen("UserNames.smq", "r");

if(ptrRead == NULL) {
    perror("UserNames.smq");
    return; // or perhaps exit(EXIT_FAILURE);
}

La variabile f deve essere un bool f = false; poiché è un flag booleano.

Non modifichi sname dopo l'inizializzazione da passed , quindi perché non dichiari void Suggestions (const char* passed) e usi passed ovunque invece di sname ? Non è necessario copiare la stringa passed non modificata in sname (che non si modifica nemmeno) ...

Non gestisci o evita buffer overflow . In particolare, se sname è una stringa molto lunga (più ampia della tua MAX ...) hai il temuto comportamento non definito

A proposito, loop come for(y = 0; y < strlen(sname); y++) sono davvero inefficienti. Stai calcolando la lunghezza della stringa ad ogni iterazione; memorizzalo meglio e calcola la lunghezza della stringa una volta:

size_t snlen = strlen(sname);
for (y=0; y<snlen; y++)

(alcuni compilatori potrebbero essere in grado di fare una tale ottimizzazione, ma non dovresti prenderlo come previsto)

Inoltre, utilizza più puntatori sistematici su char , ad es. sostituire

for(w = 0; w < strlen(user[z].userName); w++)
                {
                    // Decrypts the name
                    user[z].userName[w] -= key);
                }

con

for (char*pc = user[z].userName; *pc; pc++)
  *pc -= key;

Tale ciclo è più breve per scrivere e utilizzare i puntatori di caratteri, non calcolare il strlen ad ogni iterazione e utilizzare il fatto che le stringhe sono terminate da un byte zero.

Naturalmente, tieni presente che la crittografia è davvero scarsa; se ne hai bisogno, usa una libreria o una funzione di crittografia esistente (vedi crypt (3) e TLS ...)

    
risposta data 26.08.2016 - 06:30
fonte

Leggi altre domande sui tag