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

时间:2018-01-23 09:49:02

标签: java algorithm sorting enums

例如,我想对Enum进行排序。我有一个密钥为Enum

的对象

已更新

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;
    }

}

排序Arrays.sort使用TimSortMergeSort平均O (n log n)投放。但是如果我们使用有限数量的常量(Enums),我们可以及时使用counting sort O (n)。是否有一种标准机制可以对Enums中的java使用计数排序?

3 个答案:

答案 0 :(得分:1)

如果您事先知道常量的顺序,可以使用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);
} 

这种方法的复杂性平均为O(n)

在问题的更新版本中,您询问pigeonhole sort。它类似于计数排序,但有自己的名称。我们需要在上面的算法中进行一些更改。首先,我们需要将HashMap<MyEnum, Integer>替换为HashMap<MyEnum, List<Bean>>,并将所有Bean个对象存储在相应的列表中。然后在迭代输入之后,我们需要以指定的顺序连接所有列表。

答案 1 :(得分:0)

这里有一个独特的答案:不要。

不要担心O(n)vs O(n * log(n))。担心编写可随时间维护和增强的人类可读代码。

有两种情况:

  • n 太大了,差异很重要。这意味着 n 可能是真正大数字。然后,您将面对卡车装载其他更重要的方面,您应该首先关注。因为“处理链”中的每个和任何步骤都很重要。在这种情况下,您必须仔细查看每个步骤,并确定如何对其进行优化(最有可能的是,您必须先执行度量才能应用有所作为的优化)
  • n 太小了...... uups: n 很小。这意味着我们首先谈论的是“不到毫秒”。

长话短说:这听起来像是典型的早熟优化。然后唯一有效的答案是:专注于编写干净,优雅的代码来完成工作。然后用实际数据测量。然后决定是否需要采取进一步行动(而且大部分时间:不是)。

答案 2 :(得分:0)

好的,没有讨论我们应该使用O(n)还是O(nlogn)就足够了。无论如何,可能你可以实现自定义counting sort算法? (我不记得我认识的任何文库都有这个):

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;
}