🌻 JAVA/알고리즘, 자료구조

알고리즘 - Merge Sort (분할 정복, 병합 정렬)

2020. 11. 16. 12:31
목차
  1. 분할 정복 (Merge Sort)
반응형

안녕하세요, 알고리즘을 정리하는 포스팅입니다. 다른 알고리즘을 참고하시려면 해당 카테고리를 이용해주세요. 😊

 

'🌻 JAVA/알고리즘, 자료구조' 카테고리의 글 목록

공부한 것들 정리한 내용을 포스팅합니다.

iseunghan.tistory.com

 

 

분할 정복 (Merge Sort)

Merge Sort, 분할 정복, 병합 정렬, 합병 정렬 이라고도 한다. 시간복잡도는 최악의 상황까지도 O(n log n)을 보장한다.

나는 이 알고리즘을 공부할때, 분할 정복이라고 배워서 분할 정복이라고 칭하겠다.

 

그렇다면 왜 분할 정복일까?

Merge Sort가 O(n logn)을 보장할 수 있었던 이유는 정렬 할 배열을 반으로 분할 한뒤 각각 정렬 시키고 합치기 때문에 속도가 빠르다고 할 수 있다. (아래의 이미지를 보자)

배열을 반으로 자르고, 그 자른 배열을 또 반으로 자르고, 그렇게 혼자가 될때까지 분할 시킨다.

뭔가 반복적인 과정이 보인다. 이 정렬은 재귀로 표현 할 수 있다.

각 처리 하는 순서를 번호로 표시 해봤다.

그럼 각 순서대로 처리 하는 과정을 살펴 보자.

  • mergeSort(arr, 0, 5);
middle을 먼저 구한다. middle = (0 + 5) / 2  --> 2

그럼 두번 나눠서 재귀 호출을 한다.

  • mergeSort(arr, 0, middle);
  • mergeSort(arr, middle+1, 5);

 

  • 1. mergeSort(arr, 0, 2);
int m = 0;
int n = 2;
int middle = (m+n) / 2; // 1


  • mergeSort(arr, m, middle); // recursion (arr, 0, 1)
  • mergeSort(arr, middle+1, n); // recursion (arr, 2, 2)

 

  • 2. mergeSort(arr, 0, 1);
int m = 0;
int n = 1;
int middle = (m+n) / 2; // 0

  • mergeSort(arr, m, middle); // recursion (arr, 0, 0)
  • mergeSort(arr, middle+1, n); // recursion (arr, 1, 1)

 

  • 3. mergeSort(arr, 0, 0);
int m = 0;
int n = 0;
int middle = (m+n) / 2; // 0

호출 할 필요가 없다!

 

  • 4. mergeSort(arr, 1, 1);
int m = 0;
int n = 0;
int middle = (m+n) / 2; // 0

마찬가지로 호출 할 필요가 없다!

여기서 알 수 있는 조건 mergeSort 호출 시 m == n일 경우 호출 할 필요없다. ( m < n ) 인 경우만 호출하면 된다.

 

  • 5. mergeSort(arr, 2, 2);  -> 호출 X
  • 6. mergeSort(arr, 3, 5);-  >  3,4/5,5 호출
    • 7. mergeSort(arr, 3, 4);  -> 3,3/4,4 호출
      • 8. mergeSort(arr, 3, 3);  -> 호출 X
      • 9. mergeSort(arr, 4, 4);  -> 호출 X
    • 10. mergeSort(arr, 5, 5);  -> 호출 X

 

자 여기까지 분할 하는 과정을 살펴보았는데, 코드로 나타내면 아래와 같다.

public void mergeSort(int[] arr, int m, int n) {
	if(m < n) {
    	int middle = (m + n) / 2;
    	mergeSort(arr, m, middle);
        mergeSort(arr, middle + 1, n);
    }
}

 

 

이제 분할 정복에서 정복 과정, 즉 합치면서 정렬 시키는 과정을 살펴보자.

총 5번에 걸쳐서 정복 과정이 이루어 질텐데, 그 과정을 한번 하나씩 보겠다.

 

 

  • 1. merge(arr, 0, 1)

인자 값으로 arr배열의 주소와, 시작 인덱스, 마지막 인덱스 를 넘겨준다.

각 인덱스의 값들을 비교하면서 sorted 배열에다가 넣는다.

 

  • 2. merge(arr, 0, 2) 

이제 지금이 중요하다. 앞에 정렬된 두개의 인덱스와 arr[2] 를 비교해서 sorted에 넣어야 하는데

앞에 배열은 이미 정렬된 상태이기 때문에, for문으로 비교후 sorted에 넣어주면 된다.

비교후 값을 넣어주고, 해줘야 할 것이 k값 증가, 넣은 인덱스 값 증가 시키기. 위에 그림은 k++, j++ 를 해주면 된다.

그치만, 조심해야 할것이 j++ 를 해주면 인덱스가 벗어나게 된다.

그래서 우리가 설정 해줘야 할 조건은 ( i <= middle && j <= n ) 이다.

 

