【问题标题】:Java Trie Matching using Iterator使用迭代器进行 Java Trie 匹配
【发布时间】:2016-12-29 12:45:28
【问题描述】:

我有一项任务,其中涉及创建公司名称的 Trie(从文件中读取),然后读取新闻文章输入并计算来自 Trie 的公司名称在文章中出现的次数。

我编写了一个非常标准的 Trie 结构,但是对于分配,让 TrieNode 保存完整的单词而不是每个字符更有意义。

为了让事情变得更复杂,文件中的每个公司名称都有一个“主要名称”,并且可以有多个“次要名称”。例如:Microsoft Corporation、Microsoft、Xbox - 其中名字始终是主要名称。

作业要求我计算文章中任何公司名称的所有匹配项,但在打印结果时仅返回公司的主要名称。因此,我的 TrieNode 具有 String primeName 数据字段以及标准 isEnd bool。但是,在我的例子中,isEnd 表示指定节点及其父节点是否形成完整的公司名称。

例如,使用文章输入“Microsoft Corporation 刚刚发布了新的 Xbox 控制台”。我需要返回类似于“Microsoft:2”的内容,因为 Microsoft Corporation 和 Xbox 共享相同的主要公司名称,即 Microsoft。

我在 getHits() 方法中使用了迭代器,但是当我找到命中时,我需要查看数组中的下一个单词以确保它不是继续,然后再决定是停止还是继续。问题是调用 iter.next() 不仅“窥视”下一个值,而且它向前移动,基本上导致我跳过单词。

例如,如果您查看下面的代码和我的示例,在“Best”获得成功后,它应该看到“Buy”是一个子项,并且在下一次循环时会得到“Buy”的匹配项,但是因为我已经调用 iter.next() 在 While 循环中查看“购买”,所以下一次迭代完全跳过“购买”。有什么方法可以让我简单地查看 While 循环中的下一个 iter 值而不实际移动到它?此外,非常感谢对此代码的任何改进!我确信有很多地方我草率地实施了一些东西。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class BuildTrie {


    // Class Methods
    public static void main(String[] args) throws IOException {

        Trie Companies = new Trie();

        String filename = "companies.dat";
        try {
            BufferedReader reader = new BufferedReader(new FileReader(filename));
            String line;
            while ((line = reader.readLine()) != null) {
                // Split line by tab character
                String[] aliases = line.replaceAll("\\p{P}", "").split("\t");
                // Loop over each "alias" of specific company
                for (int n = 0; n < aliases.length; n++) {
                    String[] name = aliases[n].split(" ");
                    // Insert each alias into Trie with index 0 as primary
                    Companies.insert(name, aliases[0]);
                }

            }
            reader.close();
        } catch (Exception e) {
            System.err.format("Exception occurred trying to read '%s'.", filename);
            e.printStackTrace();
        }
        /*System.out.println("Article Input: ");
        try (BufferedReader input = new BufferedReader(new InputStreamReader(System.in))) {
            String line;
            while ((line = input.readLine()) != null) {
                if (".".equals(line)) break;
                String[] items = line.trim().replaceAll("\\p{P}", "").split("\\s+");
                for (int i = 0; i < items.length; i++) {
                    Companies.words.add(items[i]);
                    //System.out.println(items[i]);
                }
            }
        }*/

        Companies.articleAdd("The");
        Companies.articleAdd("company");
        Companies.articleAdd("Best");
        Companies.articleAdd("Buy");
        Companies.articleAdd("sell");
        Companies.articleAdd("Xbox");

        Companies.getHits();

    }

}

// Trie Node, which stores a character and the children in a HashMap
class TrieNode {
    // Data Fields
    private String word;
    HashMap<String,TrieNode> children;
    boolean bIsEnd;
    private String primary = "";

    // Constructors
    public TrieNode() {
        children = new HashMap<>();
        bIsEnd = false;
    }
    public TrieNode(String st, String prime)  {
        word = st;
        children = new HashMap<>();
        bIsEnd = false;
        primary = prime;
    }

