Arrays. sort 소스 코드 분석
10825 단어 자바
(이 소스 코드 는 JDK 1.8 버 전 을 기반 으로 낮은 버 전과 큰 차이 가 있 음)
1. Arrays. sort 방법 안내
Sorts the specified range of the specified array of objects according to the order induced by the specified comparator.
The range to be sorted extends from index fromIndex, inclusive, to index toIndex, exclusive.
(If fromIndex==toIndex, the range to be sorted is empty.)
All elements in the range must be mutually comparable by the specified comparator
(that is, c.compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the range).
This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.
Implementation note: This implementation is a stable, adaptive,
iterative mergesort that requires far fewer than n lg(n) comparisons when the input array is partially sorted,
while offering the performance of a traditional mergesort when the input array is randomly ordered.
If the input array is nearly sorted, the implementation requires approximately( ; ) n comparisons.
Temporary storage requirements vary from a small constant for nearly sorted input arrays to n/2 object references for randomly ordered input arrays.
The implementation takes equal advantage of ascending and descending order in its input array,
and can take advantage of ascending and descending order in different parts of the the same input array.
It is well-suited to merging two or more sorted arrays: simply concatenate the arrays and sort the resulting array.
이상 은 대체적으로 다음 과 같은 몇 가지 정 보 를 말 했다.
1. 정렬 된 요 소 는 Comparable 인 터 페 이 스 를 실현 해 야 합 니 다. 프로그램 에서 compare 방법 을 실행 할 때 ClassCastException 이상 을 해 서 는 안 됩 니 다.
2. 같은 요 소 는 정렬 작업 을 하지 않 습 니 다.
3. 방법 에서 병합 정렬 방식 으로 정렬 했 습 니 다. 배열 의 일부 질서 있 는 상 태 는 nlg (n) 차 비교 가 필요 합 니 다.
4. 배열 의 데이터 가 기본적으로 질서 있 는 상태 에 있 을 때 n 번 정도 비교 해 야 합 니 다.
2. 소스 코드 해독
2.1 입구 방법 sort
public static void sort(T[] a, int fromIndex, int toIndex, Comparator super T> c) {
//
if (c == null) {
sort(a, fromIndex, toIndex);
} else {
rangeCheck(a.length, fromIndex, toIndex);
// ,LegacyMergeSort 1.8 , ,
// ,
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex, c);
else
//
TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
}
}
2.2 Comparator 가 설정 되 어 있 지 않 음
public static void sort(Object[] a, int fromIndex, int toIndex) {
//
rangeCheck(a.length, fromIndex, toIndex);
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex);
else
ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
}
// , ,
private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException(
"fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
}
if (fromIndex < 0) {
throw new ArrayIndexOutOfBoundsException(fromIndex);
}
if (toIndex > arrayLength) {
throw new ArrayIndexOutOfBoundsException(toIndex);
}
}
sort 방법 을 통 해 알 수 있 듯 이 사용자 정의 Comparator 가 지정 되 지 않 았 을 때 실제 ComparableTimsert 방법 을 실행 하 는 정적 방법 입 니 다. 다음 과 같은 방법 으로 구체 적 으로 어떤 일 을 했 는 지 살 펴 보 겠 습 니 다.
static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
// ,assert
assert a != null && lo >= 0 && lo <= hi && hi <= a.length;
//
int nRemaining = hi - lo;
// 2, ,
if (nRemaining < 2)
return; // Arrays of size 0 and 1 are always sorted
// If array is small, do a "mini-TimSort" with no merges
// ,MIN_MERGE=32, ,
// ,
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, work, workBase, workLen);
// , , 32 , ,
// 16 <= k <= 32
int minRun = minRunLength(nRemaining);
do {
// Identify next run
//
int runLen = countRunAndMakeAscending(a, lo, hi);
// If run is short, extend to min(minRun, nRemaining)
// ? , ,
// runLen == mainRun ,
if (runLen < minRun) {
int force = nRemaining <= minRun ? nRemaining : minRun;
// , ,lo ,force , lo+runLen
// lo + force ,
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;
}
다음은 프로그램 에서 질서 있 는 하위 배열 의 길 이 를 어떻게 판단 하 는 지 살 펴 보 겠 습 니 다.
/**
* lo:
* hi:
*/
private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
assert lo < hi;
int runHi = lo + 1;
if (runHi == hi)
return 1;
// Find end of run, and reverse range if descending
// , Comparator , Comparable
// comparaTo , comparable
// lo + 1 , lo + 1 , ,
// ,
if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending
while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)
runHi++;
//
reverseRange(a, lo, runHi);
} else { // Ascending
while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0)
runHi++;
}
// - ,
return runHi - lo;
}
위의 방법 에서 주로 두 가 지 를 실현 했다.
1. 아래 표 시 를 시작 할 때 정렬 해 야 할 배열 을 검색 합 니 다. 내림차 순 으로 배열 하면 질서 있 는 하위 배열 이 끝 날 때의 아래 표 시 를 runHi + + 로 계산 하고 내림차 순 하위 배열 을 오름차 순 으로 반전 합 니 다.
2. 오름차 서브 배열 이 라면 질서 있 는 부분 끝 요소 의 아래 표 시 를 계산 합 니 다.
다음은 반전 의 실현 을 간단하게 살 펴 보 자.
private static void reverseRange(Object[] a, int lo, int hi) {
hi--;
while (lo < hi) {
Object t = a[lo];
a[lo++] = a[hi];
a[hi--] = t;
}
}
원본 코드 를 보면 배열 의 요소 의 앞 뒤 를 교환 하여 이 루어 진 다 는 것 을 알 수 있 습 니 다.
마지막 으로 정렬 을 실현 하 는 방법 으로 소스 코드 를 실현 하 는 것 이다.
/**
* a:
* lo:
* hi:
* start:
*/
private static void binarySort(Object[] a, int lo, int hi, int start) {
assert lo <= start && start <= hi;
if (start == lo)
start++;
for ( ; start < hi; start++) {
//
Comparable pivot = (Comparable) a[start];
// Set left (and right) to the index where a[start] (pivot) belongs
//
int left = lo;
//
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left).
* pivot < all in [right, start).
*/
// , pivot
//
while (left < right) {
// , left right ,
// (left + right) / 2
int mid = (left + right) >>> 1;
// ,
// pivot , right
// ? start , ,
// ,
if (pivot.compareTo(a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
assert left == right;
/*
* The invariants still hold: pivot >= all in [lo, left) and
* pivot < all in [left, start), so pivot belongs at left. Note
* that if there are elements equal to pivot, left points to the
* first slot after them -- that's why this sort is stable.
* Slide elements over to make room for pivot.
*/
int n = start - left; // The number of elements to move
// Switch is just an optimization for arraycopy in default case
switch (n) {
case 2: a[left + 2] = a[left + 1];
case 1: a[left + 1] = a[left];
break;
default: System.arraycopy(a, left, a, left + 1, n);
}
a[left] = pivot;
}
}
요약:
1. 배열 길이 < 32 비트 시 정렬
2. 배열 길이 > 32 시 계 산 된 세그먼트 배열 길이 에 따라 배열 을 작은 블록 으로 나 눈 다음 작은 블록 마다 정렬 을 마 친 후 결 과 를 합 친다.
이상 은 단지 나의 개인 적 인 견해 일 뿐 이 니, 비판 과 지적 을 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.