Java의 Arrays.sort 메소드가 다른 유형에 대해 두 가지 다른 정렬 알고리즘을 사용하는 이유는 무엇입니까?


121

Java 6의 Arrays.sort방법은 기본 배열에 Quicksort를 사용하고 객체 배열에 병합 정렬을 사용합니다. 대부분의 경우 Quicksort가 병합 정렬보다 빠르며 메모리 비용이 적게 든다고 생각합니다. 내 실험은 두 알고리즘이 모두 O (n log (n))이지만이를 지원합니다. 그렇다면 왜 다른 유형에 다른 알고리즘이 사용됩니까?


14
Quicksort 최악의 경우는 NlogN이 아닌 N ^ 2입니다.
codaddict

잠깐, Integers 또는 무언가 의 배열이 있으면 어떻게됩니까 ?
Tikhon Jelvis

1
이것은 당신이 읽은 소스에 설명 되어 있지 않습니까?
Humphrey Bogart

5
이 정보는 더 이상 최신 정보가 아닙니다. 자바 SE 7의 시작, 머지 소트는 대체되었습니다 TimSort 그리고 이것은 QuickSort로 대체 된 듀얼 피벗 이것은 QuickSort . Java API 문서에 대한 링크는 아래 내 대답을 참조하십시오.
Will Byrne 2015 년

답변:


200

가장 가능성이 높은 이유 : 퀵 정렬이 안정적 이지 않습니다 . 즉, 동일한 항목이 정렬 중에 상대 위치를 변경할 수 있습니다. 무엇보다도 이것은 이미 정렬 된 배열을 정렬하는 경우 변경되지 않을 수 있음을 의미합니다.

기본 유형에는 ID가 없기 때문에 (동일한 값을 가진 두 개의 정수를 구별 할 방법이 없음) 이것은 중요하지 않습니다. 그러나 참조 유형의 경우 일부 응용 프로그램에서 문제가 발생할 수 있습니다. 따라서 안정적인 병합 정렬이 사용됩니다.

OTOH, 기본 유형에 대해 (보장 된 n * log (n)) 안정적인 병합 정렬을 사용하지 않는 이유는 배열의 복제본을 만들어야하기 때문일 수 있습니다. 참조 된 객체가 일반적으로 참조 배열보다 훨씬 더 많은 메모리를 차지하는 참조 유형의 경우 일반적으로 중요하지 않습니다. 그러나 원시 유형의 경우 배열을 완전히 복제하면 메모리 사용량이 두 배가됩니다.


1
quicksort를 사용하는 또 다른 이유는 평균적으로 quicksort가 mergesort보다 빠르기 때문입니다. quicksort는 mergesort보다 더 많은 비교를 수행하지만 배열 액세스는 훨씬 적습니다. 입력에 실제 응용 프로그램에서 드문 일이 아닌 많은 중복 항목이 포함 된 경우 3 방향 퀵 정렬도 선형 시간을 달성 할 수 있습니다 (제 생각에는 이중 피벗 퀵 정렬에도이 속성이 있습니다).
Jingguo Yao

이 배열을 복제하지 않는 원시 유형의 내가 유일한 이유는 기본적으로 안정성 계약, 생각, 그래서 그것은 ..., 장소에 정렬 할 수 있습니다
rogerdpack

27

에 인용 된 자바 7 API 문서에 따르면 이 답변 , Arrays#Sort()객체 배열 지금 사용 TimSort 머지 소트과 삽입 정렬의 하이브리드입니다. 반면, Arrays#sort()기본 배열의 경우 이제 Dual-Pivot QuickSort를 사용 합니다. 이러한 변경 사항은 Java SE 7부터 구현되었습니다.


2
두 가지 다른 알고리즘이 선택된 이유는 답이 아닙니다.
알렉산드르

12

내가 생각할 수있는 한 가지 이유는 quicksort가 O ( n ^ 2 ) 의 최악의 경우 시간 복잡도를 갖는 반면 mergesort는 O ( n log n ) 의 최악의 경우 시간을 유지 한다는 것입니다 . 객체 배열의 경우 퀵 정렬이 최악의 경우 인 중복 객체 참조가 여러 개있을 것으로 예상됩니다.

다양한 알고리즘에 대한 적절한 시각적 비교 가 있으며 다른 알고리즘에 대한 맨 오른쪽 그래프에 특히주의하십시오.


2
Java quicksort는 수정 된 Quicksort로 O (n ^ 2)로 저하되지 않습니다. "이 알고리즘은 많은 데이터 세트에서 n * log (n) 성능을 제공하여 다른
Quicksort

7

저는 알고리즘에 대한 Coursera 수업을 듣고 있었고 Bob Sedgewick 교수 강의에서 Java 시스템 정렬에 대한 평가를 언급했습니다.

"프로그래머가 객체를 사용하는 경우 공간은 매우 중요한 고려 사항이 아니며 병합 정렬에 사용되는 추가 공간은 문제가 아닐 수 있습니다. 프로그래머가 기본 유형을 사용하는 경우 성능이 가장 중요한 요소이므로 사용할 수 있습니다. 빠른 정렬. "


4
주된 이유가 아닙니다. 그 문장 바로 뒤에 "왜 참조 유형에 MergeSort가 사용됩니까?"라는 질문이 비디오에 삽입되었습니다. (안정적이기 때문에). 나는 Sedgewick이 그것을 질문하기 위해 비디오에서 언급하지 않았다고 생각합니다.
likern

1

java.util.ArraysComparable 을 구현 하거나 Comparator를 사용하는 객체에 대해 int 및 mergesort 와 같은 기본 유형에 대해 quicksort 를 사용합니다 . 두 가지 다른 방법을 사용하는 아이디어는 프로그래머가 객체를 사용하는 경우 공간이 매우 중요한 고려 사항이 아니므로 병합 정렬에 사용되는 추가 공간 이 문제가되지 않을 수 있고 프로그래머가 기본 유형을 사용하는 경우 성능이 가장 중요한 것일 수 있으므로 사용하십시오 .

예 : 이것은 정렬 안정성이 중요한 경우의 예입니다.

여기에 이미지 설명 입력

그렇기 때문에 안정적인 정렬이 객체 유형, 특히 정렬 키보다 더 많은 데이터가있는 변경 가능한 객체 유형 및 객체 유형에 대해 의미가 있으며 mergesort가 그러한 정렬입니다. 그러나 원시 유형의 경우 안정성은 관련성이 없을뿐만 아니라 무의미합니다.

출처 : 정보


0

Java의 Arrays.sort방법은 빠른 정렬, 삽입 정렬 및 병합 정렬을 사용합니다. OpenJDK 코드에 구현 된 단일 및 이중 피벗 퀵소트도 있습니다. 가장 빠른 정렬 알고리즘은 상황에 따라 다르며 승자는 작은 배열에 대한 삽입 정렬 (현재 선택한 47 개), 대부분 정렬 된 배열에 대한 병합 정렬, 나머지 배열에 대한 빠른 정렬이므로 Java의 Array.sort ()는 최상의 알고리즘을 선택하려고합니다. 해당 기준에 따라 적용됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.