코드로 작성해보면,

 while (i <= middle && j <= n) {
            if (a[i] < a[j]) {
                sorted[k] = a[i];
                i++;
            }else{
                sorted[k] = a[j];
                j++;
            }
            k++;
        }

 

자 그 다음 해야 할 것이 무엇일까?

while문이 종료되면, 아직 남아 있는 데이터가 있다는 뜻이다. 그와 동시에 한쪽은 이미 다 옮겼고, 나머지 한쪽만 반복문을 통해 넣어주기만 하면 된다.

코드로 함께 보자.

 

1. 만약 i가 middle보다 커졌을 경우

if(i > middle) {

	for(int t = j; t <= n; t++) {
		sorted[k++] = arr[t];	
	}
}

 

2. 만약 j가 n보다 커졌을 경우

if(j > n) {

	for(int t = i; t <= middle; t++) {
		sorted[k++] = arr[t];	
	}
}

 

그 다음에 sorted 배열을 다시 arr 배열로 덮어씌어 주면 된다!

for(int t=m; t <= n; t++) {
	arr[t] = sorted[t];
}

 

 

전체 코드

public class Merge_Sort_Tutorial {
    static int number = 8;
    static int[] sorted = new int[8];
    private static void merge(int[] a, int m, int middle, int n) {
        int i = m;
        int j = middle + 1;
        int k = m;
		// 두 배열 중 하나를 다 옮길 때 까지 반복
        while (i <= middle && j <= n) {
            if (a[i] < a[j]) {
                sorted[k] = a[i];
                i++;
            }else{
                sorted[k] = a[j];
                j++;
            }
            k++;
        }
        // 남아있는 데이터 삽입
        if (i > middle) {
            for (int t = j; t <= n; t++) {
                sorted[k] = a[t];
                k++;
            }
        }else{
            for (int t = i; t <= middle; t++) {
                sorted[k] = a[t];
                k++;
            }
        }
        // 정렬된 배열을 삽입
        for (int t = m; t <= n; t++) {
            a[t] = sorted[t];
        }
    }

    private static void mergeSort(int[] a, int m, int n) {
        if (m < n) {
            int middle = (m + n) / 2;
            mergeSort(a, m, middle);
            mergeSort(a, middle + 1, n);
            merge(a, m, middle, n);
        }
    }

    public static void main(String[] args) {
        int[] array = {7, 1, 5, 5, 8, 9, 3, 2};
        mergeSort(array, 0 , array.length-1);

        for (int i : array) {
            System.out.print(i + ", ");
        }
    }
}

 

반응형
저작자표시 (새창열림)
  1. 분할 정복 (Merge Sort)
'🌻 JAVA/알고리즘, 자료구조' 카테고리의 다른 글
  • 알고리즘 - 백트래킹(Back-Tracking)
  • 알고리즘 - 재귀 알고리즘 (feat. Factorial, Fibonacci)
  • 알고리즘 - Counting Sort (카운팅 정렬 / 계수 정렬) 알고리즘
  • 알고리즘 - 에라토스테네스의 체 - 소수 판별 알고리즘
iseunghan
iseunghan
꾸준하게 열심히..
iseunghan
iseunghan

공지사항

  • 어제보다 나은 오늘이 되기 위해 🔥
  • 분류 전체보기 (262)
    • 💐 Spring (14)
      • 개념 및 이해 (2)
      • Spring 핵심 기술 (24)
      • Spring REST API (8)
      • Spring MVC, DB 접근 기술 (7)
      • Spring Security (23)
      • Spring in Action (1)
    • 🌻 JAVA (84)
      • 자바 ORM 표준 JPA 프로그래밍 (20)
      • 알고리즘, 자료구조 (13)
      • 디자인 패턴 (7)
      • 정리정리정리 (43)
      • JUnit (1)
    • 🔖 Snippets (3)
      • Javascript (3)
    • ⚙️ Devops (22)
      • ⛏ Git (11)
      • 🐳 Docker (6)
      • 🐧 Linux (3)
      • 🌈 Jenkins (1)
      • 📬 Kafka (1)
    • 💬 ETC.. (4)
      • 💻 macOS (2)
    • 🌧️ ORM (2)
      • JPA (2)
    • 🐍 Python (3)
    • 📚 Databases (15)
      • 오라클로 배우는 데이터베이스 개론과 실습(2판) (3)
      • RealMySQL 8.0 (8)
    • 🔥 Computer Science (5)
      • 📡 네트워크 (5)
    • 🏷️ 협업 (1)
    • 📜 코딩테스트 (38)
      • BAEKJOON\수학 1, 수학 2 (8)
      • BAEKJOON\재귀 (5)
      • BAEKJOON\브루트 포스 (3)
      • BAEKJOON\정렬 (1)
      • BAEKJOON\백트래킹 (5)
      • BAEKJOON\BFS, DFS (6)
      • BAEKJOON\이분탐색 (1)
      • BAEKJOON\다이나믹 프로그래밍 (9)
      • BAEKJOON\그리디 알고리즘 (0)
    • ✨ ISEUNGHAN (1)

인기 글

전체
오늘
어제
반응형
hELLO · Designed By 정상우.
iseunghan
알고리즘 - Merge Sort (분할 정복, 병합 정렬)
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.