Java,如何在Comparator中按字母顺序对char进行排序

时间:2019-09-24 02:16:32

标签: java comparator

我正在尝试建立字符的最大堆。首先按频率排序,如果频率相同,则按字母顺序排序。

Map<Character, Integer> map = new HashMap<>();
for(int i = 0; i < n; i++) {
     char c = s.charAt(i);
     map.put(c, map.getOrDefault(c, 0) + 1);
}

Queue<Character> pq = new PriorityQueue<>(new Comparator<Character>(){
  @Override
  public int compare(Character c1, Character c2){
   if(map.get(c1) == map.get(c2)){
     return c1 < c2 ? -1 : (c1 == c2 ? 0 : 1);
     //return (char)c1 - (char)c2; same output
   }
   return map.get(c2) - map.get(c1);
  }
});

for(char key : map.keySet()){
   pq.offer(key);
   System.out.println(key + " has freq " + map.get(key));
}

while(!pq.isEmpty()) {
     System.out.print(pq.poll() + " ");
}   

我在此maxheap中放入了26个字母,每个字母的频率相同5000。

但是输出顺序为'a','z','y','x'....,'c','b'。
enter image description here

每个字符的频率为5时,顺序正确。 enter image description here

我不明白为什么频率为5000的输出是这样的。如何获得正确的订单?

3 个答案:

答案 0 :(得分:3)

鉴于所有频率均相同,则您的if语句错误。您可以使用内置方法比较对象并返回结果

Integer f1 = map.get(c1);
Integer f2 = map.get(c2);
int x = f1.compareTo(f2)
if(x == 0){
    return Character.compare(c1, c2);
}
return x;

答案 1 :(得分:1)

您正在通过Integer==语句比较两个if(map.get(c1) == map.get(c2))实例。它在频率为5时起作用的原因是,对-128…+ 127范围内的自动装箱值进行了强制缓存。当频率为5000时,Integer对象的身份未指定,相等的对象可能具有不同的身份。

一种解决方法是改用equals。另一个是停止手动实现Comparator并使用工厂方法。加上其他改进,您的代码可简化为

Map<Character, Integer> map = new HashMap<>();
for(int i = 0; i < n; i++) {
     map.merge(s.charAt(i), 1, Integer::sum);
}

Queue<Character> pq = new PriorityQueue<>(
    Comparator.<Character>comparingInt(map::get).reversed()
        .thenComparing(Comparator.naturalOrder())
);

map.forEach((key, freq) -> {
   pq.offer(key);
   System.out.println(key + " has freq " + freq);
});

while(!pq.isEmpty()) {
     System.out.print(pq.poll() + " ");
}

答案 2 :(得分:0)

您可以使用.equals()方法比较两个对象。它将返回一个布尔值。如果您想进行硬编码比较,则为每个字母分配一个整数值(总共26个变量)并比较它们的整数值,您会知道将哪个放在哪里。