繁体   English   中英

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

[英]How to sort Enums by Counting Sort?

例如,我要对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 ),则可以使用时间O (n)计数排序 有没有一种标准的机制可以在javaEnums使用计数排序?

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


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

一个明显的答案是:不要。

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

有两种情况:

  • n太大,以至于差异很重要。 这意味着n可能是一个非常大的数字。 然后,你所面对的,你应该首先着眼于其他更重要的方面一卡车 因为那样 “处理链”中的一步都很重要。 在这种情况下,您必须仔细查看每个步骤,并确定如何对其进行优化(而且很可能,您必须先进行测量,然后才能应用能够发挥作用的优化)
  • n太小了……uups: n很小。 这意味着我们首先是在谈论“少于毫秒”。

长话短说:这听起来像是典型的过早优化。 然后唯一有效的答案是:专注于编写干净,优雅的代码以完成工作。 然后使用真实数据进行测量 然后确定是否需要采取进一步的措施(大多数情况下:不需要)。

好的,没有讨论我们应该使用O(n)还是O(nlogn)就足够了。 无论如何,可能您可以实现自定义counting sort算法? (我不记得我知道的任何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