我正在使用
在ArrayList中排序100万个字符串(每个字符串50个字符)final Comparator comparator= new Comparator<String>() {
public int compare(String s1, String s2) {
if (s2 == null || s1 == null)
return 0;
return s1.compareTo(s2);
}
};
Collections.Sort(list,comparator);
平均时间为:1300毫升
如何加快速度?
答案 0 :(得分:4)
如果您使用的是Java 6或更低版本,则可以通过切换到Java 7来获得加速。在Java 7中,他们将排序算法更改为TimSort,在某些情况下表现更好(特别是works well with partially sorted input) 。 Java 6及以下used MergeSort。
但是我们假设您使用的是Java 6.我尝试了三个版本:
Collections.sort():重复运行您提供的比较器在我的机器上执行 3.0秒(包括读取1,000,000个随机生成的小写ascii字符串的输入)
基数排序:其他答案建议Radix sort。我尝试了以下代码(假设字符串的长度都相同,只有小写的ascii):
String [] A = list.toArray(new String[0]);
for(int i = stringLength - 1; i >=0; i--) {
int[] buckets = new int[26];
int[] starts = new int[26];
for (int k = 0 ; k < A.length;k++) {
buckets[A[k].charAt(i) - 'a']++;
}
for(int k = 1; k < buckets.length;k++) {
starts[k] = buckets[k -1] + starts[k-1];
}
String [] temp = new String[A.length];
for(int k = 0; k < A.length; k++) {
temp[starts[A[k].charAt(i) - 'a']] = A[k];
starts[A[k].charAt(i) - 'a']++;
}
A = temp;
}
我的机器上需要 29.0秒才能完成。我不认为这是为这个问题实现基数排序的最佳方法 - 例如,如果你做了一个最重要的数字排序,那么你可以提前终止唯一的前缀。而使用就地排序也会有一些好处(关于这一点有一个很好的引用 - “The troubles with radix sort are in implementation, not in conception”)。我想写一个更好的基于基数排序的解决方案,这样做 - 如果我有时间,我会更新我的答案。
Bucket Sort:我还实施了Peter Lawrey的bucket sort解决方案的略微修改版本。这是代码:
Map<Integer, List<String>> buckets = new TreeMap<Integer,List<String>>();
for(String s : l) {
int key = s.charAt(0) * 256 + s.charAt(1);
List<String> list = buckets.get(key);
if(list == null) buckets.put(key, list = new ArrayList<String>());
list.add(s);
}
l.clear();
for(List<String> list: buckets.values()) {
Collections.sort(list);
l.addAll(list);
}
在我的机器上完成 2.5秒。我相信这次胜利来自于分区。
因此,如果切换到Java 7的TimSort对您没有帮助,那么我建议对数据进行分区(使用bucket sort之类的东西)。如果您需要更好的性能,那么您还可以多线程处理分区。
答案 1 :(得分:2)
你没有指定你使用的排序算法比其他算法更快(快速/合并与泡沫) 此外,如果您在多核/多处理器计算机上运行,您可以在多个线程之间划分排序(再次具体取决于排序算法,但here's示例)
答案 2 :(得分:2)
您可以对前两个字符使用基数排序。如果你前两个字符是独特的,你可以使用类似的东西。
List<String> strings =
Map<Integer, List<String>> radixSort =
for(String s: strings) {
int key = (s.charAt(0) << 16) + s.charAt(1);
List<String> list = radixSort.get(key);
if(list == null) radixSort.put(key, list = new ArrayList<String>());
list.add(s);
}
strings.clear();
for(List<String> list: new TreeMap<Integer, List<String>>(radixSort).values()) {
Collections.sort(list);
strings.addAll(list);
}