Попробуйте реализацию

Я пытаюсь реализовать очень простой Trie на Java, который поддерживает 3 операции. Я бы хотел, чтобы у него был метод вставки, метод has (т. е. определенное слово в дереве) и метод toString для возврата дерева в виде строки. Я считаю, что у меня вставка работает правильно, но has и toString оказываются сложными. Вот что у меня есть до сих пор.

Класс триэ.


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"));
    }
}

И класс узла


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 "";
    }
}

Таким образом, в основном при создании Trie, TrieNode создается как корень с 26 дочерними элементами. Когда делается попытка вставки, в этом корневом узле вызывается вставка, которая рекурсивно создает новый узел в правильной позиции и продолжается до тех пор, пока слово не будет завершено. Я считаю, что этот метод работает правильно.

Моя функция has очень сломана, потому что по какой-то причине я должен иметь этот оператор возврата за скобками. Я не могу включить его в предложение else или компилятор жалуется. Кроме этого, я думаю, что этот метод должен работать с некоторыми настройками, но я не могу понять это на всю жизнь.

toString - это зверь, с которым я пытался справиться, но ничего из того, что я добавляю, не работает, поэтому я оставлю это до тех пор, пока не решу проблему has. Если я заработаю, я смогу найти способ переформатировать его в функцию toString.

Цель int val = word.charAt(0) - 64; это связано с тем, что каждая введенная строка должна быть полностью заглавной (я создам функцию форматирования строки, чтобы гарантировать это впоследствии), поэтому значение int первой буквы - 64 будет его позицией в массиве. т.е. индекс массива 0 равен A, поэтому A = 64, A - 64 = 0. B = 65, B - 64 = 1 и так далее.


person dc.    schedule 08.02.2010    source источник
comment
Вместо: int val = word.charAt(0) - 64; вы делаете: int val = word.charAt(0) - 'A'; !   -  person Nicolas Gramlich    schedule 30.01.2012
comment
Есть ли причина, по которой ваша попытка 26-ая? Почему вы ограничиваетесь только заглавными буквами США? Что произойдет, если какой-либо из ключей содержит пробелы или (запрещает Odin) международные символы?   -  person Enno    schedule 29.05.2012
comment
Вот моя реализация, включая addWord, getWordNumber, listAllDistinctWords, см. ее через: github.com/shaogbi/Java/blob/master/datastructure/MyTrie.java   -  person coderz    schedule 26.05.2014


Ответы (6)


Ваша функция has, вероятно, должна выглядеть так:

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

Вы выполняете рекурсивный вызов, но вам действительно нужно позволить этому значению вернуться обратно к исходному вызывающему объекту.

person Anon.    schedule 08.02.2010
comment
Вау, понял. Мне действительно нужно найти дополнительную информацию о рекурсии. Единственная проблема сейчас заключается в том, что в определенных ситуациях я получаю исключения с нулевым указателем. Например: Введите слова TEST и TATTER. TEST и TATTER возвращают true, а отсечение любых символов из этих поисков возвращает false. Это хорошо. Но если я ищу TESTA, я получаю нулевой указатель. Ищу TATTERR, получаю нулевой указатель. Я не уверен, что вызывает это, так как я проверяю наличие нулей в первом выражении. - person dc.; 09.02.2010
comment
Рассмотрим случай, когда c[val] равно null, а word.length() равно 1. c[val] равно null, поэтому первое if ложно, и мы смотрим на второе. Итак, мы тестируем c[val].flag... Уверен, вы видите проблему. - person Anon.; 09.02.2010
comment
Ах да, поэтому я проверяю флаг нулевого значения. Так просто. Вторая пара глаз всегда так полезна. :) - person dc.; 09.02.2010

Возможно, вы можете просто использовать «Map c» вместо «TrieNode[] c», что позволит вам использовать это для всех типов символов в верхнем/нижнем регистре и даже для специальных символов и даже сэкономит вам место (выделение массива из 26 символов в каждый уровень персонажа)

person Gaurav Kohli    schedule 27.11.2011

Вот моя реализация: -

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);

        }
    }
}

}
person Ashutosh Jha    schedule 15.06.2015

Вот простая реализация Java без использования какой-либо другой структуры данных

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());
    }


}
person Dheeraj Sachan    schedule 26.06.2016

Вот моя реализация:

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;
    }
}
person Enrico Giurin    schedule 06.03.2017
comment
Как мы могли бы реализовать набор объектов, имеющих строку и числа для поиска с использованием поиска по основанию (триоду) по дереву. stackoverflow.com/ вопросы/55297803/ - person TAB; 26.03.2019