【问题标题】:Comparator and Priority Queues比较器和优先级队列
【发布时间】:2011-04-15 15:20:16
【问题描述】:

我正在编写霍夫曼代码,我导入一个文件,为每个字符生成霍夫曼代码,然后将二进制文件输出到文件中。要导入字符,我使用读取每个字符的扫描仪,将其放入具有读取字符值和频率为 1 的节点中。然后,将节点添加到 PriorityQueue。由于 Node 类有一个 compareTo 方法,它只比较频率,我怎样才能实现一个比较器到这个特定的 PriorityQueue,在队列中排序时比较字符?提前致谢。

文字示例: 字符队列应按如下方式排序:

[A:1][A:1][A:1][B:1][C:1]
Next step:
[A:1][A:2][B:1][C:1]
Final:
[A:3][B:1][C:1]

这里有一些sn-ps:

protected class Node implements Comparable<Node>{
    Character symbol;
    int frequency;

    Node left = null;
    Node right = null;
    @Override
    public int compareTo(Node n) {
        return n.frequency < this.frequency ? 1 : (n.frequency == this.frequency ? 0 : -1);
    }

    public Node(Character c, int f){
        this.symbol = c;
        this.frequency = f;
    }
    public String toString(){
        return "["+this.symbol +","+this.frequency+"]";
    }

这是需要自定义比较器的 PriorityQueue:

public static PriorityQueue<Node> gatherFrequency(String file) throws Exception{
    File f = new File(file);
    Scanner reader = new Scanner(f);
    PriorityQueue<Node> PQ = new PriorityQueue<Node>();
    while(reader.hasNext()){
        for(int i = 0; i < reader.next().length();i++){
            PQ.add(new Node(reader.next().charAt(0),1));
        }
    }
    if(PQ.size()>1){ //during this loop the nodes should be compared by character value
        while(PQ.size() > 1){
            Node a = PQ.remove();
            Node b = PQ.remove();
            if(a.symbol.compareTo(b.symbol)==0){
                Node c = new Node(a.symbol, a.frequency + b.frequency);
                PQ.add(c);
            }
            else break;
        }
        return PQ;
    }
    return PQ;

}

这是我使用 HashMap 创建的新方法:

public static Collection<Entry<Character,Integer>> gatherFrequency(String file) throws Exception{
        File f = new File(file);
        Scanner reader = new Scanner(f);
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        while(reader.hasNext()){
            for(int i = 0; i < reader.next().length();i++){
                Character key = reader.next().charAt(i);
                if(map.containsKey(reader.next().charAt(i))){
                    int freq = map.get(key);
                    map.put(key, freq+1);
                }
                else{
                    map.put(key, 1);
                }
            }
        }
        return map.entrySet();
    }

【问题讨论】:

  • 这似乎比它需要的复杂得多。不应该将所有A 都计算在内,即使它们不是连续的。
  • 如果它们在按字符值排序的 PriorityQueue 中,它们将始终是连续的

标签: java hashmap priority-queue comparator huffman-code


【解决方案1】:

实现 Huffman 树的标准方法是使用 hashmap(在 Java 中,您可能会使用 HashMap&lt;Character, Integer&gt;)来计算每个字母的频率,并插入优先级队列每个字母一个节点。因此,在构建 Huffman 树本身时,您从一个已经处于您展示的“最终”状态的优先级队列开始。然后霍夫曼算法反复从优先队列中提取两个节点,为这两个节点构造一个新的父节点,并将新节点插入优先队列。

【讨论】:

  • @TrevorMA:除非你真的需要TIntIntHashMap 提供的轻微性能改进,否则我建议你使用标准HashMap,特别是因为你以前没有使用过它(这将是一个学习它的好机会,你会遇到HashMap TIntIntHashMap更多)。
  • @TrevorMA:是的;这可能有点令人困惑。 put() 方法用于第一次在 hashmap 中放置一些东西,也用于替换现有值。假设您有一个字符存储在变量c 中;那么您首先需要检查 hashmap 是否包含 c 作为键。如果是这样,您可以使用 get() 读取当前频率,计算频率 + 1 并使用 put() 更新哈希图中的频率。如果密钥不存在,您可以使用频率 1 添加它。
  • @TrevorMA:没问题。使用entrySet() 方法,该方法为您提供映射条目的集合,其中每个条目都包含键和值。
  • @TrevorMA:很高兴它有帮助。顺便说一句,请记住以某种方式在输出文件中包含对霍夫曼树的描述,因为如果您没有树,算法生成的位序列就没有多大用处... ;-)
  • @TrevorMA:在执行完Character key = reader.next().charAt(i); 之后,您再次调用reader.next(),从而又读取了一个字符。该字符可能与现在存储在key 中的字符不同,并且您询问字典中是否存在 second 字符 - 如果存在,您尝试更新 key . (编辑:我现在看到您多次调用 next() - 每次调用 next 都会为您提供输入中的下一个字符串...在整个 while 循环体中仅使用一次 next()。)
猜你喜欢
  • 1970-01-01
  • 2021-06-17
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多