-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdictionary.c
154 lines (142 loc) Β· 5.04 KB
/
dictionary.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Implements a dictionary's functionality
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdbool.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Global variable that counts how many words were read
int words_count = 0;
// Choose number of buckets in hash table
const unsigned int N = 26 * 26;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// Get the index in our hash table
int index = hash(word);
// Goes at every node in our linked list, searching for the word
for (node *cursor = table[index]; cursor != NULL; cursor = cursor->next)
{
// If found (ignoring case), return true
if (strcasecmp(cursor->word, word) == 0)
{
return true;
}
}
// If the went on every node and nothing was found, return false
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// This is a two character hash function, i.e., it returns a value according to the first two characters in a word
// Convert the first and the character to a lower case one and then convert it to an int (e.g., an 'a' would be 97)
int first_letter_number = 0, second_letter_number = 0;
first_letter_number = (int) tolower(word[0]);
// Make the letter's number a number within the range of 0 to 25, inclusive (i.e., from 'a' to 'z'), so we return a zero-indexed number
first_letter_number -= 97;
if (strlen(word) > 1)
{
second_letter_number = (int) tolower(word[1]);
second_letter_number -= 97;
}
/*
To understand the bellow formula let's look at an example for the first two characters:
(Beeing x the 'first_letter_number' and y the 'second_letter_number', we have the following)
aa --> 00 x(25 + 1) + y = 0(25 + 1) + 1 = 0 + 0 = 0
ab --> 01 x(25 + 1) + y = 0(25 + 1) + 1 = 0 + 1 = 1
ac --> 02
...
az --> 025 = 25 x(25 + 1) + y = 0(25 + 1) + 25 = 0 + 25 = 25
ba --> 26 x(25 + 1) + y = 1(25 + 1) + 0 = 26 + 0 = 26
bb --> 27
...
bz --> 51 x(25 + 1) + y = 1(25 + 1) + 25 = 26 + 25 = 51
ca --> 52 x(25 + 1) + y = 2(25 + 1) + 0 = 2*26 + 0 = 52
*/
int index_number = first_letter_number * (25 + 1) + second_letter_number;
return index_number;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
unsigned int index;
// Open the dictionary file
FILE *dict = fopen(dictionary, "r");
// Check if we are out of memory. If so, return false
if (dict == NULL)
{
return false;
}
// Create our word as a buffer for every word read in the dictionary
char *word_buffer = malloc(LENGTH);
// Keep reading the dictionary until it gets to it's end (EOF - End Of File)
while (fscanf(dict, "%s", word_buffer) != EOF)
{
// Create a node for each word
node *new_word = malloc(sizeof(node));
// Check if we are out of memory to do so
if (new_word == NULL)
{
return false;
}
// Copy the read word to the word field in our brand new node
strcpy(new_word->word, word_buffer);
// Update the number of read words
words_count ++;
//Hash word
index = hash(new_word->word);
// As described in the walkthrough video, first, point the brand new word to the beginning of the hash table
new_word->next = table[index];
// Then, point the table itself to where 'new_word' is pointing to, so we don't lose the breadcrumbs
// That way, every new word is inserted in the beginning of our linked list
table[index] = new_word;
}
free(word_buffer);
fclose(dict);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// Return the number of words we are counting in the 'load' function
return words_count;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
node *cursor, *tmp;
// Itarates through every node in our hash table
for (int i = 0; i < N; i ++)
{
// If the 'head' of the node is itself NULL, continue the iteration
if (table[i] == NULL)
{
continue;
}
// Else, the cursor points to the heads points and the tmp points to the same thing as cursor does
cursor = table[i];
tmp = cursor;
// Stop the loop if tmp points to a NULL value
while (tmp != NULL)
{
// The cursor goes to its next node
cursor = cursor->next;
// We free tmp (the node where cursor was pointing to)
free(tmp);
// Update the tmp to where cursor currently points to
tmp = cursor;
}
}
return true;
}