Advertisement
Guest User

Untitled

a guest
Nov 18th, 2022
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.99 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdbool.h>
  4. #include <iso646.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7. #include <stdint.h>
  8. #include <time.h>
  9.  
  10. // exit on failure                         
  11. #define FAIL return EXIT_FAILURE
  12. #define MAX_WORD_LENGTH_PRIME 251 // some high word length
  13. #define LAST_ELEMENT "<END_OF_STRING>" // do not use in text
  14. #define EMPTY_ELEMENT "<EMPTY_SYMBOL>" // do not use in text
  15. #define MIN_PRIME_NUMBER 2
  16.  
  17. // remainders for each letter code in hash function computation
  18. size_t remainders[MAX_WORD_LENGTH_PRIME];
  19.  
  20. // hash table entry
  21. typedef struct
  22. {
  23.     char word[MAX_WORD_LENGTH_PRIME]; // 8-bit UTF-8
  24.     size_t count;
  25. } element; // to use declaration without struct keyword over all source
  26.  
  27. typedef struct
  28. {
  29.     size_t index;
  30.     size_t count;
  31. } found_element;
  32.  
  33. typedef struct
  34. {
  35.     bool result;
  36.     bool is_error;
  37.     size_t index;
  38.     size_t new_size;
  39. } insert_status;
  40.  
  41. typedef struct
  42. {
  43.     bool result;
  44.     size_t new_size;
  45. } increase_status;
  46.  
  47. found_element found_data = { 0, 0 };
  48.  
  49. void hashtable_content_print(element * hashtable, size_t size)
  50. {
  51.     if (hashtable != NULL)
  52.     {  
  53.         element element_i;
  54.        
  55.         printf("HASHTABLE PRIME SIZE = %zu\n", size);
  56.        
  57.         for(size_t i = 0; i< size; ++i)
  58.         {
  59.             element_i = hashtable[i];
  60.            
  61.             //if (strcmp(element_i.word, EMPTY_ELEMENT) != 0 and strcmp(element_i.word, LAST_ELEMENT) != 0)
  62.                 printf("%s count is %zu\n", element_i.word, element_i.count);
  63.         }
  64.     }  
  65.     else
  66.         puts("NULL table pointer passed to print.");
  67. }
  68.  
  69.  
  70. void recalculate_remainders()
  71. {
  72.     for (size_t i = 0; i < MAX_WORD_LENGTH_PRIME; ++i)
  73.         remainders[i] = rand() % MAX_WORD_LENGTH_PRIME;
  74. }
  75.  
  76. size_t get_next_prime_number(size_t current_prime_number) // required to get new hashtable size on reconstruction (with rounds == 1 we will got minimal memory loss)
  77. {
  78.     size_t saved = current_prime_number;
  79.     bool is_prime = true;
  80.    
  81.     if (current_prime_number >= MIN_PRIME_NUMBER)
  82.         for(current_prime_number = current_prime_number + 1; current_prime_number < SIZE_MAX; ++current_prime_number)  
  83.             {
  84.                 for(size_t j = 2; j < current_prime_number; ++j)
  85.                     if (current_prime_number % j == 0)
  86.                     {
  87.                         is_prime = false;
  88.                        
  89.                         break; 
  90.                     }
  91.                     else
  92.                         is_prime = true;
  93.    
  94.                 if (is_prime)
  95.                     break;     
  96.             }
  97.    
  98.     return (current_prime_number == saved) ? 0 : current_prime_number;
  99. }
  100.  
  101. // argc, argv checking
  102. bool check_params(int params_count, char *params[])
  103. {
  104.     return (params_count == 2) and (params != NULL) and (params[1] != NULL);
  105. }
  106.  
  107. size_t hash(char value[], size_t offset, size_t hashtable_prime_size) // double hashing probe
  108. {
  109.     size_t result = 0;
  110.    
  111.     if (value != NULL and strlen(value) > 0)
  112.         for (size_t i = 0; value[i] != '\0'; ++i)
  113.             result += remainders[i] * value[i];
  114.     else
  115.         puts("NULL value pointer or empty value passed to hash function.");
  116.     result = (result % hashtable_prime_size + offset * (1 + result % (hashtable_prime_size - 1))) % hashtable_prime_size;
  117.    
  118.     printf("word = %s; offset = %zu; hash = %zu\n", value, offset, result);
  119.    
  120.     return result;
  121. }
  122.  
  123. bool hashtable_element_search(element * hashtable, char key[], size_t hashtable_prime_size)
  124. {  
  125.     if ((hashtable != NULL) and (key != NULL))
  126.     {
  127.         puts("SEARCHING...");
  128.        
  129.         element found;
  130.         size_t offset = 0, index;
  131.        
  132.         do
  133.         {                  
  134.             if (strcmp((found = hashtable[index = hash(key, offset++, hashtable_prime_size)]).word, key) == 0) 
  135.             {  
  136.                 found_data.index = index;
  137.                 found_data.count = found.count;
  138.                
  139.                 printf("FOUND ELEMENT WORD = \"%s\" WITH INDEX = %zu AND COUNT = %zu\n", found.word, found_data.index, found_data.count);
  140.                
  141.                 return true;           
  142.             }
  143.             else
  144.                 printf("PROBE OF ELEMENT WORD = \"%s\" WITH INDEX = %zu AND KEY = \"%s\"\n", found.word, index, key);
  145.         }
  146.         while(offset != hashtable_prime_size);
  147.     }
  148.     else
  149.         puts("NULL table pointer or NULL key pointer passed to search.");
  150.    
  151.     return false;
  152. }
  153.  
  154. increase_status hashtable_size_increase(element * hashtable, size_t rounds, size_t hashtable_prime_size) // rounds is a number of prime hashtable size rises
  155. {  
  156.     increase_status result = { false, 0 };
  157.  
  158.     if (hashtable != NULL and rounds > 0)
  159.         {  
  160.             printf("INCREASING HASHTABLE USING %zu ROUNDS...\n", rounds);
  161.            
  162.             size_t new_size, offset = 0, index = 0, saved_size = 0, old_size = 0;
  163.        
  164.             while(rounds >= 1)
  165.             {
  166.                 saved_size = new_size = get_next_prime_number(hashtable_prime_size);               
  167.                 --rounds;
  168.             }
  169.            
  170.             puts("===HASHTABLE CONTENT BEFORE RESIZEMENT===");
  171.             hashtable_content_print(hashtable, hashtable_prime_size);
  172.             puts("===END===");
  173.             element new_hashtable[new_size];
  174.             memset(&new_hashtable, 0, new_size * sizeof(element));
  175.             old_size = hashtable_prime_size;
  176.             result.new_size = new_size;
  177.             printf("NEW PRIME SIZE = %zu\n", new_size);
  178.             new_hashtable[--new_size].count = 0;
  179.             new_hashtable[new_size].word[0] = '\0';
  180.             strcpy(new_hashtable[new_size].word, LAST_ELEMENT);
  181.                        
  182.             // cleaning array
  183.             while(--new_size > 0)
  184.             {              
  185.                 new_hashtable[new_size].count = 0;
  186.                 new_hashtable[new_size].word[0] = '\0';
  187.                 strcpy(new_hashtable[new_size].word, EMPTY_ELEMENT);
  188.             }
  189.                
  190.             new_hashtable[new_size].count = 0;
  191.             new_hashtable[new_size].word[0] = '\0';
  192.             strcpy(new_hashtable[new_size].word, EMPTY_ELEMENT);
  193.             element found; 
  194.            
  195.             puts("FINDING EMPTY ELEMENT...");
  196.            
  197.             // empty element in new hashtable already exists
  198.             while(strcmp((found = hashtable[new_size++]).word, LAST_ELEMENT) != 0)
  199.                 {  
  200.                     printf("FINDING PLACE FOR WORD = \"%s\" WITH COUNT = %zu\n", found.word, found.count);
  201.                      
  202.                     if (strcmp(found.word, EMPTY_ELEMENT) == 0) // pass
  203.                     {
  204.                         puts("PASSED BECAUSE OF EMPTY");
  205.                        
  206.                         continue;
  207.                     }
  208.                     else
  209.                     {
  210.                         size_t stop_defense = 2 * hashtable_prime_size;
  211.                        
  212.                         while(strcmp(new_hashtable[index = hash(found.word, offset++, hashtable_prime_size)].word, EMPTY_ELEMENT) != 0 and offset < stop_defense);
  213.                        
  214.                         printf("TEMP TABLE WORD = \"%s\" AT INDEX = %zu\n", new_hashtable[index].word, index);
  215.                        
  216.                         new_hashtable[index].count = found.count;
  217.                         new_hashtable[index].word[0] = '\0';   
  218.                         strcpy(new_hashtable[index].word, found.word);
  219.                        
  220.                         printf("POSTED WORD = \"%s\" WITH INDEX = %zu AND COUNT = %zu INTO TEMP TABLE\n", found.word, index, found.count);
  221.                     }
  222.                 }
  223.             puts("===OLD HASHTABLE CONTENT===");
  224.             hashtable_content_print(hashtable, old_size);
  225.             puts("===END==="); 
  226.             void * temp = realloc(hashtable, saved_size * sizeof(element));
  227.            
  228.             if(temp)
  229.             {
  230.                
  231.                 //memset(&temp, 0, sizeof(temp)); WHY ISN'T WORKING?
  232.                 puts("===TEMPORARY HASHTABLE CONTENT===");
  233.                 hashtable_content_print(hashtable, saved_size);
  234.                 puts("===END===");
  235.                
  236.                 if (memcpy(temp, new_hashtable, saved_size * sizeof(element)))
  237.                 {
  238.                     hashtable = temp;
  239.                    
  240.                     puts("COPIED INTO NEW MEMORY LOCATION");
  241.                     puts("===NEW HASHTABLE CONTENT===");
  242.                     hashtable_content_print(hashtable, saved_size);
  243.                     puts("===END===");
  244.                    
  245.                     result.result = true;
  246.                    
  247.                     return result; // success
  248.                 }
  249.             }
  250.             else
  251.             {
  252.                 puts("Memory reallocation fails. Terminated.");
  253.                
  254.                 free(hashtable);               
  255.                 exit(1);
  256.             }
  257.         }
  258.         else
  259.             puts("NULL pointer to hashtable or incorrect rounds count passed to increase function.");
  260.            
  261.     return result;
  262. }
  263.  
  264. insert_status hashtable_element_insert(element * hashtable, element new_element, size_t hashtable_prime_size)
  265. {
  266.     insert_status result = { false, true, 0, hashtable_prime_size };
  267.    
  268.     if (new_element.word != NULL and strcmp(new_element.word, LAST_ELEMENT) != 0 and strcmp(new_element.word, EMPTY_ELEMENT) != 0) //validation
  269.     {
  270.         puts("INSERTING...");
  271.  
  272.         result.is_error = false;
  273.        
  274.         if (hashtable_element_search(hashtable, new_element.word, hashtable_prime_size))
  275.         {  
  276.             result.index = found_data.index;
  277.            
  278.             printf("STEP 1. FOUND AT INDEX = %zu. NOT INSERTED.\n", result.index);
  279.            
  280.             return result; // element already exists       
  281.         }
  282.        
  283.         if (!hashtable_element_search(hashtable, EMPTY_ELEMENT, hashtable_prime_size)) // key not found
  284.         {  
  285.             puts("STEP 2. EMPTY ELEMENT NOT FOUND.");
  286.            
  287.             increase_status output = hashtable_size_increase(hashtable, 1, hashtable_prime_size); // reconstruct hashtable to add empty elements       
  288.            
  289.             if (output.result)
  290.                 result.new_size = output.new_size;
  291.             else
  292.             {
  293.                 puts("Resizement of hashtable failed. Terminated.");
  294.                
  295.                 free(hashtable);
  296.                 exit(1);
  297.             }  
  298.                
  299.             hashtable_element_search(hashtable, EMPTY_ELEMENT, hashtable_prime_size);      
  300.         }
  301.        
  302.         hashtable[found_data.index].count = new_element.count; // rewrite empty element
  303.         hashtable[found_data.index].word[0] = '\0';
  304.         strcpy(hashtable[found_data.index].word, new_element.word);
  305.         result.result = true;      
  306.        
  307.         printf("NEW ELEMENT WORD = \"%s\" FOUND WITH INDEX = %zu\n", new_element.word, found_data.index);
  308.        
  309.         return result;     
  310.     }
  311.     else
  312.         puts("Incorrect new element word.");
  313.    
  314.     return result;
  315. }
  316.  
  317. void hashtable_elements_fill(FILE * textfile, element * hashtable, size_t hashtable_prime_size)
  318. {  
  319.     char word[MAX_WORD_LENGTH_PRIME];
  320.     word[0] = '\0';
  321.     bool is_word = false;
  322.     char input;
  323.    
  324.     while(!feof(textfile) and !ferror(textfile))
  325.     {
  326.         input = getc(textfile);
  327.        
  328.         puts("FILLING...");
  329.        
  330.         if (!isspace(input)) // append to a whole UTF-8 word
  331.         {          
  332.             is_word = true;        
  333.             strncat(word, &input, 1);                                  
  334.         }
  335.         else if (is_word)
  336.         {          
  337.             element new_element = { "", 1 };
  338.             new_element.word[0] = '\0';
  339.             strcpy(new_element.word, word);
  340.            
  341.             puts("===WORD===");
  342.             puts(word);
  343.             puts("===END===");  
  344.            
  345.             insert_status output = hashtable_element_insert(hashtable, new_element, hashtable_prime_size);
  346.            
  347.             printf("OUTPUT INDEX = %zu\n", output.index);
  348.            
  349.             if(output.is_error)
  350.             {
  351.                 puts("OUTPUT.IS_ERROR = TRUE");
  352.                
  353.                 continue; // invalid word
  354.             }
  355.             else if (!output.result)       
  356.             {
  357.                 puts("OUTPUT.RESULT = FALSE. INCREASING COUNT...");            
  358.                 printf("COUNT BEFORE = %zu\n", hashtable[output.index].count);
  359.                
  360.                 ++hashtable[output.index].count; // increasing found word counter  
  361.                
  362.                 printf("COUNT AFTER = %zu\n", hashtable[output.index].count);
  363.             }
  364.            
  365.             word[0] = '\0';
  366.             is_word = false;           
  367.         }
  368.     }  
  369.    
  370.     if (ferror(textfile))  
  371.         perror("File reading error occured."); 
  372. }
  373.  
  374. int main(int params_count, char *params[])
  375. {          
  376.     srand(time(NULL)); // setup randomizer
  377.  
  378.     if (!check_params(params_count, params))
  379.     {
  380.         puts("Params check failed. Program terminated.");
  381.        
  382.         FAIL;
  383.     }
  384.    
  385.     char *filename;
  386.    
  387.     filename = params[1];                          
  388.     FILE *textfile = fopen(filename, "r");
  389.  
  390.     if(textfile == NULL)        
  391.     {  
  392.         puts("Cannot read input file. Program terminated.");
  393.        
  394.         FAIL;
  395.     }
  396.     printf("FILENAME = %s", filename);
  397.     recalculate_remainders();
  398.     printf("HASHTABLE SIZE = %zu", MIN_PRIME_NUMBER * sizeof(element));
  399.     element * hashtable = malloc(MIN_PRIME_NUMBER * sizeof(element));
  400.    
  401.     if (hashtable)
  402.     {
  403.         size_t counter = MIN_PRIME_NUMBER,
  404.                 hashtable_prime_size = MIN_PRIME_NUMBER; // starts from minimal prime size because of empty textfile existence probability (we do not got memory loss in this case);
  405.         hashtable[--counter].count = 0;
  406.         hashtable[counter].word[0] = '\0';
  407.         strcpy(hashtable[counter].word, LAST_ELEMENT);
  408.        
  409.         while(counter > 0)
  410.         {
  411.             hashtable[--counter].count = 0;
  412.             hashtable[counter].word[0] = '\0';
  413.             strcpy(hashtable[counter].word, EMPTY_ELEMENT);
  414.         }
  415.         // there are may be no words in a file at all (end element with NULL string always stored for barrier search)
  416.        
  417.         puts("===HASHTABLE CONTENT===");
  418.         hashtable_content_print(hashtable, hashtable_prime_size);
  419.         puts("===END===");
  420.        
  421.         hashtable_elements_fill(textfile, hashtable, hashtable_prime_size);
  422.        
  423.         puts("===HASHTABLE CONTENT===");
  424.         hashtable_content_print(hashtable, hashtable_prime_size);
  425.         puts("===END===");
  426.        
  427.         free(hashtable);           
  428.     }
  429.     else
  430.         perror("Cannot assign memory location.");
  431.    
  432.     fclose(textfile);      
  433.    
  434.     return EXIT_SUCCESS;
  435. }
  436.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement