0

我使用以下代码创建哈希图,然后使用树图和比较器对哈希图中的值进行排序。然而,输出是相当出乎意料的。所以任何关于我做错了什么的想法都会有所帮助

代码

public static void main(String[] args) {
    System.out.println("Most freq"+mostFreq(" i me hello hello hello me"));
}


public static String[] mostFreq(String str){

    if ((str==null)||( str.trim().equalsIgnoreCase("")))
        return null;

    String[] arr = new String[10];

    String[] words= str.split(" ");

    Map <String,Integer> map = new HashMap<String,Integer>();

    for (String word :words)
    { 
        int count =0;
        if (map.containsKey(word))
        {     
            count= map.get(word);
            map.put(word, count+1);
        }             
        else
            map.put(word, 1);
    }

    MyComparator comp= new MyComparator(map);
    Map<String,Integer> newMap= new TreeMap(comp);
    newMap.putAll(map);
    Iterator it= newMap.entrySet().iterator();
    while (it.hasNext())
    {
        Map.Entry pairs = (Map.Entry) it.next();
        System.out.println("Key  "+pairs.getKey()+"-- value"+pairs.getValue());
    }

    return arr;
}

这是比较器

package samplecodes;

import java.util.Comparator;
import java.util.Map;

public class MyComparator implements Comparator {

    Map map;

    public MyComparator(Map map){
        this.map=map;
    }

    @Override
    public int compare(Object o1, Object o2) {
        return ((Integer)map.get(o1) >(Integer)map.get(o2)? (Integer)map.get(o1):(Integer)map.get(o2));
    }

}

输出形式为

me-2
hello-3
i-3
4

3 回答 3

3

请检查 JavaDoc 的compare:您不返回较大的值,而是返回< , -1for =和for > 。所以你可以写:o1o20o1o21o1o2

@Override
public int compare(Object o1, Object o2) {
    return ((Integer) map.get(o1)).compareTo((Integer) map.get(o2);
}
于 2013-10-25T02:14:03.847 回答
1

Java Doc ofTreeMap明确指出:

基于红黑树的 NavigableMap 实现。地图根据其键的自然顺序进行排序

我们不应该通过使用TreeMap按值排序来违反此规则。

但是,要按值排序,我们可以执行以下操作:

  1. 创建一个LinkedList条目map
  2. 用于Collection.sort对条目进行排序
  3. 将已排序的条目插入 a LinkedHashMap: 使键保持插入顺序,当前按自然顺序排序。
  4. 返回LinkedHashMap排序后的map

     public static <K extends Comparable,V extends Comparable> Map<K,V> sortByValues(Map<K,V> map){
        List<Map.Entry<K,V>> entries = new LinkedList<Map.Entry<K,V>>(map.entrySet());
    
        Collections.sort(entries, new Comparator<Map.Entry<K,V>>() {
    
            @Override
            public int compare(Entry<K, V> o1, Entry<K, V> o2) {
                return o1.getValue().compareTo(o2.getValue());
            }
        });
    
    
        Map<K,V> sortedMap = new LinkedHashMap<K,V>();
    
        for(Map.Entry<K,V> entry: entries){
            sortedMap.put(entry.getKey(), entry.getValue());
        }
    
        return sortedMap;
    }
    
    }
    

参考: 按值排序地图

于 2013-10-25T02:30:04.543 回答
0

您所做的实际上是对工具的滥用。

我相信你需要做的是:

  1. 有一个输入单词的列表/数组(仍然可以通过拆分输入字符串来获得它)
  2. 创建一个 Map 将单词存储为键,将频率存储为值
  3. 有一个唯一词的集合,然后根据频率对集合进行排序
  4. 在做输出的时候,遍历排序后的唯一词列表,对于每个元素,从frequencyMap中得到频率,输出词+频率。

当然,您仍然可以使用 TreeSet 之类的东西并使用频率作为键,但是您应该将单词列表作为此映射(又名 Multi-Map)的值,而不是编写一个不遵循合同的有问题的比较器比较器: http ://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html#compare%28T,%20T%29 您的原始实现和其中之一的评论答案不符合规则sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y (原来的更糟糕)。

一些代码片段只是为了给你提示:

List<String> words = ....;
Map<String, Integer> wordFrequencyMap = new HashMap<String, Integer>();
// iterate words and update wordFrequencyMap accordingly
List<String> uniqueWords = new ArrayList<String>(new HashSet<String>(words));
Collections.sort(uniqueWords, new WordFrequencyComparator<String>(wordFrequencyMap));
for (String w : uniqueWords) {
  System.out.println("word : " + w + "  frequency : " + wordFrequencyMap.get(w));
}

缺少的部分应该不难。

于 2013-10-25T03:21:38.953 回答