특정 정렬 알고리즘은 어떤 조건에서 실제로 가장 빠른 알고리즘입니까?
Θ(log(n)2)Θ(n⋅log(n)2)
Θ(n⋅k)Θ(n⋅m)k=2#number_of_Possible_valuesm=#maximum_length_of_keys
3) 기본 데이터 구조가 연결된 요소로 구성되어 있습니까? 예-> 항상 병합 정렬을 사용합니다. 링크 된 데이터 구조에 대해 서로 다른 종류의 병합 된 종류의 병합 된 고정 크기 또는 적응 형 (일명 자연) 상향식을 쉽게 구현할 수 있으며 각 단계에서 전체 데이터를 복사 할 필요가 없으며 재귀가 필요하지 않기 때문에 다른 일반적인 비교 기반 정렬보다 빠르며 빠른 정렬보다 빠릅니다.
4) 분류가 안정적이어야합니까? 예-> 임의의 정렬을 안정화하는 것처럼 빠른 정렬이 선호되는 경우에도 기본 데이터 구조 및 예상되는 데이터의 종류에 따라 적절한 크기 또는 적응 형 병합 정렬을 사용합니다. 알고리즘은 원래 인덱스로 구성된 최악의 경우 추가 메모리를 필요로하며, 입력 데이터에 대해 수행 될 각 스왑과도 동기화 상태를 유지해야합니다. 병합 정렬이 차단되었을 수 있습니다.Θ(n)
5) 기본 데이터의 크기를 중소 규모로 묶을 수 있습니까? 예 : n <10,000 ... 100,000,000 (기본 아키텍처 및 데이터 구조에 따라 다름)입니까? 예-> 비 토닉 정렬 또는 배처 홀수-짝 병합을 사용하십시오. 고토 1)
6) 다른 메모리 를 절약 할 수 있습니까 ? 예-> a) 입력 데이터가 이미 정렬 된 대량의 순차적 데이터로 구성되어 있습니까? -> 적응 형 (일명 자연) 병합 정렬 또는 팀 정렬 사용 예-> b) 입력 데이터가 대부분 올바른 위치에있는 요소로 구성되어 있습니까? -> 버블 정렬 또는 삽입 정렬을 사용하십시오. 당신이 그들의 두려워하는 경우 (거의 정렬 된 데이터에 대한 병적 인) 시간의 복잡성을, 어쩌면 간격의 (거의) 점근 적으로 최적의 순서와 종류의 쉘로 전환을 고려, 일부 시퀀스 산출하는 최악의 경우 런타임이 알려져 있거나 콤 정렬을 시도해보십시오. 셸 정렬 또는 빗 정렬이 실제로 제대로 수행되는지 확실하지 않습니다.Θ(n)Θ(n2)Θ(n⋅log(n)2)
아니오-> 7) 다른 메모리 를 절약 할 수 있습니까 ? 예-> a) 신뢰할 수없는 데이터 구조가 순차적 순차 액세스를 허용합니까? 예-> 데이터 끝에 도달 할 때까지 한 번에 하나의 읽기 / 쓰기 액세스 시퀀스 만 허용합니까 (예 : 테이프 액세스)? 예-> i) 병합 정렬을 사용하지만이 경우를 정할 수있는 확실한 방법은 없으므로 추가 메모리 가 필요할 수 있습니다 . 그러나 시간과 공이 있다면 만 사용하여 시간 에 2 개의 배열을 병합하는 방법이 있습니다Θ(log(n))Θ(n)Θ(n)Θ(log(n))Donald E. Knuth "컴퓨터 프로그래밍의 기술, 3 권 : 분류 및 검색"에 따르면, 안정적인 방식으로 공간 5.5.3. L. Trabb-Pardo의 알고리즘이 있다고 말합니다. 그러나 이것이 순진한 mergesort 버전이나 위의 경우보다 quicksort보다 빠를 것이라고 의심합니다. 아니요, 그것은 일련의 데이터에 여러 번 동시에 액세스 할 수 있습니다 (예 : 테이프 드라이브가 아닙니다)-> ii) 퀵 정렬을 사용하십시오. 실제적인 목적으로 무작위 또는 대략적인 중앙값을 권장합니다. 병리학 적 사례에 주의를 기울이면 소개 정렬 사용을 고려하십시오. 결정 론적 행동에 지친 사람이라면 중간 값 알고리즘을 사용하여 피벗 요소를 선택하는 것이 좋습니다.Θ(n2)Θ(n)시간과 순진한 구현에는 공간 (병렬화 가능)이 필요한 반면 공간 (병렬화 불가능 만 필요로 구현 될 수 있습니다 . 그러나 중앙값 중간 알고리즘은 최악의 경우 런타임 을 갖는 결정적인 빠른 정렬을 제공합니다 . 아니요-> 문제가 발생했습니다 (죄송합니다. 각 데이터 요소에 한 번 이상 액세스 할 수있는 방법은 최소한 한 번은 필요합니다)Θ(n)Θ(log(n))Θ(n⋅log(n))
아니오-> 8) 적은 양의 메모리를 절약 할 수 있습니까? 예-> 기본 데이터 구조가 임의 액세스를 허용합니까? 예-> 힙 정렬을 사용하면 의 점근 최적의 런타임이 있지만 캐시 일관성이 떨어지고 병렬화되지 않습니다. 아니오-> 당신은 망했다 아니오-> 당신은 망했다Θ(n⋅log(n))
빠른 정렬을위한 구현 힌트 :
1) 순진 바이너리 퀵 정렬에는 추가 메모리가 필요하지만 마지막 재귀 호출을 루프에 다시 작성하여 로 줄이는 것이 상대적으로 쉽습니다 . k> 2의 k-ary 퀵 정렬에 대해 동일한 작업을 수행하려면 공간 (마스터 정리에 따라)이 필요하므로 이진 퀵 정렬에는 최소의 메모리가 필요하지만 k> 2의 k-ary 퀵 정렬이 실제 설정에서 바이너리 퀵 정렬보다 빠를 지 아는 사람이 있다면 기뻐하십시오.Θ는 ( 로그 ( N ) ) Θ를 ( N 로그 K ( 케이 - 1 ) )Θ(n)Θ(log(n))Θ(nlogk(k−1))
2) 빠른 정렬의 상향식 반복 변형이 있지만 AFAIK에는 하향식과 동일한 점근 적 공간 및 시간 경계가 있으며 구현하기 어려운 추가 측면이 있습니다 (예 : 대기열을 명시 적으로 관리). 내 경험은 실제적인 목적을 위해 고려할 가치가 없다는 것입니다.
mergesort에 대한 구현 힌트 :
1) bottum-up mergesort는 재귀 호출이 필요하지 않으므로 항상 top-down mergesort보다 빠릅니다.
2) 매우 순진한 병합 정렬은 각 단계 후에 시간 배열에서 데이터를 다시 복사하는 대신 이중 버퍼를 사용하여 속도를 높이고 버퍼를 전환 할 수 있습니다.
3) 많은 실제 데이터의 경우 적응 병합 병합은 고정 크기 병합 정렬보다 훨씬 빠릅니다.
4) 입력 데이터를 거의 동일한 크기의 k 개로 분할하여 병합 알고리즘을 쉽게 병렬화 할 수 있습니다. 이것은 데이터에 대한 k 참조를 필요로하며, 모든 k (또는 작은 상수 c> = 1의 경우 c * k)가 가장 가까운 메모리 계층 (보통 L1 데이터 캐시)에 맞도록 k를 선택하는 것이 좋습니다. k 요소 중에서 가장 작은 요소를 선택하면 순진한 방법 (선형 검색)은 시간이 걸리지 만 k 요소 내에 최소 힙을 작성하고 가장 작은 요소를 선택하면 상각 된 만 필요합니다 시간 (최소한의 선택은 입니다. 그러나 각 요소에서 한 요소가 제거되고 다른 요소로 대체되므로 약간의 유지 관리가 필요합니다). 병렬 병합에는 항상 필요합니다Θ ( 로그 ( k ) ) Θ ( 1 ) Θ ( n )Θ(k)Θ(log(k))Θ(1)Θ(n) k에 관계없이 메모리.
필자가 작성한 내용에서 다음 조건이 모두 적용되는 경우를 제외하고 quicksort가 종종 가장 빠른 알고리즘이 아니라는 것이 분명합니다.
1) "몇 가지"가능한 값 이상이 있습니다
2) 기본 데이터 구조가 연결되어 있지 않습니다
3) 우리는 안정적인 주문이 필요하지 않습니다
4) 데이터는 bitonic sorter 또는 Batcher 홀수-짝 mergesort 킥의 약간 차선의 비 점근 적 런타임에 적합합니다.
5) 데이터가 거의 정렬되지 않았으며 이미 정렬 된 더 큰 부분으로 구성되지 않음
6) 여러 장소에서 동시에 데이터 시퀀스에 액세스 할 수 있습니다
7) {메모리 정렬은 퀵 정렬의 가능한 하위 최적 분할을 넘어 알고리즘 속도를 늦추는 한 특히 비용이 많이 듭니다 (병합 정렬의 주요 단점이기 때문에). } 또는 { 추가 메모리 만 가질 수 있습니다 . 이 너무 많습니다 (예 : 외부 저장소)}Θ ( n )Θ(log(n))Θ(n)
추신 : 누군가 텍스트의 서식을 지정하는 데 도움이 필요합니다.