분할정복 알고리즘으로 리스트를 두 개로 나누고 각 하위 리스트를 정렬한 후 각각을 하나로 합친다. 

  @Test
    public void mergeSortTest() {
        // divide-and-conquer 알고리즘
        // 리스트를 두 개로 나누고 각 하위 리스트를 정렬한 후 각각을 하나로 합친다.
        // 병합정렬 성능은 O(nlogn), 각각의 병합시간이 O(n)이다.
        // 왼쪽으로 나눈 리스트를 정렬하고 -> 오른쪽으로 나눈 리스트를 정렬한다.

        List<Integer> values = Arrays.asList(7,1,3,2,3,9,2,5);
        List<Integer> sorted = divide(values);
        System.out.println(sorted);
    }

    public List<Integer> divide(final List<Integer> values) {
        if (values.size() < 2) {
            return values;
        }

        int listSize = values.size();

        final List<Integer> leftHalf = values.subList(0, listSize / 2);
        final List<Integer> rightHalf = values.subList(listSize / 2, listSize);

        System.out.println("-- dividing..leftHalf : " + leftHalf + " , rightHalf : " + rightHalf);

        return conquer(divide(leftHalf), divide(rightHalf));
    }

    private List<Integer> conquer(final List<Integer> left, final List<Integer> right) {
        System.out.println("## merging.. leftHalf : " + left + " , rightHalf : " + right);
        int leftPtr = 0;
        int rightPtr = 0;

        final List<Integer> merged = new ArrayList<>(left.size() + right.size());

        int leftSize = left.size();
        int rightSize = right.size();

        while (leftPtr < leftSize && rightPtr < rightSize) {
            if (left.get(leftPtr) < right.get(rightPtr)) {
                merged.add(left.get(leftPtr));
                leftPtr++;
            } else {
                merged.add(right.get(rightPtr));
                rightPtr++;
            }
        }

        while (leftPtr < leftSize) {
            merged.add(left.get(leftPtr));
            leftPtr++;
        }

        while (rightPtr < rightSize) {
            merged.add(right.get(rightPtr));
            rightPtr++;
        }

        System.out.println("## merged : " + merged);

        return merged;
    }
-- dividing..leftHalf : [7, 1, 3, 2] , rightHalf : [3, 9, 2, 5]
-- dividing..leftHalf : [7, 1] , rightHalf : [3, 2]
-- dividing..leftHalf : [7] , rightHalf : [1]
## merging.. leftHalf : [7] , rightHalf : [1]
## merged : [1, 7]
-- dividing..leftHalf : [3] , rightHalf : [2]
## merging.. leftHalf : [3] , rightHalf : [2]
## merged : [2, 3]
## merging.. leftHalf : [1, 7] , rightHalf : [2, 3]
## merged : [1, 2, 3, 7]
-- dividing..leftHalf : [3, 9] , rightHalf : [2, 5]
-- dividing..leftHalf : [3] , rightHalf : [9]
## merging.. leftHalf : [3] , rightHalf : [9]
## merged : [3, 9]
-- dividing..leftHalf : [2] , rightHalf : [5]
## merging.. leftHalf : [2] , rightHalf : [5]
## merged : [2, 5]
## merging.. leftHalf : [3, 9] , rightHalf : [2, 5]
## merged : [2, 3, 5, 9]
## merging.. leftHalf : [1, 2, 3, 7] , rightHalf : [2, 3, 5, 9]
## merged : [1, 2, 2, 3, 3, 5, 7, 9]
[1, 2, 2, 3, 3, 5, 7, 9]

 

병합정렬의 성능은 O(nlogn)이고 각각의 병합시간은 O(n)이며 각 재귀 호출은 주어진 리스트 숫자의 절반만큼만 발생한다는 사실을 다시 한번 기억하자.

출처 : JAVA 프로그래밍 면접 이렇게 준비한다

'알고리즘과 디자인패턴' 카테고리의 다른 글

Java Decorator Pattern 설명과 예시  (0) 2023.03.09
알고리즘 관련 to know list  (0) 2022.03.29
리스트 정렬하기  (0) 2022.01.23
자바 알고리즘 스터디  (0) 2021.08.11

+ Recent posts