-
합병 정렬개발 지식/알고리즘 2020. 7. 9. 01:26
JAVA로 작성되었습니다.
합병 정렬
- 분할정복을 이용한 정렬방법
- 배열을 한개의 조각이 될 때까지 쪼개고 두개 (1, 1)를 서로 비교,
4개(2, 2)를 서로 비교, 8개(4, 4)를 서로 비교 하는 방법 - 비교한 결과를 저장하기 위해 임시의 배열이 추가로 필요하다.
- 인자로 들어온 left가 right보다 작은지 검증한다 (같다면 숫자가 하나이기에)
- 중간값을 결정한다. ((오른쪽 값 - 왼쪽 값) / 2 + left)
- 중간값과 왼쪽 배열, 중간값 오른쪽 배열을 다시 분할하는 재귀함수를 호출한다.
- left + 1 = right 가 될때까지 분할을 수행한다.
(분할해야 하는 배열의 요소가 2개)
(3개인 경우 2개와 1개로 쪼개지고 왼쪽의 2개만 쪼개져 서로 비교를 진행하고
다시 돌아와 2개와 1개의 비교를 진행한다.) - 1개 두개를 비교했으면 요소가 2개인 정렬된 배열 2개를 다시 비교하고
비교된 4개의 요소는 다시 다른 4개의 요소와 비교되어 원본 배열의 크기와
같아질 때 까지 비교를 진행한다. - 비교를 진행하는 방법은 왼쪽 배열의 첫번째 값과 오른쪽 배열의 첫번째 값을
비교하는 것으로 시작한다.- 첫번째 값이 오른쪽이 더 작다면 오른쪽의 첫번째 값을 임시배열의 처음 값에
집어 넣는다. 그리고 왼쪽의 인덱스는 그대로 두고 오른쪽 배열의
인덱스를 + 1 하여 오른쪽의 두번째 값과 왼쪽의 첫번째 값을 비교한다. - 이번에도 오른쪽 배열의 숫자가 더 작다면 위와 같은 방법으로 임시 배열에
오른쪽의 값을 집어 넣고 오른쪽 배열의 인덱스만을 증가시켜
다음 숫자를 비교한다.
- 첫번째 값이 오른쪽이 더 작다면 오른쪽의 첫번째 값을 임시배열의 처음 값에
- 비교가 끝나면 왼쪽 배열과 오른쪽 배열중 하나는 배열의 끝에 도달하였을텐데
그때 인덱스가 끝에 위치하지 않은 배열의 나머지를 모두 임시의 배열에 추가한다.- 비교를 진행하기 전 왼쪽과 오른쪽 배열은 각자 정렬이 완료되어있는 상태이다.
그러므로 한쪽의 모든 값보다 작다면 반대쪽의 기존에 정렬된 숫자를 그대로
뒤에 넣는 것이 맞는것.
- 비교를 진행하기 전 왼쪽과 오른쪽 배열은 각자 정렬이 완료되어있는 상태이다.
- 서로의 비교, 정렬이 끝나고 인자로 들어온 left값부터 right값 까지의 원본배열에
임시 배열의 값들을 집어넣어준다.- 6부터 10까지의 값을 비교하여 임시배열에 저장하였다면 임시배열의 크기는
5이고 그 5개의 값을 원본 배열의 인덱스 6 - 10에 넣어주는 것.
- 6부터 10까지의 값을 비교하여 임시배열에 저장하였다면 임시배열의 크기는
- 재귀함수가 끝나고 원본을 반 나눈 배열 두개를 비교하고 나 정렬이 종료된다.
import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; import java.util.Random; public class MergeSort { public List<Integer> list_merge(List<Integer> list, int left, int right) { // 리스트 를 반으로 쪼갠다. // 재귀 함수 발동! (반절의 왼쪽, 반절의 오른쪽) // 재귀 함수가 반환하는 두 리스트를 하나씩 비교하여 정렬한다. // System.out.println("new!"); int mid = 0; if (left < right) { mid = ((right - left) / 2) + left; // System.out.println("left: " + left + "\nright: " + right + "\nmid: " + mid); list = list_merge(list, left, mid); list = list_merge(list, mid + 1, right); List<Integer> temp = new ArrayList<Integer>(); int temp1 = left, temp2 = mid + 1; while (temp1 <= mid && temp2 <= right) { // System.out.println("index: " + temp1 + " value: " + list.get(temp1)); // System.out.println("index: " + temp2 + " value: " + list.get(temp2)); if (list.get(temp1) <= list.get(temp2)) { temp.add(list.get(temp1)); temp1++; } else if (list.get(temp1) > list.get(temp2)) { temp.add(list.get(temp2)); temp2++; } } if (temp1 == mid + 1) { for (int i = temp2; i <= right; i++) { temp.add(list.get(i)); } } else if (temp2 == right + 1) { for (int i = temp1; i <= mid; i++) { temp.add(list.get(i)); } } for (int i = left, temp_cnt = 0; i <= right && temp_cnt < temp.size(); i++, temp_cnt++) { list.set(i, temp.get(temp_cnt)); } } // System.out.println(list + "\n"); return list; } public void accuracy_test(List<Integer> origin, List<Integer> sorted) { int cnt = 0, temp1 = 0; List<Integer> temp = new ArrayList<Integer>(sorted); for (int i = temp1; i < origin.size(); i++) { for (int j = 0; j < temp.size(); j++) { if (temp.get(j).equals(origin.get(i))) { if (i < origin.size() - 1) { temp1++; } temp.remove(j); j = temp.size(); cnt++; } } } System.out.println("Matching rate: " + (cnt / origin.size()) * 100 + "%"); } public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); MergeSort mergeSort = new MergeSort(); Random random = new Random(); for (int i = 0; i < 10; i++) { list.add(random.nextInt(10)); } List<Integer> origin_copy = new ArrayList<Integer>(list); System.out.println("before: " + origin_copy); list = mergeSort.list_merge(list, 0, list.size() - 1); System.out.println("after: " + list); mergeSort.accuracy_test(origin_copy, list); } }
'개발 지식 > 알고리즘' 카테고리의 다른 글
쉘 정렬 (0) 2020.07.09 탐색 (선형 탐색, 트리 탐색, AVL, 회전 연산) (0) 2020.07.01 트리 (완전 이진, 포화 이진, Max-heap, Min-heap) (0) 2020.06.30 스택, 큐 (0) 2020.06.30 메모리 관리 (0) 2020.06.30