/************************ Trie.java *******************************
*
*/
class TrieNode {
boolean isLeaf;
}
class TrieNonLeaf extends TrieNode {
boolean endOfWord = false;
String letters;
TrieNode[] ptrs = new TrieNode[1];
TrieNonLeaf() {
isLeaf = false;
}
TrieNonLeaf(char ch) {
letters = new String();
letters += ch;
isLeaf = false;
}
}
class TrieLeaf extends TrieNode {
String suffix;
TrieLeaf() {
isLeaf = true;
}
TrieLeaf(String suffix) {
this.suffix = new String(suffix);
isLeaf = true;
}
}
class Trie {
protected TrieNonLeaf root;
protected final int notFound = -1;
public Trie() {
}
public Trie(String word) {
root = new TrieNonLeaf(word.charAt(0)); // initialize the root
createLeaf(word.charAt(0),word.substring(1),root); // to avoid later
} // test;
public void sideView() {
sideView(0,root,new String()); // assumption: the root is not null;
}
protected void sideView(int depth, TrieNode p, String prefix) {
if (p.isLeaf) {
for (int j = 1; j <= depth; j++)
System.out.print(" ");
System.out.println(" >" + prefix + "|" + ((TrieLeaf)p).suffix);
}
else {
for (int i = ((TrieNonLeaf)p).letters.length()-1; i >= 0; i--) {
if (((TrieNonLeaf)p).ptrs[i] != null) {
// add the letter corresponding to position i to prefix;
prefix = prefix.substring(0,depth) +
((TrieNonLeaf)p).letters.charAt(i);
sideView(depth+1,((TrieNonLeaf)p).ptrs[i],prefix);
}
else { // if empty leaf;
for (int j = 1; j <= depth+1; j++)
System.out.print(" ");
System.out.println(">>" + prefix.substring(0,depth) +
((TrieNonLeaf)p).letters.charAt(i) + "|");
}
}
if (((TrieNonLeaf)p).endOfWord) {
for (int j = 1; j <= depth+1; j++)
System.out.print(" ");
System.out.println(">>" + prefix.substring(0,depth) + "||");
}
}
}
protected int position(TrieNonLeaf p, char ch) {
int i = 0;
for ( ; i < p.letters.length() && p.letters.charAt(i) != ch; i++);
if (i < p.letters.length())
return i;
else return notFound;
}
public boolean found(String word) {
TrieNode p = root;
int pos, i = 0;
while (true)
if (p.isLeaf) { // node p is a leaf
TrieLeaf lf = (TrieLeaf) p; // where the matching
if (word.substring(i).equals(lf.suffix)) // suffix of
return true; // word should be found;
else return false;
}
else if ((pos = position((TrieNonLeaf)p,word.charAt(i))) != notFound
&& i+1 == word.length()) // the end of word has to
if (((TrieNonLeaf)p).ptrs[pos] == null) // correspond
return true; // with an empty leaf
else if(!(((TrieNonLeaf)p).ptrs[pos]).isLeaf &&
((TrieNonLeaf)((TrieNonLeaf)p).ptrs[pos]).endOfWord)
return true; // or the endOfWord marker on;
else return false;
else if (pos != notFound && ((TrieNonLeaf)p).ptrs[pos] != null) {
p = ((TrieNonLeaf)p).ptrs[pos];// continue path,
i++; // if possible,
}
else return false; // otherwise failure;
}
protected void addCell(char ch, TrieNonLeaf p, int stop) {
int i;
int len = p.letters.length();
char[] s = new char[len+1];
TrieNode[] tmp = p.ptrs;
p.ptrs = new TrieNode[len+1];
for (i = 0; i < len+1; i++)
p.ptrs[i] = null;
if (stop < len) // if ch does not follow all letters in p,
for (i = len; i >= stop+1; i--) { // copy from tmp letters > ch;
p.ptrs[i] = tmp[i-1];
s[i] = p.letters.charAt(i-1);
}
s[stop] = ch;
for (i = stop-1; i >= 0; i--) { // and letters < ch;
p.ptrs[i] = tmp[i];
s[i] = p.letters.charAt(i);
}
p.letters = new String(s);
}
protected void createLeaf(char ch, String suffix, TrieNonLeaf p) {
int pos = position(p,ch);
TrieLeaf lf = null;
if (suffix != null && suffix.length() > 0) // don't create any leaf
lf = new TrieLeaf(suffix); // if there is no suffix;
if (pos == notFound) {
for (pos = 0; pos < p.letters.length() &&
p.letters.charAt(pos) < ch; pos++);
addCell(ch,p,pos);
}
p.ptrs[pos] = lf;
}
public void insert(String word) {
TrieNonLeaf p = root;
TrieLeaf lf;
int offset, pos, i = 0;
while (true) {
if (i == word.length()) { // if the end of word reached,
if (p.endOfWord)
System.out.println("duplicate entry1: " + word);
p.endOfWord = true; // set endOfWord to true;
return;
} // if position in p indicated
pos = position(p,word.charAt(i));
if (pos == notFound) { // by the first letter of word
createLeaf(word.charAt(i),word.substring(i+1),p);
// does not exist, create
return; // a leaf and store in it the
} // unprocessed suffix of word;
else if (pos != notFound && // empty leaf in position pos;
p.ptrs[pos] == null) {
if (i+1 == word.length()) {
System.out.println("duplicate entry2: " + word);
return;
}
p.ptrs[pos] = new TrieNonLeaf(word.charAt(i+1));
((TrieNonLeaf)(p.ptrs[pos])).endOfWord = true;
// check whether there is any suffix left:
String s = (word.length() > i+2) ? word.substring(i+2) : null;
createLeaf(word.charAt(i+1),s,(TrieNonLeaf)(p.ptrs[pos]));
return;
}
else if (pos != notFound && // if position pos is
p.ptrs[pos].isLeaf) { // occupied by a leaf,
lf = (TrieLeaf) p.ptrs[pos]; // hold this leaf;
if (lf.suffix.equals(word.substring(i+1))) {
System.out.println("duplicate entry3: " + word);
return;
}
offset = 0;
// create as many non-leaves as the length of identical
// prefix of word and the string in the leaf (for cell 'R',
// leaf "EP", and word "REAR", two such nodes are created);
do {
pos = position(p,word.charAt(i+offset));
// word = "ABC", leaf = "ABCDEF" => leaf = "DEF";
if (word.length() == i+offset+1) {
p.ptrs[pos] = new TrieNonLeaf(lf.suffix.charAt(offset));
p = (TrieNonLeaf) p.ptrs[pos];
p.endOfWord = true;
createLeaf(lf.suffix.charAt(offset),
lf.suffix.substring(offset+1),p);
return;
}
// word = "ABCDEF", leaf = "ABC" => leaf = "DEF";
else if (lf.suffix.length() == offset ) {
p.ptrs[pos] = new TrieNonLeaf(word.charAt(i+offset+1));
p = (TrieNonLeaf) p.ptrs[pos];
p.endOfWord = true;
createLeaf(word.charAt(i+offset+1),
word.substring(i+offset+2),p);
return;
}
p.ptrs[pos] = new TrieNonLeaf(word.charAt(i+offset+1));
p = (TrieNonLeaf) p.ptrs[pos];
offset++;
} while (word.charAt(i+offset) == lf.suffix.charAt(offset-1));
offset--;
// word = "ABCDEF", leaf = "ABCPQR" =>
// leaf('D') = "EF", leaf('P') = "QR";
// check whether there is any suffix left:
// word = "ABCD", leaf = "ABCPQR" =>
// leaf('D') = null, leaf('P') = "QR";
String s = null;
if (word.length() > i+offset+2)
s = word.substring(i+offset+2);
createLeaf(word.charAt(i+offset+1),s,p);
// check whether there is any suffix left:
// word = "ABCDEF", leaf = "ABCP" =>
// leaf('D') = "EF", leaf('P') = null;
if (lf.suffix.length() > offset+1)
s = lf.suffix.substring(offset+1);
else s = null;
createLeaf(lf.suffix.charAt(offset),s,p);
return;
}
else {
p = (TrieNonLeaf) p.ptrs[pos];
i++;
}
}
}
}