如何在Trie数据结构中实现删除方法?

时间:2014-04-02 17:55:41

标签: java algorithm data-structures trie

我正在尝试实现PatriciaTrie数据结构。最近我通过Google Docs在编码访谈中问过这个问题。但我无法回答这个问题。

我通过在下面的代码中添加insert方法取得了一些进展,但却陷入了remove代码中的PatriciaTrie方法 - 不确定如何实现 -

以下是我的PatriciaTrie代码 -

public class PatriciaTrie {

    protected static class Edge {
        Node target;
        TTString label;
        public Edge(Node target, TTString label) {
            this.target = target;
            this.label = label;
        }
    }

    protected static class Node {
        Edge[] edges;           // the children of this node
        int numberOfChildren;   // the number of children
        public Node() {
            edges = new Edge[128];
            numberOfChildren = 0;
        }
    }

    /**
     * number of strings stored in the trie
     */
    protected int number;

    /**
     * This is root
     */
    protected Node root;

    public PatriciaTrie() {
        root = new Node();
        number = 0;
    }

    /** 
     * Add the x to this trie
     * @param x the string to add
     * @return true if x was successfully added or false if x is already in the trie
     */
    public boolean insert(TTString x) {
        Node current = root;
        for (int i = 0; i < x.length(); i++) {
            TTString ch = x.subString(i, 1);
            if (current.edges[x.charAt(i)] != null) {
                Node child = current.edges[x.charAt(i)].target;
                current = child;
            } else {
                current.edges[x.charAt(i)] = new Edge(new Node(), ch);
                current.numberOfChildren++;
                current = current.edges[x.charAt(i)].target;
            }
            if (i == x.length() - 1)
                return true;
        }
        return false;
    }

    /** 
     * Remove x from this trie
     * @param x the string to remove
     * @return true if x was successfully removed or false if x is not stored in the trie
     */
    public boolean remove(TTString x) {
        // not sure how to do this

        return false;
    }       
}

以下是我的TTString课程 -

public class TTString {
    int i;        // index of first character  
    int m;        // length
    byte[] data;  // data 

    public TTString(String s) {
        data = s.getBytes();
        i = 0;
        m = s.length();
    }

    protected TTString(byte[] data, int i, int m) {
        this.data = data;
        this.i = i;
        this.m = m;
    }

    public TTString subString(int j, int n) {
        if (j < 0 || j >= m) throw new IndexOutOfBoundsException();
        if (n < 0 || j + n > m) throw new IndexOutOfBoundsException();
        return new TTString(data, i+j, n);
    }

    /**
     * The length of this string
     * @return
     */
    public int length() {
        return m;
    }

    /**
     * Return the character at index j
     * @param j
     * @return
     */
    public char charAt(int j) {
        return (char)data[i+j];
    }
}

有关如何在此处实施remove方法的任何想法?

3 个答案:

答案 0 :(得分:1)

一个想法是:从根到叶子对应于x的最后一个字符(假设有包含x的路径,否则没有什么可改变的),记住最后一个在进程中分叉你的路径(第一个分叉在根目录)。当您在叶子上时,从最后一个叉子中移除所有边缘/节点直到叶子。

答案 1 :(得分:0)

我已经在TRIE数据结构的C#中实现了它,字符串代码如下。您可以在此处查看完整代码http://devesh4blog.wordpress.com/2013/11/16/real-time-auto-complete-using-trie-in-c/

       public void RemoveWord(string word, TRIENode rootNode, string id)
    {
        int len = word.Length;
        if (len == 0)
        {
            rootNode.PrefixCount--;
            if (rootNode.PrefixCount == 0)
                rootNode.IsCompleteWord = false;
            rootNode.Ids.Remove(id);
            return;
        }
        for (int i = 0; i < len; i++)
        {
            string key = word.Substring(i, 1);
            string lowerVersionKey = key.ToLower();
            rootNode.PrefixCount--;
            rootNode = rootNode.Children[lowerVersionKey];
        }
        rootNode.Ids.Remove(id);
        if (rootNode.Ids.Count == 0)
            rootNode.IsCompleteWord = false;
    }

答案 2 :(得分:0)

这是我的代码和示例测试:

protected static class Edge {
    Node target;
    TTString label;

    public Edge(Node target, TTString label) {
        this.target = target;
        this.label = label;
    }
}

protected static class Node {
    Edge[] edges; // the children of this node
    int numberOfChildren; // the number of children
    // isEnd is true means this node is a string's end node.
    boolean isEnd;

    public Node() {
        edges = new Edge[128];
        numberOfChildren = 0;
        isEnd = false;
    }
}

/**
 * number of strings stored in the trie
 */
protected int number;

/**
 * This is root
 */
protected Node root;

public PatriciaTrie() {
    root = new Node();
    number = 0;
}

/**
 * Add the x to this trie
 * 
 * @param x
 *            the string to add
 * @return true if x was successfully added or false if x is already in the
 *         trie
 */
public boolean insert(TTString x) {
    // not sure what I am supposed to do here?
    Node current = root;
    for (int i = 0; i < x.length(); i++) {
        TTString ch = x.subString(i, 1);
        if (current.edges[x.charAt(i)] != null) {
            Node child = current.edges[x.charAt(i)].target;
            current = child;
        } else {
            current.edges[x.charAt(i)] = new Edge(new Node(), ch);
            current.numberOfChildren++;
            current = current.edges[x.charAt(i)].target;
        }
        if (i == x.length() - 1) {
            // mark this node is the string x's end node.
            current.isEnd = true;
            return true;
        }
    }
    return false;
}

// find the string x in the trie, if true, return the x.
public TTString find(TTString x) {
    boolean isOk = false;
    Node current = root;
    for (int i = 0; i < x.length(); i++) {
        if (current.edges[x.charAt(i)] != null) {
            current = current.edges[x.charAt(i)].target;
        } else {
            isOk = false;
        }
        if (i == x.length() - 1 && current.isEnd == true) {
            isOk = true;
        }
    }
    if (isOk == false)
        return null;
    else
        return x;
}

public boolean remove(TTString x) {
    Node current = root;
    for (int i = 0; i < x.length(); i++) {
        if (current.edges[x.charAt(i)] != null) {
            current = current.edges[x.charAt(i)].target;
        } else {
            return false;
        }
        if (i == x.length() - 1) {
            // delete the string x.
            current.isEnd = false;
            return true;
        }
    }
    return false;
}

void run() {
    /*
     * Here is the sample patricialTrie whose edges are labeled with
     * letters.
     */
    TTString tmp = new TTString("ABCD");
    System.out.println(insert(tmp) ? "YES" : "NO");
    Node current = root;
    for (int i = 0; i < tmp.length(); i++) {
        System.out.println(current.edges[tmp.charAt(i)].label.charAt(0));
        current = current.edges[tmp.charAt(i)].target;
    }
    tmp = new TTString("ABCDE");
    insert(tmp);
    tmp = new TTString("ABDF");
    insert(tmp);

    /*
     * remove method
     */
    tmp = new TTString("ABCDE");
    System.out.println(remove(tmp) ? "YES" : "NO");
    System.out.println(find(tmp) == null ? "NULL" : find(tmp));
    tmp = new TTString("ABCD");
    System.out.println(find(tmp) == null ? "NULL" : find(tmp));
}

public static void main(String args[]) {
    new PatriciaTrie().run();
}