按频率排序字符串数组的最有效方法

Edd*_*Edd 6 java arrays string mode

我有一个字符串数组:

String[] stringArray = {"x", "y", "z", "x", "x", "y", "a"};
Run Code Online (Sandbox Code Playgroud)

什么是最快/最有效的方式来订购这个更小Collection/按频率的每个String频率的频率顺序?

我虽然关于使用Stringa作为键,HashMap<String,Integer>但这不会按频率排序

我考虑的另一种方法是使用TreeMap<Integer, String[]>带有该整数的字符串列表,但似乎涉及很多检查..

我试图避免使用多个循环如果可能,因为我的String数组将比上面的数组大得多.谢谢!

编辑 我想要的只是能够按频率顺序输出字符串,并且最好能够将该字符串与其在频率中的频率配对,例如两个输出数组:

["x", "y", "z", "a"]
[3,2,1,1]
Run Code Online (Sandbox Code Playgroud)

如果速度不是一个问题,这将是一个非常简单的问题,这就是为什么我在这里问伟大的思想:)

Ósc*_*pez 10

您可以通过两个步骤解决此问题:

  1. 创建一个计数器对象 - Map<String, Integer>每个字符串列出它在输入中出现的次数:换句话说,它是一个频率图.这是O(n)因为您只需要遍历输入一次以构建地图

  2. 使用上一个映射,使用其键创建一个列表,使用项目的频率(映射中的值)作为排序条件进行排序.这是O(n log n),你可以调用Collections.sort(),以Comparator使用串频的比较

这就是我的意思:

String[] stringArray = {"x", "y", "z", "x", "x", "y", "a"};

final Map<String, Integer> counter = new HashMap<String, Integer>();
for (String str : stringArray)
    counter.put(str, 1 + (counter.containsKey(str) ? counter.get(str) : 0));

List<String> list = new ArrayList<String>(counter.keySet());
Collections.sort(list, new Comparator<String>() {
    @Override
    public int compare(String x, String y) {
        return counter.get(y) - counter.get(x);
    }
});
Run Code Online (Sandbox Code Playgroud)

执行上述代码后,变量list将包含以下值(未指定相同频率的元素之间的顺序):

[x, y, a, z]
Run Code Online (Sandbox Code Playgroud)

将列表转换为数组是微不足道的:

list.toArray(new String[list.size()])
Run Code Online (Sandbox Code Playgroud)

如果你需要找出每个字符串的频率,只需遍历排序的键:

for (String str : list) {
    int frequency = counter.get(str);
    System.out.print(str + ":" + frequency + ", ");
}
Run Code Online (Sandbox Code Playgroud)