简体   繁体   English

如何通过计数排序对枚举进行排序?

[英]How to sort Enums by Counting Sort?

For example, I want to sort Enum. 例如,我要对Enum进行排序。 And I have an object with key as Enum 我有一个键为Enum的对象

UPDATED 更新

public class Main {

    public static void main(String[] args) throws Exception {

        Bean[] mass = new Bean[] { new Bean(new Object(), A), new Bean(new Object(), C), new Bean(new Object(), D),
                new Bean(new Object(), B), new Bean(new Object(), A) }; // 1, 3, 4, 2, 1
        Arrays.sort(mass, new EnumComparator());
        System.out.println(Arrays.toString(mass)); //[1, 1, 2, 3, 4]

    }
}

class EnumComparator implements Comparator<Bean> {

    @Override
    public int compare(Bean o1, Bean o2) {
        return o1.key.toString().compareTo(o2.key.toString());
    }

}

class Bean {
    public Object data;
    public Enum key;

    public Bean(Object data, Enum key) {
        super();
        this.data = data;
        this.key = key;
    }

    @Override
    public String toString() {
        return key.toString();
    }

}

enum MyEnum {

    D("4"),
    A("1"),
    B("2"),
    C("3");

    private String index;

    private MyEnum(String index) {
        this.index = index;
    }

    @Override
    public String toString() {
        return index;
    }

}

Sorting Arrays.sort uses TimSort or MergeSort to run on average O (n log n) . 排序Arrays.sort使用TimSortMergeSort到平均运行O (n log n) But if we use a finite number of constants ( Enums ), we can use the counting sort in time O (n) . 但是,如果我们使用有限数量的常量( Enums ),则可以使用时间O (n)计数排序 Is there a standard mechanism for using counting sort for Enums in java ? 有没有一种标准的机制可以在javaEnums使用计数排序?

If you know the order of the constants in advance you can use a HashMap to implement a counting sort: 如果事先知道常量的顺序,则可以使用HashMap来实现计数排序:

List<MyEnum> countingSort(MyEnum order[], List<MyEnum> input) {
    HashMap<MyEnum, Integer> countMap = new HashMap<>();
    for (MyEnum obj : input) {
        countMap.put(obj, countMap.getOrDefault(obj, 0) + 1);
    }

    List<MyEnum> result = new ArrayList<>();
    for (MyEnum obj : order) {
        for (int i = 0; i < countMap.getOrDefault(obj, 0); ++i) {
            result.add(obj);
        }
    }

    return result;
}

public static void main (String[] args) {   
    MyEnum order[] = {A, B, C, D};
    List<MyEnum> input = Arrays.asList(D, C, A, B, D, D, B, A, A, C, D);
    List<MyEnum> res = countingSort(order, input);
} 

The complexity of this approach is O(n) in average. 这种方法的复杂度平均为O(n)


In the updated version of the question, you are asking about pigeonhole sort . 在问题的更新版本中,您正在询问鸽孔排序 It is similar to counting sort but has its own name. 它类似于计数排序,但有其自己的名称。 We need several changes in the algorithm above. 我们需要对上述算法进行一些更改。 First, we need to replace a HashMap<MyEnum, Integer> with HashMap<MyEnum, List<Bean>> , and store all Bean objects in the corresponding lists. 首先,我们需要将HashMap<MyEnum, Integer>替换为HashMap<MyEnum, Integer> HashMap<MyEnum, List<Bean>> ,并将所有Bean对象存储在相应的列表中。 Then after iteration through the input, we need to join all that lists in the specified order. 然后,在迭代输入之后,我们需要以指定顺序连接所有列表。

A distinct non answer here: don't. 一个明显的答案是:不要。

Do not worry about O(n) vs O(n*log(n)). 不用担心O(n)vs O(n * log(n))。 Worry about writing human readable code that can be maintained and enhanced over time. 担心编写随时间可以维护和增强的人类可读代码。

There are two cases: 有两种情况:

  • n is so large that the difference matters. n太大,以至于差异很重要。 This means that n is probably a really large number. 这意味着n可能是一个非常大的数字。 Then you are facing a truck load of other, more important aspects you should first focus on. 然后,你所面对的,你应该首先着眼于其他更重要的方面一卡车 Because then each and any step in your "processing chain" matters. 因为那样 “处理链”中的一步都很重要。 In such cases, you have to carefully look at each step, and determine how to optimize it (and most likely, you have to do measurements prior being able to apply optimizations that make a difference) 在这种情况下,您必须仔细查看每个步骤,并确定如何对其进行优化(而且很可能,您必须先进行测量,然后才能应用能够发挥作用的优化)
  • n is so small that ... uups: n is small. n太小了……uups: n很小。 Meaning we are talking about "less than milli seconds" in the first place. 这意味着我们首先是在谈论“少于毫秒”。

Long story short: this sounds like a typical pre-mature optimisation. 长话短说:这听起来像是典型的过早优化。 And then the only valid answer is: focus on writing clean, elegant code that gets the job done. 然后唯一有效的答案是:专注于编写干净,优雅的代码以完成工作。 Then measure with real data. 然后使用真实数据进行测量 And then decide if further action is required (and most of times: it is not). 然后确定是否需要采取进一步的措施(大多数情况下:不需要)。

Ok, no discussing about should we use O(n) or O(nlogn) is enough. 好的,没有讨论我们应该使用O(n)还是O(nlogn)就足够了。 Anyway, probably you could implement custom counting sort algorithm? 无论如何,可能您可以实现自定义counting sort算法? (I do not remember that any lib I know have this): (我不记得我知道的任何lib都有这个):

private static void countSort(Bean[] mass) {
    List<Bean>[] arr = (List<Bean>[])new List[MyEnum.values().length];

    for (Bean bean : mass) {
        int pos = Integer.parseInt(bean.key.getIndex()) - 1;

        if (arr[pos] == null)
            arr[pos] = new ArrayList<>();

        arr[pos].add(bean);
    }

    int i = 0;

    for (List<Bean> beans : arr)
        for (Bean bean : beans)
            mass[i++] = bean;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM