在使用jdk1.7后发现,部分使用排序的列表变了。然后就可劲的找原因。最后发现:
首先进入Collection.sort方法
public static <T extends Comparable<? super T>> void sort(List<T> list) { Object[] a = list.toArray(); Arrays.sort(a); ListIterator<T> i = list.listIterator(); for (int j=0; j<a.length; j++) { i.next(); i.set((T)a[j]); } }
本质就是对数组进行排序然后输出。
再进入Arrays.sort()方法
public static void sort(Object[] a) { if (LegacyMergeSort.userRequested) legacyMergeSort(a); else ComparableTimSort.sort(a); }
看到这,其实也里看到点东西了,哈哈userRequested,再点进去
static final class LegacyMergeSort { private static final boolean userRequested = java.security.AccessController.doPrivileged( new sun.security.action.GetBooleanAction( "java.util.Arrays.useLegacyMergeSort")).booleanValue(); }
原来如此,在JVM中配置-Djava.util.Arrays.useLegacyMergeSort=true ,就可以使用传统的归并排序了。
到此为止,已经解决为什么JDK1.7的排序会与JDK1.6不致的问题的。下面我们来深入的看下这两个排序方式的迥异:
legacyMergeSort()核心实现
private static void mergeSort(Object[] src, Object[] dest, int low, int high, int off) { int length = high - low; // Insertion sort on smallest arrays if (length < INSERTIONSORT_THRESHOLD) { for (int i=low; i<high; i++) for (int j=i; j>low && ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--) swap(dest, j, j-1); return; } // Recursively sort halves of dest into src int destLow = low; int destHigh = high; low += off; high += off; int mid = (low + high) >>> 1; mergeSort(dest, src, low, mid, -off); mergeSort(dest, src, mid, high, -off); // If list is already sorted, just copy from src to dest. This is an // optimization that results in faster sorts for nearly ordered lists. if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) { System.arraycopy(src, low, dest, destLow, length); return; } // Merge sorted halves (now in src) into dest for(int i = destLow, p = low, q = mid; i < destHigh; i++) { if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0) dest[i] = src[p++]; else dest[i] = src[q++]; } }
排序个数小于7,直接使用插入排序,时间复杂度为O(n2),适用于小数据排序。其它部分典型的归并排序实现法。不过人家写的确实高效率 int mid = (low + high) >>> 1; 给我们肯定直接就成了int mid=(low+high)/2;
ComparableTimSort.sort(a)核心实现
rangeCheck(a.length, lo, hi); int nRemaining = hi - lo; if (nRemaining < 2) return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges if (nRemaining < MIN_MERGE) { int initRunLen = countRunAndMakeAscending(a, lo, hi); binarySort(a, lo, hi, lo + initRunLen); return; } /** * March over the array once, left to right, finding natural runs, * extending short natural runs to minRun elements, and merging runs * to maintain stack invariant. */ ComparableTimSort ts = new ComparableTimSort(a); int minRun = minRunLength(nRemaining); do { // Identify next run int runLen = countRunAndMakeAscending(a, lo, hi); // If run is short, extend to min(minRun, nRemaining) if (runLen < minRun) { int force = nRemaining <= minRun ? nRemaining : minRun; binarySort(a, lo, lo + force, lo + runLen); runLen = force; } // Push run onto pending-run stack, and maybe merge ts.pushRun(lo, runLen); ts.mergeCollapse(); // Advance to find next run lo += runLen; nRemaining -= runLen; } while (nRemaining != 0); // Merge all remaining runs to complete sort assert lo == hi; ts.mergeForceCollapse(); assert ts.stackSize == 1;
ComparableTimSort来源于GOOGLE,详见下文
两个对象直接比如定义Comparator
public double compare(Object o1, Object o2) { ComparaContainer tr1 = (ComparaContainer) o1; ComparaContainer tr2 = (ComparaContainer) o2; if (tr1.getCompareValue() < tr2.getCompareValue()) { return (tr1.getCompareValue()-tr2.getCompareValue()); } else if (tr1.getCompareValue() == tr2.getCompareValue()) { return tr1.getSecondValue() <= tr2.getSecondValue() ? 0 : 1; } else { return 1; } }
由于1.7改得更为严谨不能直接使用-1,0,1来表示小于、等于、大于
得改用a-b
如下所示
public int compare(Object o1, Object o2) { ComparaContainer tr1 = (ComparaContainer) o1; ComparaContainer tr2 = (ComparaContainer) o2; double m = tr1.getCompareValue()-tr2.getCompareValue(); if (tr1.getCompareValue() < tr2.getCompareValue()) { return (int)m; } else if (tr1.getCompareValue() == tr2.getCompareValue()) { m = tr1.getSecondValue()- tr2.getSecondValue(); return (int)m; } else { return (int)m; } }
或者最简单的是将原来return 0;的改成return -1;
相关推荐
在Java编程语言中,对包含中文、数字和字母的数据进行排序是一项常见的任务。这个场景下,我们关注的是如何实现一个自定义的排序规则,按照数字、字母和汉字的顺序进行排列。以下是对这一主题的详细解释。 首先,...
Java ip 地址排序Java ip 地址排序Java ip 地址排序Java ip 地址排序
java冒泡排序代码,亲测能用,控制台输入数据,自动排序
### Java 中文姓氏排序详解 #### 一、引言 在处理中文数据时,我们经常需要对含有中文姓名的数据进行排序。Java 提供了多种方式进行排序,包括使用 `Collections.sort()` 方法配合自定义比较器(`Comparator`)。...
Java基础知识: 冒泡排序详解,简单而详细的讲清楚了,什么是冒泡排序。 冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。 它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如...
在Java编程语言中,数组排序是一项基础且重要的任务。它涉及到不同的算法,这些算法通过比较和交换元素来达到数组元素的有序状态。本篇将详细探讨几种常见的排序算法及其在Java中的实现。 首先,让我们从最简单的...
本文将介绍两种常见的排序算法:直接插入排序和希尔排序,并通过Java代码实现来帮助理解。 1. 直接插入排序(直接插入排序) 直接插入排序是一种简单的排序方法,它的工作原理类似于我们平时手动整理扑克牌。在排序...
总结起来,`Collections.sort()`是Java中对List进行排序的标准工具,它支持自然排序和自定义排序。了解其工作原理和优化技巧,可以帮助我们在编程实践中更高效地处理数据。通过阅读和理解`Collections.sort()`的源码...
7. **对比其他排序算法** - 相比于快速排序、归并排序或堆排序等高效算法,选择排序在大多数情况下效率较低,但在最坏、最好和平均情况下,时间复杂度都是O(n^2)。 - 与其他简单的排序算法如冒泡排序相比,选择...
以上三个知识点总结了关于 Java 排序的一些基本应用,包括基础的冒泡排序算法、使用标准库 `Collections.sort()` 进行排序以及使用 `RuleBasedCollator` 实现国际化排序等。这些技术对于编写高效、可维护的 Java ...
7. 计数排序(Counting Sort) 计数排序不是基于比较的排序,它适用于非负整数排序,通过统计每个数字出现的次数,直接确定每个数字在输出序列的位置。时间复杂度为O(n + k),其中k为整数范围。 8. 桶排序(Bucket ...
下面我们将深入探讨如何在Java中实现集合的分组与排序。 1. **集合分组**: 集合分组通常涉及到`GroupingBy`操作,这在Java 8引入的流(Stream)API中得到了很好的支持。`Collectors.groupingBy`方法允许我们将...
根据提供的文件信息,我们可以归纳出以下关于Java排序的相关知识点: ### 一、文件基本信息 - **文件名**:`java排序.txt` - **文件描述**:该文本文件主要介绍了几种常用的Java排序算法,并通过示例代码展示了...
堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆排序7.java 使用java实现的堆排序堆...
在Java编程语言中,有多种排序算法可供使用。这里我们将探讨三种基本的排序算法:冒泡排序、选择排序和插入排序。这些算法都是基于数组的简单排序方法,适合理解排序的基本原理。 首先,我们来看冒泡排序。冒泡排序...
7. 计数排序(Counting Sort)、桶排序(Bucket Sort)和基数排序(Radix Sort): 这些排序算法适用于特定类型的数据,例如非负整数。计数排序统计每个元素出现的次数,桶排序将元素分布到多个桶中,基数排序则根据...
在Java中实现选择排序,我们通常会用到数组这一数据结构。 首先,我们要理解Java中的数组。数组是一种线性数据结构,它将相同类型的元素存储在连续的内存位置中,通过索引来访问这些元素。在Java中,声明数组时需要...
java中数组的自定义排序,种类繁多,简单实现,可自由操控。