-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfrequency.c
More file actions
182 lines (158 loc) · 4.96 KB
/
frequency.c
File metadata and controls
182 lines (158 loc) · 4.96 KB
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "frequency.h"
// Util Functions
//gets a word from stdin and puts it in w (which is a allocated memory in the heap). returns the number of chars read. returns -1 if reached EOF.
int getWord(char **w) {
char *word = (char*)malloc(sizeof(char));
if (word == NULL) return-1; //we shouldn't arrive here because there will be enough memory for normal strings, but if we do we just return -1 to emulate EOF.
char get_char = 0;
int counter = 0;
do {
get_char = getchar();
if (get_char >= 'A' && get_char <= 'Z')
get_char += 32;
if (get_char >= 'a' && get_char <= 'z') {
word = (char *)realloc(word, (++counter+1) * sizeof(char));
if (word == NULL) return-1; //we shouldn't arrive here because there will be enough memory for normal strings, but if we do we just return -1 to emulate EOF.
word[counter-1] = get_char;
}
//This loop will break when reached EOF, space, tab, or line break
} while (get_char != EOF && get_char != '\n' && get_char != '\t' && get_char != ' ');
if (get_char == EOF && counter == 0) {
free(word);
return -1; //return -1 because reached EOF.
}
if (get_char == EOF && counter == 0) {
free(word);
return -1; //return -1 because reached EOF.
}
if (counter == 0) {
free(word);
return 0;
}
word[counter] = '\0';
*w=word;
return counter;
}
// Node Structure implementation
struct _Node {
char _letter;
char *_word;
long unsigned int _count;
struct _Node* _children[NUM_LETTERS];
};
// Node Functions
/*
Allocates memory for a new Node, initialize default values
Then returns the allocated memory address.
*/
Node* new_node(char letter) {
Node *node_p = (Node*)malloc(sizeof(Node));
node_p -> _letter = letter;
node_p -> _word = NULL;
node_p -> _count = 0;
for (int i=0; i<NUM_LETTERS; i++) {
node_p -> _children[i] = NULL;
}
return node_p;
}
void assign_word_to_node(Node **node, const char *word) {
(*node) ->_word = (char*)malloc((strlen(word) * sizeof(char)) + sizeof(char));
strcpy((*node) ->_word, word);
}
void print_node(Node **node) {
if ((*node) -> _count > 0) {
printf("%s", (*node) -> _word);
printf(" %ld\n", (*node) -> _count);
}
for (int i=0; i<NUM_LETTERS; i++) {
if ((*node) ->_children[i] != NULL) {
print_node(&((*node) ->_children[i]));
}
}
}
void print_node_backwards(Node **node) {
if ((*node) -> _count > 0) {
printf("%s", (*node) -> _word);
printf(" %ld\n", (*node) -> _count);
}
for (int i=NUM_LETTERS-1; i>=0; i--) {
if ((*node) ->_children[i] != NULL) {
print_node_backwards(&((*node) ->_children[i]));
}
}
}
//frees a Node from heap memory
void free_node(Node *node) {
if (node == NULL) return;
for (int i=0; i<NUM_LETTERS; i++){
if (node -> _children[i] != NULL)
free_node(node -> _children[i]);
}
if (node -> _word != NULL)
free(node -> _word);
free(node);
}
// Trie Structure implementation
struct _Trie {
int _size;
Node *_head;
};
// Trie Functions
/*
Allocates memory for a new Trie, initialize default values
and assigns a default Node as head
Then returns the allocated memory address
*/
Trie* new_trie() {
Trie *trie_p = (Trie*)malloc(sizeof(Trie));
trie_p -> _size = 0;
trie_p -> _head = new_node(0);
return trie_p;
}
void add_word_to_trie(Trie **trie, char *word) {
Node *current_node = (*trie) -> _head;
char *wordPtr = word;
while(*wordPtr != '\0') {
int i = *wordPtr-'a'; //convert from char to index
//if the current node has a child with that letter
if (current_node -> _children[i] != NULL) {
//traverse to the char in the trie
current_node = current_node -> _children[i];
}
/*
else - the current node does not have a child
with that letter. so we want to make a new node
with that letter and traverse to it.
*/
else {
current_node -> _children[i] = new_node(*wordPtr);
current_node = current_node -> _children[i];
}
wordPtr++;
}
/*
if the current word is the head of the trie that means
the word was empty so we don't want to increase the counter
*/
if (current_node == (*trie) -> _head) return;
if (current_node -> _count == 0)
assign_word_to_node(¤t_node, word);
current_node -> _count++;
}
void print_trie(Trie **trie) {
Node *current_node = (*trie) -> _head;
print_node(¤t_node);
}
void print_trie_backwards(Trie **trie) {
Node *current_node = (*trie) -> _head;
print_node_backwards(¤t_node);
}
//frees a Trie from heap memory
void free_trie(Trie *trie) {
if (trie == NULL) return;
free_node(trie -> _head);
free(trie);
}