forked from kish-an/cs50
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dictionary.c
165 lines (140 loc) · 3.37 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
155
156
157
158
159
160
161
162
163
164
165
/* Hash Table Implementation */
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdint.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table (150% amount of words in dictionary)
const unsigned int N = 250000;
// Number of words in dictionary
unsigned int words = 0;
// Hash table
node *table[N];
// Gets a node for a singly linked list
node *getNode(const char *key)
{
node *pNode = malloc(sizeof(node));
if (pNode == NULL)
{
printf("Could not allocate memory for linked list node.\n");
return pNode;
}
strcpy(pNode->word, key);
// Set next to NULL pointer
pNode->next = NULL;
return pNode;
}
// Pass pointer to pointer for head node
void insertNode(node **head, const char *key)
{
// Create node
node *pNode = getNode(key);
// Insert node into linked list
if (*head != NULL)
{
// Make new node point to first item in linked list (a.k.a head)
pNode->next = *head;
}
// Now point head to new node
*head = pNode;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
return false;
}
// Set all next pointers to NULL in hash table
for (int i = 0; i < N; i++)
{
table[i] = NULL;
}
char word[LENGTH + 1];
while (fscanf(dict, "%s", word) != EOF)
{
// Get key from hash function
unsigned int key = hash(word);
// Get pointer address of head node (which is a pointer itself thus node**)
node **head = &table[key];
// Add value to Hash table
insertNode(head, word);
words++;
}
fclose(dict);
return true;
}
// Hashes word to a number
// DJB2 Hashing Algorithim adapted from http://www.cse.yorku.ca/~oz/hash.html
unsigned int hash(const char *word)
{
unsigned int hash = 0;
for (int i = 0, n = strlen(word); i < n; i++)
{
hash = (hash << 2) ^ word[i];
}
return hash % N;
}
// Returns true if word is in dictionary else false
bool check(const char *word)
{
// Convert word to lowercase to get same key from hash function
char copy[strlen(word) + 1];
strcpy(copy, word);
char *p = copy;
for (; *p; ++p)
{
*p = tolower(*p);
}
unsigned int key = hash(copy);
// Temp traversal pointer (points to head)
node *trav = table[key];
// Traverse through linked list (linear search)
while (trav != NULL)
{
if (strcmp(copy, trav->word) == 0)
{
return true;
}
trav = trav->next;
}
return false;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return words;
}
void unloader(node *node)
{
if (node->next != NULL)
{
unloader(node->next);
}
free(node);
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
for (int i = 0; i < N; i++)
{
// Skip if no linked list exists in element
if (table[i] == NULL)
{
continue;
}
unloader(table[i]);
}
return true;
}