가능한 다양한 접근 방식이 있습니다. 가장 적합한 것은
- 무엇 당신이 보여주기 위해 노력하고있다,
- 얼마나 많은 세부 사항 당신이 원하는 또는 필요.
알고리즘이 서브 루틴으로 사용하는 것으로 널리 알려진 알고리즘 인 경우 종종 상위 레벨로 유지됩니다. 알고리즘이 조사중인 주요 객체 인 경우 자세한 정보를 원할 수 있습니다. 분석에 대해서도 마찬가지입니다. 거친 상한 런타임 경계가 필요한 경우 정확한 수의 명령문을 원할 때와 다르게 진행합니다.
잘 알려진 알고리즘 Mergesort에 대한 세 가지 예를 제시하겠습니다.
높은 레벨
Mergesort 알고리즘은 목록을 가져와 두 개의 (약) 동일하게 긴 부분으로 나누고 부분 목록에서 되풀이하여 (정렬 된) 결과를 병합하여 최종 결과를 정렬합니다. 싱글 톤 또는 빈 목록에서는 입력을 반환합니다.
이 알고리즘은 분명히 올바른 정렬 알고리즘입니다. 리스트를 나누고 병합하는 것은 각각 시간 구현 될 수 있으며 , 최악의 경우 런타임 . 마스터 정리에 의해, 이것은 됩니다.T ( N은 ) = 2 T ( N을Θ ( n )T(n)∈Θ(nlogn)티( n ) = 2 T( n2) +Θ(n)티( N ) ∈ Θ ( N 로그n )
중간 수준
Mergesort 알고리즘은 다음 의사 코드로 제공됩니다.
procedure mergesort(l : List) {
if ( l.length < 2 ) {
return l
}
left = mergesort(l.take(l.length / 2)
right = mergesort(l.drop(l.length / 2)
result = []
while ( left.length > 0 || right.length > 0 ) {
if ( right.length == 0 || (left.length > 0 && left.head <= right.head) ) {
result = left.head :: result
left = left.tail
}
else {
result = right.head :: result
right = right.tail
}
}
return result.reverse
}
유도에 의한 정확성을 증명합니다. 길이가 0 또는 1 인 목록의 경우 알고리즘이 간단합니다. 유도 가설로서, 임의의 고정 된 자연 대해 mergesort
최대 길이의 목록에서 올바르게 수행 한다고 가정 합니다 . 이제 을 길이 의 목록으로 만드십시오 . 인덕션 가설에 의해, 및 홀드 (비 점감) 제 RESP 버전의 정렬. 재귀 호출 후 후반 . 따라서 루프는 모든 반복에서 아직 조사되지 않은 가장 작은 요소를 선택하여 추가합니다 . 따라서 and의 모든 요소를 포함하는 점점 정렬되지 않은 목록입니다.n > 1 L n + 1 L L엔n > 1엘n + 1left
right
엘while
result
result
left
right
. 그 반대는 감소하는 정렬되지 않은 버전으로 , 반환 된 원하는 결과입니다.엘
런타임과 관련하여 요소 비교 및 목록 작업을 계산합니다 (런타임을 무조건적으로 지배 함). 길이가 2보다 작은 목록도 원인이되지 않습니다. 길이가 인 리스트의 경우, 재귀 호출을위한 입력 준비, 재귀 호출 자체의 루프 및 하나에 대한 오퍼레이션이 있습니다. 두 재귀 매개 변수는 각각 최대 목록 작업 으로 계산할 수 있습니다 . 루프는 정확히 실행 많아야 하나의 소자에 비해 시간마다 반복 원인을 정확히 두리스트 연산. 을 사용하도록 최종 구현 가능n n 2 nn > 1while
reverse
엔while
엔reverse
2 N목록 작업-모든 요소가 입력에서 제거되어 출력 목록에 추가됩니다. 따라서 작업 횟수는 다음과 같은 반복을 충족합니다.
티( 0 ) = T( 1 )티( n )= 0≤ T( ⌈ n2⌉ ) +T( ⌊ n2⌋ ) +7N
마찬가지로 명확 비 감소, 그것을 고려하기에 충분한 점근 성장한다. 이 경우 반복은 다음과 같이 단순화됩니다.N = 2 K티n = 2케이
티( 0 ) = T( 1 )티( n )= 0≤ 2 T( n2) +7N
마스터 정리에 의해의 실행 시간으로 확장되는 을 얻습니다 .티∈ Θ ( n 로그n )mergesort
초 저레벨
Isabelle / HOL 에서 Mergesort의 (일반화 된) 구현을 고려하십시오 .
types dataset = "nat * string"
fun leq :: "dataset \<Rightarrow> dataset \<Rightarrow> bool" where
"leq (kx::nat, dx) (ky, dy) = (kx \<le> ky)"
fun merge :: "dataset list \<Rightarrow> dataset list \<Rightarrow> dataset list" where
"merge [] b = b" |
"merge a [] = a" |
"merge (a # as) (b # bs) = (if leq a b then a # merge as (b # bs) else b # merge (a # as) bs)"
function (sequential) msort :: "dataset list \<Rightarrow> dataset list" where
"msort [] = []" |
"msort [x] = [x]" |
"msort l = (let mid = length l div 2 in merge (msort (take mid l)) (msort (drop mid l)))"
by pat_completeness auto
termination
apply (relation "measure length")
by simp+
여기에는 이미 명확하고 종료 된 증거가 포함되어 있습니다. 여기 에서 (거의) 완전한 정확성 증명을 찾으 십시오 .
"런타임", 즉 비교 횟수의 경우, 이전 섹션과 유사한 반복이 설정 될 수 있습니다. 마스터 정리를 사용하고 상수를 잊어 버리는 대신이를 분석하여 실제 양과 같은 점에서 근사치를 구할 수 있습니다. 전체 분석은 [1]에서 찾을 수 있습니다. 대략적인 개요는 다음과 같습니다 (Isabelle / HOL 코드에 반드시 맞지는 않습니다).
위와 같이 비교 횟수의 재발은
에프0= f1에프엔= 0= f⌈ n2⌉+ f⌊ n2⌋+ 전자엔
여기서 은 부분 결과를 병합하는 데 필요한 비교 횟수입니다 ². 바닥과 천장을 제거하기 위해 이 짝수 인지 여부에 대해 대소 문자 구분을 수행합니다 . n이자형엔엔
{ f2 M에프2m+1=2fm+e2m=fm+fm+1+e2m+1
중첩 사용하여 역방향 / 정방향으로 차이 의 하고 우리가 얻을e nfnen
∑k=1n−1(n−k)⋅Δ∇fk=fn−nf1 .
이 합계는 Perron 공식 의 오른쪽과 일치합니다 . 우리는 정의 디리클레 발생 시리즈 의 로Δ∇fk
W(s)=∑k≥1Δ∇fkk−s=11−2−s⋅∑k≥1Δ∇ekks=: ⊟(s)
Perron의 공식과 함께
fn=nf1+n2πi∫3−i∞3+i∞⊟(s)ns(1−2−s)s(s+1)ds 입니다.
평가 는 분석되는 사례에 따라 다릅니다. 그 외에는, 약간의 속임수 후에 잔류 물 정리 를 적용하여⊟(s)
fn∼n⋅log2( n ) + n ⋅ A ( 로그2( n ) ) + 1
여기서 는 값을 갖는 주기적 함수입니다 .에이[ - 1 , - 0.9 ]
- Mellin 변형 및 무증상 : Flajolet and Golin 의 합병 재발 (1992)
- 가장 좋은 경우 :
최악의 경우 :
평균 사례 :이자형엔= ⌊ n2⌋
이자형엔= n − 1
이자형엔= n − ⌊ n2⌋⌈ n2⌉ +1− ⌈ n2⌉⌊ n2⌋ +1