2022. 9. 17. 23:19ㆍCS/자료구조, 알고리즘
이번 포스팅에서는 선택정렬(Selection Sort) 알고리즘을 증명해보자.
selection sort 는 알고리즘을 처음 접하면 알게 되는 녀석이다.
하지만 이 역시 수학적으로 엄밀하게 증명해본 적이 없어 이를 증명해보고자 한다.
selection sort 소스코드
// Selection Sort
int sort(int a[], int n){
int i, j, m, t;
for(i=0;i<n;i++){
// Find Minimum
m = i;
for(j=i; j<n; j++)
if(a[m] > a[j])
m=j;
t = a[i];
a[i] = a[m];
a[m] = t;
// a[m] : 최소값, a[i] ~ a[n-1] 중에
}
return -1;
}
Sorting 알고리즘의 정확성 증명
우선 정렬이 완료됐다는 걸 어떻게 증명할 것인가? 에 대한 답을 내려야 한다.
- 입력값 : a[0], a[1], .... ,a[n-1]
- 입력값은 정수 집합이다.
정렬이 완료되었다는 것, 즉 Sorting이 완료된 후에는 다음을 만족해야 한다.
- Sorting 이 끝난 후의 배열을 편의상 b[0], b[1], ..... b[n-1] 이라 하자.
- 같은 배열이지만 구분을 위해 이름만 다르게 한 것이다. (b는 배열 a와 같음.
조건 1: 집합조건이 성립
- { a[0], a[1], ..... ,a[n-1] } = { b[0], b[1], .... , b[n-1] } 집합으로 같음
조건 2: b[0] < b[1] < ...... < b[n-1]
b[k] = b[k+1]인 경우는 부등호가 달라져야 하겠지만, 편의상 같은 값을 없다고 가정하겠다.
위 조건 1, 2 가 만족되면 sorting이 증명됐다고 볼 수 있다.
Proof by Invariant
앞서 binary search 에서도 invariant로 증명을 하였는데, 선택정렬도 invariant 를 통해 증명해보자.
(Invariant 란 불변 조건으로, 함수가 실행되는 동안 이 조건이 깨지지 않으면 증명된다.)
Invariant
(1) 집합조건이 깨지지 않는다.
(2) k번째 루프가 끝난 후에는 다음이 성립한다.
- a[0] < a[1] < ..... < a[k-1]
- x > k-1 이라면 a[k-1] < a[x] 가 성립한다.
Proof Invariant
수학적 귀납법을 이용해 불변조건을 증명해보자.
Base
k=0일 때 (1)은 null condition, true. (2)도 null이므로, true.
성립할 조건이 아예 없으면 true이다. 따라서 Invariant 는 성립한다.
Step
P(k) : k+1 번째 루프를 돌고 난 후에 Invariant 가 성립.
P(k-1) -> P(k) 임을 보여야 한다.
Invariant
P(k-1) 이 사실이라고 가정했으므로 (루프 k번 돌음)
(1) a[0] < a[1] < ...... < a[k-1] 을 만족한다.
(2) x > k-1 일때 a[k-1] < a[x] 을 만족한다.
P(k)
K+1 번째 루트가 끝난 다음에 가장 작은 값을 k 에 가져다 뒀으므로
Invariant (2) : x > k 일 때 a[k] < a[x] 가 성립한다.
이제 Invariant (1) : a[0] < a[1] < ..... < a[k] 임을 보이면 되는데,
앞의 P(k-1)이 참이므로 a[k-1] < a[k] 만 보이면 끝이다.
a[k]는 P(k-1)의 Invariant (2) 에 의해 a[k-1] 보다 크므로, a[k-1] < a[k] 임이 증명되었다. 따라서 k일때도 Invariant 가 성립한다.
따라서 P(k-1) -> P(k) 가 성립한다.
즉 k 번째 루프가 끝났을 때 Invariant 가 성립한다면, k+1 번째 루트가 끝났을 때도 Invariant 가 성립한다.
결론
수학적 귀납법에 의해 Invariant 가 항상 성립함을 보였다. 따라서 Sorting 은 참이다.
COMPLEXITY
T(N) = N + T(N-1) = N + N-1 + T(N-2) = ....... = O(N^2)
다음은 재귀적으로 선택정렬을 구현한 코드이다.
// resursive Selection sort
int sort(int a[], int n){
int j,m,t;
if(n<=1) return;
m=0;
for(j=0;j<n;j++){
if(a[m]>a[j]) m=j;
}
// a[0]와 a[m] swap
t = a[0]; a[0] = a[m]; a[m]=t;
sort(a+1, n-1);
return -1;
}
앞서 일반 selection sort 의 증명 방법과 비슷하다. 이번에는 수학적 귀납법만으로 증명 가능하다.
sorting 되었다는 증명 조건
입력: a[0], a[1], ..... ,a[n-1] 정수 집합.
sorting 이 끝난 후 다음을 만족해야 한다.
- 조건 1 : {a[0], a[1], .... ,a[n-1] } = {b[0], b[1], ..... ,b[n-1] } 집합으로 같음
- 조건 2 : b[0] < b[1] < ..... < b[n-1] (증명 편의상 같은 값은 없다고 가정)
Proof By Induction
집합 조건을 깰 수 있는 코드는 지금도 없다. 따라서 집합 조건을 만족.
Base : n = 1. 정렬 할 것도 없다. true
Step :
n-1 일 때 sort() 함수가 성공한다면, n 일 때 sort() 함수가 성공한다. 를 보이자.
Sort 함수 내부에 Sort(a+1, n-1) 가 재귀적으로 호출되므로 이를 이용.
P(n-1) : sort(a+1, n-1)
P(n) : sort(a, n) 이라 하자.
P(n-1) 이 참이라 가정할 때, P(n) 도 참임을 보이자.
즉 재귀호출이 끝난 후 a[1] < a[2] < ..... < a[n-1] 라면 함수가 끝날 때 a[0] < a[1] < ...... <a[n-1] 임을 보이자.
위의 소스코드를 유심히 보자.
재귀호출을 하기 전, for문을 돈 후에 swap을 통해 가장 작은 값을 앞으로 옮기지 않았는가.
즉 a[0]이 가장 작은 값이라는 것. a[0] < a[1], a[2], ..... ,a[n-1] 임은 자명하다.
따라서 a[1] < a[2] < ..... < a[n-1] 이라면 a[0] < a[1] < a[2] ..... < a[n-1] 은 참이다.
Conclusion
Base, Step 에 의해 귀납적으로 sort 는 참이다.
COMPLEXITY
T(N) =
N + T(N-1) =
N + (N-1) + T(N-2) = ........
= O(N^2) 이다.
'CS > 자료구조, 알고리즘' 카테고리의 다른 글
Prim 알고리즘 - 2 (2) | 2022.09.19 |
---|---|
Prim 알고리즘 - 1 (0) | 2022.09.18 |
Mergesort (0) | 2022.09.12 |
Binary Search 증명 (1) | 2022.09.04 |
재귀 알고리즘의 정확성 증명 (0) | 2022.09.03 |