주어진 문제를 2개 이상의 작은 문제로 순환적으로 분할하여 각각 해결한 후 다시 각각의 해들을 결합하여 원래 문제를 해결하는 방식
종류 | 분할 방법 | 분할 각각 사용 여부 |
---|---|---|
이진탐색 | 1/2로 분할 | 각 분할 한 부분 중 하나만 선택 |
퀵 정렬 | a:b 로 분할 | 각 분할 한 부분 모두 |
합병정렬 | 1/2로 분할 | 각 분할 한 부분 모두 |
선택문제 | a:b 로 분할 | 각 분할 한 부분 중 하나만 선택 |
전제 : 정렬된 상태의 입력 데이터(오름처순으로 정렬되어 있다고 가정)
배열의 가운데 원소 A[mid]와 탐색키(찾고자 하는 값)를 비교
가운데 원소 = A[mid] =(시작인덱스 / 종료 인덱스) / 2
1. 탐색키 = 가운데 원소 -> 탐색 성공 (인덱스 mid 반환 후 종료)
2. 탐색키 < 가운데 원소 -> 이진탐색(원래크기 / 1/2인 왼쪽 부분배열) 순환호출
3. 탐색키 > 가운데 원소 -> 이진탐색(원래크기 / 1/2인 오른쪽 부분배열) 순환호출
특정 원소를 기준으로 두 부분 배열로 분할하고 각 부분 배열에 대해 퀵정렬을 순환적으로 적용
! 피벗(pivot) : 주어진 배열을 두 부분 배열로 분리할 때 기준이 되는 특정 원소
피벗이 제자리를 잡도록하여 정렬하는 방식
피벗이 제자리를 잡도록하여 정렬 = 피벗의 왼쪽 부분 배열은 피벗보다 작은 숫자
피벗의 오른쪽 부분 배열은 피벗보다 큰 숫자
A[] : 배열
n : 배열의 크기
QuickSort(A[],n){
if(n>1){
pivot = Partition(A[0...n-1],n); // 두 부분 배열로 분할
QuickSort(A[0...pivot-1],pivot); // 왼쪽 부분 배열에 대한 순환 호출
QuickSort(A[pivot+1...n-1],n-pivot-1); // 오른쪽 부분 배열에 대한 순환 호출
}
}
int Partition(A[],n){
Left = 1 ; Right = n-1;
//A[0] 를 비벗 값으로 설정
//피벗 보다 큰 위치의 값을 찾음
try{
while(Left < Right&& A[0]<A[Left]){
Left++; // 배열의 index 를 넘어가는 경우 발생 (피봇 보다 큰 값이 없을경우)
}
//피벗 보다 작은 위치의 값을 찾음
while(Left > Right&& A[0]>A[Right]){
Right--; // right = -1 이 되는 경우 발생(피봇 보다 작은 값이 없을경우)
}
//작은 위치와 큰 값의 위치를 변경
if(Left < Right) A[Left]<->A[Right] // 교환
else A[0]<->A[Right] // 피벗과 최종적인 작은 위치의 값을 교환
}catch(IndexOutOfBoundsException e){
if(Left > n ) A[0]<->A[Right]
if(Right == -1) Right = 0;//index 0 번째 자리 확정
}
return Right; // 피벗의 index 값을 반환
}
[가장 최악의 경우]
[가장 최선의 경우]
[가장 평균적인 경우]
=> 피벗의 선택의 임의성만 보장되면 평균 성능을 보일 가능성이 매우 높다.
(배열의 임의의 값을 선택한 후 , 배열의 첫 원소와 서로 교환 후 정렬 수행)