    // Trie Node Methods
    public HashMap<String,TrieNode> getChildren() {
        return children;
    }
    public String getValue() {
        return word;
    }
    public void setIsEnd(boolean val) {
        bIsEnd = val;
    }
    public boolean isEnd() {
        return bIsEnd;
    }
    public String getPrime() {
        return primary;
    }
}

class Trie {
    private ArrayList<String> article = new ArrayList<String>();
    private HashMap<String,Integer> hits = new HashMap<String,Integer>();

    // Constructor
    public Trie() {
        root = new TrieNode();
    }

    // Insert article text
    public void articleAdd(String word) {
        article.add(word);
    }

    // Method to insert a new company name to Trie
    public void insert(String[] names, String prime)  {

        // Find length of the given name
        int length = names.length;
        //TrieNode currNode = root;

        HashMap<String,TrieNode> children = root.children;

        // Traverse through all words of given name
        for( int i=0; i<length; i++)
        {
            String name = names[i];
            System.out.println("Iter: " + name);
            TrieNode t;
            // If there is already a child for current word of given name
            if( children.containsKey(name))
                t = children.get(name);
            else   // Else create a child
            {
                System.out.println("Inserting node " + name + " prime is " + prime);
                t = new TrieNode(name, prime);
                children.put( name, t );
            }
            children = t.getChildren();

            int j = names.length-1;
            if(i==j){
                t.setIsEnd(true);
                System.out.println("WordEnd");
            }
        }
    }

    public void getHits() {
        // String[] articleArr = article.toArray(new String[0]);
        // Initialize reference to traverse through Trie
        // TrieNode crawl = root;
        // int level, prevMatch = 0;
        Iterator<String> iter = article.iterator();
        TrieNode currNode = root;

        while (iter.hasNext()) {
            String word = iter.next();
            System.out.println("Iter: " + word);
            // HashMap of current node's children
            HashMap<String,TrieNode> child = currNode.getChildren();
            // If hit in currNode's children
            if (child.containsKey(word)) {
                System.out.println("Node exists: " + word);
                // Update currNode to be node that matched
                currNode = child.get(word);
                System.out.println(currNode.isEnd());
                String next = "";
                // If currNode is leaf and next node has no match in children, were done
                if (iter.hasNext()) {next = iter.next();}
                if (currNode.isEnd() && !child.containsKey(next)) {
                        System.out.println("Matched word: " + word);
                        System.out.println("Primary: " + currNode.getPrime());
                        currNode = root;
                    } else {
                    // Else next node is continuation

                }

            } else {
             // Else ignore next word and reset

                currNode = root;
            }
        }
    }
    private TrieNode root;
}

