알고리즘
분할정복
코딩 화이팅
2023. 3. 22. 15:21
이진검색 재귀
- 자료의 중앙에 있는 원소를 고른다.
- 중앙 원소의 값과 찾고자 하는 목표 값을 비교한다.
- 중앙 원소의 값과 찾고자 하는 목표 값이 일치하면 탐색을 종료한다.
- 목표 값이 중앙 원소의 값보다 작으면 자료의 왼쪽 반에 대해서 새로 검색을 수행하고, 크다면 자료의 오른쪽 반에 대해서 새로 검색을 수행한다.
- 찾고자 하는 값을 찾을 때까지 1.~4.의 과정을 반복한다.
package day0322_분할정복;
public class 분할정복04_이진검색_재귀 {
static int[] arr;
static int key;
public static void main(String[] args) {
// 정렬된 상태라고 가정
arr = new int[] { 2, 4, 6, 8, 9, 17, 28 };
key = 4;
System.out.println(binarySearch(0, arr.length-1));
}
// 이진검색을 하는 이유는요!
// 이거 이안에 들었나~(boolean) / 들었다면 어디에 들었나~(int)
// 인자값으로 무엇을 들고가야하나 (경계의 시작점과 끝점을)
public static boolean binarySearch(int st, int ed) {
//기저조건(못찾았다)
if(st > ed) return false;
int mid = (st + ed) / 2; //정수값
//같다면
if(arr[mid] == key) return true;
//크다면 (왼쪽구간으로)
else if(arr[mid] > key) return binarySearch(st, mid-1);
//작다면 (오른쪽구간으로)
else return binarySearch(mid+1, ed);
}
}
//
true
만약 key값이 없는 값이라면 false출력
이진검색 API
package day0322_분할정복;
import java.util.Arrays;
public class 분할정복05_이진검색_API {
static int[] arr;
static int key;
public static void main(String[] args) {
// 정렬된 상태라고 가정
arr = new int[] { 2, 4, 6, 8, 9, 17, 28 };
key = 8;
//있는 key값을 찾으면 해당 인덱스를 반환해주고
//없는 key값을 찾으면 음수를 반환하는거 같은데 규칙을 모르겠다.
//무슨 규칙이 있는거 같긴한데 ... 무엇이지?
System.out.println(Arrays.binarySearch(arr, key));
}
}
//
3
병합정렬
package day0322_분할정복;
import java.util.Arrays;
public class 병합정렬 {
public static void main(String[] args) {
int[] arr = new int[] {69, 10, 30, 2, 16, 8, 31, 22};
mergeSort(arr); // 병합 정렬 수행
System.out.println(Arrays.toString(arr)); // 정렬된 배열 출력
}
// 병합 정렬 메소드
public static void mergeSort(int[] arr) {
// 배열이 null이거나 길이가 2보다 작은 경우
if (arr == null || arr.length < 2) {
System.out.println("배열이 없거나 짧아요");
return;
}
sort(arr, 0, arr.length - 1); // 배열을 분할하고 정렬하는 메소드 호출
}
// 분할 및 정렬하는 메소드
private static void sort(int[] arr, int left, int right) {
// 배열의 길이가 1인 경우
if (left >= right) {
return;
}
int mid = (left +right) / 2; // 배열을 분할하기 위한 중간 지점 계산
sort(arr, left, mid); // 왼쪽 부분 배열 정렬
sort(arr, mid + 1, right); // 오른쪽 부분 배열 정렬
merge(arr, left, mid, right); // 정렬된 부분 배열 병합
}
// 병합 메소드
private static void merge(int[] arr, int left, int mid, int right) {
int[] temp = new int[right - left + 1]; // 병합할 때 사용할 임시 배열 생성
int i = left, j = mid + 1, k = 0; // i는 왼쪽 부분 배열의 시작 인덱스, j는 오른쪽 부분 배열의 시작 인덱스, k는 임시 배열의 인덱스
// 왼쪽과 오른쪽 부분 배열을 비교하여 임시 배열에 정렬된 상태로 삽입
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 왼쪽 부분 배열에 남은 요소들을 임시 배열에 삽입
while (i <= mid) {
temp[k++] = arr[i++];
}
// 오른쪽 부분 배열에 남은 요소들을 임시 배열에 삽입
while (j <= right) {
temp[k++] = arr[j++];
}
// 임시 배열에 있는 요소들을 원래 배열에 정렬된 상태로 복사
for (int p = 0; p < temp.length; p++) {
arr[left + p] = temp[p];
}
}
}
퀵정렬_로무토파티션
주어진 배열을 두 개로 분할하고, 각각을 정렬한다.
병합정렬과 다른 점
- 병합 정렬은 그냥 두 부분으로 나누는 반면에, 퀵 정렬은 분할할 때, 기준 아이템(pivot item)중심으로, 이보다 작은 것은 왼편, 큰 것은 오른편에 위치시킨다.
- 각 부분 정렬이 끝난 후, 병합정렬은 "병합"이란 후처리 작업이 필요하나, 퀵 정렬은 필요로 하지 않는다.
동작 과정
- 정렬한 배열 입력
- 임의의 한 점을 pivot으로 선정(Partition 방법)
pivot보다 작은 값들은 왼쪽으로, 큰 값들은 오른쪽으로 이동 - 정렬할 범위가 0이나 1이 될 때까지 분할 정복
package day0322_분할정복;
import java.util.Arrays;
public class 퀵정렬_로무토파티션 {
public static void main(String[] args) {
int[] arr = {3,1,6,12,78,34,7};
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr)); // [1, 3, 6, 7, 12, 34, 78]
}
// 퀵정렬을 구현하는 메소드
private static void quickSort(int[] arr, int left, int right) {
// 배열이 null이거나 빈 배열일 경우
if (arr == null || arr.length == 0) {
return; // 정렬할 필요가 없으므로 바로 리턴
}
// left가 right보다 작은 경우
if (left < right) {
// 배열을 분할하는 기준 인덱스를 구함
int pivotIndex = partition(arr, left, right);
// pivot을 기준으로 왼쪽 부분배열 퀵정렬 수행
quickSort(arr, left, pivotIndex - 1);
// pivot을 기준으로 오른쪽 부분배열 퀵정렬 수행
quickSort(arr, pivotIndex + 1, right);
}
}
// 배열을 분할하는 기준 인덱스를 구하는 메소드
public static int partition(int[] arr, int left, int right) {
// pivot을 가장 오른쪽 값으로 설정
int pivot = arr[right];
int i = left - 1; // i를 왼쪽 끝으로 설정
// left부터 right - 1까지 반복
for (int j = left; j < right; j++) {
// 현재 값이 pivot보다 작거나 같은 경우
if (arr[j] <= pivot) {
i++; // i를 1 증가시킴
swap(arr, i, j); // i와 j를 swap함
}
}
swap(arr, i + 1, right); // pivot을 i + 1과 swap함
return i + 1; // i + 1을 pivot으로 설정하여 리턴
}
// 배열에서 두 인덱스의 값을 서로 바꾸는 메소드
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}