Trie implementation
Asked Answered
I

6

15

I am attempting to implement a very simple Trie in Java that supports 3 operations. I'd like it to have an insert method, a has method (ie is a certain word in the trie), and a toString method to return the trie in string form. I believe I have insertion working properly, but has and toString are proving to be difficult. Here's what I have so far.

The trie class.


public class CaseInsensitiveTrie implements SimpleTrie {

    //root node
    private TrieNode r;

    public CaseInsensitiveTrie() {
        r = new TrieNode();
    }

    public boolean has(String word) throws InvalidArgumentUosException {
        return r.has(word);
    }

    public void insert(String word) throws InvalidArgumentUosException {
        r.insert(word);
    }

    public String toString() {
        return r.toString();
    }

    public static void main(String[] args) {

        CaseInsensitiveTrie t = new CaseInsensitiveTrie();

        System.out.println("Testing some strings");
        t.insert("TEST");
        t.insert("TATTER");
        System.out.println(t.has("TEST"));
    }
}

And the node class


public class TrieNode {

    //make child nodes
    private TrieNode[] c;
    //flag for end of word
    private boolean flag = false;

    public TrieNode() {
        c = new TrieNode[26]; //1 for each letter in alphabet
    }

    protected void insert(String word) {
        int val = word.charAt(0) - 64;

        //if the value of the child node at val is null, make a new node
                //there to represent the letter
        if (c[val] == null) {
            c[val] = new TrieNode();
        }

        //if word length > 1, then word is not finished being added.
        //otherwise, set the flag to true so we know a word ends there.
        if (word.length() > 1) {
            c[val].insert(word.substring(1));
        } else {
            c[val].flag = true;
        }
    }

    public boolean has(String word) {
        int val = word.charAt(0) - 64;
        if (c[val]!=null && word.length()>1) {
            c[val].has(word.substring(1));
        } else if (c[val].flag==true && word.length()==1) {
            return true;
        }

        return false;
    }

    public String toString() { 
        return "";
    }
}

So basically, when creating a Trie, a TrieNode is created as the root with 26 children. When an insert is attempted, insert is called on that root node, which recursively creates a new node at the correct position, and continues until the word is complete. I believe that method is working properly.

My has function is very broken, because I have to have that return statement outside of the brackets for some reason. I cannot contain it within an else clause or the compiler complains. Other than that, I am thinking that method should work with some tweaks, but I cannot figure it out for the life of me.

toString is a beast I have tried to tackle, but nothing I throw at it works, so I will leave that be until I solve the has problem. If I get has working I may be able to figure a way to reformat it into a toString function.

The purpose of the int val = word.charAt(0) - 64; is because each string entered must be all caps (I will create a string formatting function to ensure this afterwards) so the first letter's int value - 64 will be it's position in the array. ie array index 0 is A, so A = 64, A - 64 = 0. B = 65, B - 64 = 1, and so on.

Incarnate answered 8/2, 2010 at 22:58 Comment(3)
Instead of: int val = word.charAt(0) - 64; you do: int val = word.charAt(0) - 'A'; !Hoopes
Is there any reason why your trie is 26-ary? Why do you limit yourself to just uppercase US letters? What happens if any of the keys have spaces or (Odin forbid) international characters in them?Glade
Here is my implementation, including addWord, getWordNumber, listAllDistinctWords, see it via: github.com/shaogbi/Java/blob/master/datastructure/MyTrie.javaRentschler
E
13

Your has function should probably look like this:

if (c[val]!=null && word.length()>1) {
    return c[val].has(word.substring(1)); //<-- Change is on this line
} else if (c[val].flag==true && word.length()==1) {
    ...etc

You perform the recursive call, but you really need to let that value propagate back out to the original caller.

Entropy answered 8/2, 2010 at 23:3 Comment(3)
Wow, that got it. I really need to find some more information on recursion. The only problem now is that I am getting nullpointer exceptions in certain situations. For example: Input the words TEST and TATTER. TEST and TATTER return true, cutting off any characters from those searches return false. This is good. But, if I search for TESTA, I get a nullpointer. Search for TATTERR, I get a nullpointer. I am not sure what is causing this, since I am checking for nulls int he first statement.Incarnate
Consider the case where c[val] is null and word.length() is 1. c[val] is null so the first if is false, and we look at the second one. So we test c[val].flag... I'm sure you can see the problem.Entropy
Ah right, so I am checking for the flag of a null value. So simple. A second set of eyes is always so helpful. :)Incarnate
E
7

Maybe you can just use "Map c"instead of "TrieNode[] c", that would allow you to use this for all the types of characters uppercase/lowercase and even special characters and even would save you space ( allocating 26 character array at each character level )

Erythrite answered 27/11, 2011 at 13:37 Comment(0)
B
2

Here is simple java implementation without using any other data structure

import java.util.ArrayList;
import java.util.List;

class Trie {

    private static Node root = new Node(' ', false);

    static int getIndex(char x) {
        return ((int) x) - ((int) 'a');
    }

    static class Node {
        char data;
        boolean isLeaf;
        Node[] children;

        Node(char data, boolean leaf) {
            this.data = data;
            this.isLeaf = leaf;
            this.children = new Node[26];
        }

    }