【问题讨论】:

    标签: java tree trie


    【解决方案1】:

    我认为你可以使用 for 循环而不是使用 while 和 iter.next(),如下所示

    for (Map.Entry entry : article.entrySet()) { String word = entry.getKey();

    }

    所以你并没有真正移动到你的哈希图的下一个项目。

    如果这不是你的意思,请澄清我们。

    谢谢, 义

    【讨论】:

    • 感谢 Nghia,我实际上在发布后就尝试过,它似乎按预期工作(对我的逻辑进行了一些小的调整)。
    【解决方案2】:

    为此,我选择使用 for 循环而不是 While 循环,并调整了一些逻辑以使其正常工作。对于那些感兴趣的人,下面是新代码,以及“companies.dat”文件的示例(填充到 Trie 中的内容)。标准输入是任何以“。”结尾的文本摘录。换行。

    Companies.dat:

    Microsoft Corporation   Microsoft   Xbox
    Apple Computer  Apple   Mac
    Best Buy
    Dell
    

    TrieBuilder:

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.*;
    
    public class BuildTrie {
    
        // Class Methods
        public static void main(String[] args) throws IOException {
    
            Trie Companies = new Trie();
    
            String filename = "companies.dat";
            try {
                BufferedReader reader = new BufferedReader(new FileReader(filename));
                String line;
                while ((line = reader.readLine()) != null) {
                    // Split line by tab character
                    String[] aliases = line.replaceAll("\\p{P}", "").split("\t");
                    // Loop over each "alias" of specific company
                    for (int n = 0; n < aliases.length; n++) {
                        String[] name = aliases[n].split(" ");
                        // Insert each alias into Trie with index 0 as primary
                        Companies.insert(name, aliases[0]);
                    }
    
                }
                reader.close();
            } catch (Exception e) {
                System.err.format("Exception occurred trying to read '%s'.", filename);
                e.printStackTrace();
            }
            System.out.println("Article Input: ");
            try (BufferedReader input = new BufferedReader(new InputStreamReader(System.in))) {
                String line;
                while ((line = input.readLine()) != null) {
                    if (".".equals(line)) break;
                    String[] items = line.trim().replaceAll("\\p{P}", "").split("\\s+");
                    for (int i = 0; i < items.length; i++) {
                        Companies.articleAdd(items[i]);
                    }
                }
            }
    
            Companies.getHits();
    
        }
    
    }
    
    // Trie Node, which stores a character and the children in a HashMap
    class TrieNode {
        // Data Fields
        private String word;
        HashMap<String,TrieNode> children;
        boolean bIsEnd;
        private String primary = "";
    
        // Constructors
        public TrieNode() {
            children = new HashMap<>();
            bIsEnd = false;
        }
        public TrieNode(String st, String prime)  {
            word = st;
            children = new HashMap<>();
            bIsEnd = false;
            primary = prime;
        }
    
        // Trie Node Methods
        public HashMap<String,TrieNode> getChildren() {
            return children;
        }
        public String getValue() {
            return word;
        }
        public void setIsEnd(boolean val) {
            bIsEnd = val;
        }
        public boolean isEnd() {
            return bIsEnd;
        }
        public String getPrime() {
            return primary;
        }
    }
    
    class Trie {
        private ArrayList<String> article = new ArrayList<String>();
        private HashMap<String,Integer> hits = new HashMap<String,Integer>();
    
        // Constructor
        public Trie() {
            root = new TrieNode();
        }
    
        // Insert article text
        public void articleAdd(String word) {
            article.add(word);
        }
    
        // Method to insert a new company name to Trie
        public void insert(String[] names, String prime)  {
    
            // Find length of the given name
            int length = names.length;
    
            HashMap<String,TrieNode> children = root.children;
    
            // Traverse through all words of given name
            for( int i=0; i<length; i++)
            {
                String name = names[i];
                TrieNode t;
                // If there is already a child for current word of given name
                if( children.containsKey(name))
                    t = children.get(name);
                else   // Else create a child
                {
                    t = new TrieNode(name, prime);
                    children.put( name, t );
                }
                children = t.getChildren();
    
                int j = names.length-1;
                if(i==j){
                    t.setIsEnd(true);
                }
            }
        }
    
        public void getHits() {
            // Initialize reference to traverse through Trie
            TrieNode currNode = root;
    
            for (int i=0; i < article.size(); i++) {
                String word = article.get(i);
                System.out.println("Searching: " + word);
                // HashMap of current node's children
                HashMap<String, TrieNode> child = currNode.getChildren();
                // If hit in currNode's children
                if (child.containsKey(word)) {
                    System.out.println("Node exists: " + word);
                    // Update currNode to be node that matched
                    currNode = child.get(word);
                    child = currNode.getChildren();
                    System.out.println("isEnd?: " + currNode.isEnd());
                    String next = "";
                    if (i+1 < article.size()) {
                        next = article.get(i+1);
                    }
                    // If currNode is leaf and next node has no match in children, were done
                    if (currNode.isEnd() && !child.containsKey(next)) {
                        System.out.println("Primary of match: " + currNode.getPrime());
                        currNode = root;
                    }
                } else {
                    // Else ignore next word and reset
                    System.out.println("No match.");
                    currNode = root;
                }
            }
        }
        private TrieNode root;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-07-30
      • 1970-01-01
      • 1970-01-01
      • 2021-06-19
      • 2020-12-15
      • 1970-01-01
      • 2011-12-31
      • 2013-12-27
      • 1970-01-01
      相关资源
      最近更新 更多