-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAnagramTree.java
More file actions
224 lines (205 loc) · 6.24 KB
/
AnagramTree.java
File metadata and controls
224 lines (205 loc) · 6.24 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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
//
// WORDS. An iterator that reads lower case words from a text file.
//
// James Moen
// 12 Apr 23
//
import java.io.FileReader; // Read Unicode chars from a file.
import java.io.IOException; // In case there's IO trouble.
// WORDS. Iterator. Read words, represented as STRINGs, from a text file. Each
// word is the longest possible contiguous series of alphabetic ASCII CHARs.
class Words
{
private int ch; // Last CHAR from READER, as an INT.
private FileReader reader; // Read CHARs from here.
private StringBuilder word; // Last word read from READER.
// Constructor. Initialize an instance of WORDS, so it reads words from a file
// whose pathname is PATH. Throw an exception if we can't open PATH.
public Words(String path)
{
try
{
reader = new FileReader(path);
ch = reader.read();
}
catch (IOException ignore)
{
throw new IllegalArgumentException("Cannot open '" + path + "'.");
}
}
// HAS NEXT. Try to read a WORD from READER, converting it to lower case as we
// go. Test if we were successful.
public boolean hasNext()
{
word = new StringBuilder();
while (ch > 0 && ! isAlphabetic((char) ch))
{
read();
}
while (ch > 0 && isAlphabetic((char) ch))
{
word.append(toLower((char) ch));
read();
}
return word.length() > 0;
}
// IS ALPHABETIC. Test if CH is an ASCII letter.
private boolean isAlphabetic(char ch)
{
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z';
}
// NEXT. If HAS NEXT is true, then return a WORD read from READER as a STRING.
// Otherwise, return an undefined STRING.
public String next()
{
return word.toString();
}
// READ. Read the next CHAR from READER. Set CH to the CHAR, represented as an
// INT. If there are no more CHARs to be read from READER, then set CH to -1.
private void read()
{
try
{
ch = reader.read();
}
catch (IOException ignore)
{
ch = -1;
}
}
// TO LOWER. Return the lower case ASCII letter which corresponds to the ASCII
// letter CH.
private char toLower(char ch)
{
if ('a' <= ch && ch <= 'z')
{
return ch;
}
else
{
return (char) (ch - 'A' + 'a');
}
}
// MAIN. For testing. Open a text file whose pathname is the 0th argument from
// the command line. Read words from the file, and print them one per line.
public static void main(String [] args)
{
Words words = new Words("");
while (words.hasNext())
{
System.out.println("'" + words.next() + "'");
}
}
}
class AnagramTree {
private class TreeNode {
private byte[] summary;
private WordNode words;
private TreeNode left;
private TreeNode right;
private TreeNode(byte[] summary, WordNode words) {
this.summary = summary;
this.words = words;
}
}
private class WordNode {
private String word;
private WordNode next;
private WordNode(String word, WordNode next) {
this.word = word;
this.next = next;
}
}
private TreeNode treeHead;
public AnagramTree() {
treeHead = new TreeNode(new byte[26], null); //treeHead.right is the first Node in the tree
}
public void add(String word) {
byte[] currentSummary = stringToSummary(word);
TreeNode subtree = treeHead;
while (subtree != null) {
int test = compareSummaries(currentSummary, subtree.summary);
if (test < 0) {
if (subtree.left == null) {
subtree.left = new TreeNode(currentSummary, new WordNode(word, null));
return;
}
else {
subtree = subtree.left;
}
}
else if (test > 0) {
if (subtree.right == null) {
subtree.right = new TreeNode(currentSummary, new WordNode(word, null));
return;
}
else {
subtree = subtree.right;
}
}
else {
if (isIn(word, subtree.words)) {
return;
}
else {
subtree.words = new WordNode(word, subtree.words);
return;
}
}
}
}
private boolean isIn(String word, WordNode list) {
WordNode temp = list;
while (temp != null) {
if (temp.word.equals(word)) {
return true;
}
temp = temp.next;
}
return false;
}
public void anagrams() {
//MUST USE A HELPER METHOD
preorder(treeHead.right);
}
private int compareSummaries (byte[] left, byte[] right) {
for (int index = 0; index < left.length; index++) {
if (left[index] != right[index]) {
return left[index] - right[index];
}
}
return 0;
}
private byte[] stringToSummary(String word) {
byte[] out = new byte[26];
for (int index = 0; index < word.length(); index++) {
out[word.charAt(index) - 'a']++;
}
return out;
}
private void preorder(TreeNode subtree) {
if (subtree != null) {
WordNode temp = subtree.words;
if (temp.next != null) {
while(temp != null) { //Traversing the words linked list
System.out.print(temp.word + " ");
temp = temp.next;
}
System.out.println();
}
preorder(subtree.left);
preorder(subtree.right);
}
}
}
class Anagrammer {
public static void main(String[] args) {
Words book = new Words(""); //Insert file path
AnagramTree tree = new AnagramTree();
while (book.hasNext()) {
String currentWord = book.next();
tree.add(currentWord);
}
tree.anagrams();
}
}