    static void insert(String data, Node root) {
        if (data == null || data.length() == 0) {
            return;
        }
        Node child = root.children[getIndex(data.charAt(0))];
        if (child == null) {
            Node node = new Node(data.charAt(0), data.length() == 1);
            root.children[getIndex(data.charAt(0))] = node;
            if (data.length() > 1) {
                insert(data.substring(1, data.length()), node);
            }
        } else {
            if (data.length() == 1) {
                child.isLeaf = true;
            } else {
                insert(data.substring(1, data.length()), child);
            }
        }
    }

    static boolean find(String data, Node root) {
        if (data == null || data.length() == 0) {
            return true;
        }
        char x = data.charAt(0);
        //note that first node ie root is just dummy, it just holds important
        Node node = root.children[getIndex(x)];
        if (node == null) {
            return false;
        } else {
            if (data.length() == 1) {
                return node.isLeaf;
            } else {
                return find(data.substring(1, data.length()), node);
            }
        }
    }

    static boolean delete(String data, Node root) {
        if (data == null || data.length() == 0) {
            return false;
        }
        char x = data.charAt(0);
        //note that first node ie root is just dummy, it just holds important
        Node node = root.children[getIndex(x)];
        if (node == null) {
            return false;
        } else {
            if (data.length() == 1) {
                node.isLeaf = false;
                boolean allNull = true;
                for (Node node1 : node.children) {
                    allNull = allNull && node1 == null;
                }
                return allNull;
            } else {
                boolean delete = delete(data.substring(1, data.length()), node);
                if (delete) {
                    node.children[getIndex(x)] = null;
                    if(node.isLeaf){
                        return false;
                    }
                    boolean allNull = true;
                    for (Node node1 : node.children) {
                        allNull = allNull && node1 == null;
                    }
                    return allNull;                }
            }
        }
        return false;
    }


    private static List<String> strings = new ArrayList<>();

    private static List<String> getAll() {
        strings = new ArrayList<String>();
        findAllDFS(root, "");
        return strings;
    }

    private static void findAllDFS(Node node, String old) {
        if (node != null) {
            if (node.data != ' ') {
                old = old + node.data;
            }
            if (node.isLeaf) {
                strings.add(old);
            }
            for (Node node1 : node.children) {
                findAllDFS(node1, old);
            }
        }
    }

    public static void main(String[] args) {
        insert("abc", root);
        insert("xyz", root);
        insert("abcd", root);
        insert("abcde", root);


        delete("abcd", root);

 /*       System.out.println(find("abc", root));
        System.out.println(find("abcd", root));
        System.out.println(find("ab", root));
        System.out.println(find("xyz", root));*/


        System.out.println(getAll());
    }


}
Bluebeard answered 26/6, 2016 at 18:55 Comment(0)
P
1

This Trie Map implements has (called get in this implementation) and toString

Potence answered 27/11, 2011 at 13:46 Comment(0)
T
1

Here is my implementation: -

public class Tries {

class Node {
    HashMap<Character, Node> children;
    boolean end;
    public Node(boolean b){
        children = new HashMap<Character, Tries.Node>();
        end = false;
    }
}
private Node root;
public Tries(){
    root = new Node(false);
}
public static void main(String args[]){
    Tries tr = new Tries();
    tr.add("dog");
    tr.add("doggy");

    System.out.println(tr.search("dogg"));
    System.out.println(tr.search("doggy"));
}
private boolean search(String word) {
    Node crawl = root;
    int n = word.length();
    for(int i=0;i<n;i++){
        char ch = word.charAt(i);
        if(crawl.children.get(ch) == null){
            return false;
        }
        else {
            crawl = crawl.children.get(ch);
            if(i==n-1 && crawl.end == true){
                return true;
            }

        }
    }
    return false;
}
private void add(String word) {
    Node crawl = root;
    int n = word.length();
    for(int i=0;i<n;i++){
        char ch = word.charAt(i);
        if(crawl.children.containsKey(ch)){
            crawl = crawl.children.get(ch);
        }
        else {
            crawl.children.put(ch, new Node(false));
            Node temp = crawl.children.get(ch);
            if(i == n-1){
                temp.end = true;
            }
            crawl = temp;
            System.out.println(ch + "      " + crawl.end);

        }
    }
}

}
Thunder answered 15/6, 2015 at 13:36 Comment(0)
E
1

Here my implementation:

public class Tries {
private static class Leaf {
    private Leaf(char c) {
        this.c=c;
    }
    char c;
    int counter = 1;
    List<Leaf> leaves = new ArrayList<>(10);
}
private Leaf root = new Leaf('0');
public void add(String word) {
    Leaf current = root;
    Leaf newLeaf = null;
    for (char c : word.toCharArray()) {
        boolean found = false;
        for (Leaf leaf : current.leaves) {
            if (leaf.c == c) {
                current = leaf;
                current.counter++;
                found=true;
                break;
            }
        }
        if (!found) {
            newLeaf = new Leaf(c);
            current.leaves.add(newLeaf);
            current = newLeaf;
        }
    }
}
public int find(String partial) {
    Leaf current = root;
    for (char c : partial.toCharArray()) {
        boolean found = false;
        for (Leaf leaf : current.leaves) {
            if (leaf.c == c) {
                current=leaf;
                found=true;
                break;
            }
        }
        if(!found) return 0;
    }
    return current.counter;
}

public boolean hasWord(String partial) {
    return find(partial)>0;
    }
}
Erminiaerminie answered 6/3, 2017 at 8:19 Comment(1)
How could we implement a collection of object having string and numbers to search using radix (trie) tree search. #55298303Airbrush

© 2022 - 2024 — McMap. All rights reserved.