Keep going

정렬 -2 본문

Records/자료구조&알고리즘

정렬 -2

코딩천재홍 2021. 1. 30. 01:26

1. 퀵 정렬 

퀵 정렬은 각 그룹에 대해 피벗 설정과 그룹 나눔을 반복하여 모든 그룹이 1명이 되면 정렬을 마친다.

5 (pl) 7 1 4 6 (pivot) 2 3 9 8 (pr)

1. a[pl] >= x 가 성립하는 요소를 찾을 때까지 pl을 오른쪽으로 스캔합니다.

2. a[pr] <=x 가 성립하는 요소를 찾을 때 까지 pr을 왼쪽으로 스캔합니다.

 

피벗 이하의 그룹 : a[0], ... , a[pl-1]

피벗 이상의 그룹 : a[pr+1] , .... a[n-1]

 

- 피벗과 일치하는 값을 가지는 그룹이 만들어 질 때

피벗과 일치하는 값을 가지는 그룹 a[pr+1], ... , a[pl-1] 

 

<배열을 나누는 프로그램>

static void partition(int[] a, int n) {
        int pl = 0;
        int pr = n - 1;
        int x = a[n / 2];
 
        do {
            while (a[pl] < x)
                pl++;
            while (a[pr] > x)
                pr--;
            if (pl <= pr)
                swap(a, pl++, pr--);
        } while (pl <= pr);
    }
cs

 

위의 배열을 나누는 프로그램을 좀 더 발전시키면 퀵 정렬 알고리즘이 됩니다.

1. pr이 left보다 오른쪽에 있으면(= left < pr) →  왼쪽 그룹을 나눕니다.

2. pl이 right보다 왼쪽에 있으면(= pl < right) → 오른쪽 그룹을 나눕니다. 

→ left < pr , pl < right 은 모두 그룹의 개수가 1개인 경우에는 성립하지 않습니다.

(2개 이상인 그룹만이 나누기 위해 필요한 조건) 

 

<퀵 정렬 프로그램>

static void quickSort(int[] a, int left, int right) {
        int pl = left;
        int pr = right;
        int x = a[(pl + pr) / 2];
 
        do {
            while (a[pl] < x)
                pl++;
            while (a[pr] > x)
                pr--;
            if (pl <= pr)
                swap(a, pl++, pr--);
        } while (pl <= pr);
 
        if (left < pr)
            quickSort(a, left, pr);
        if (pl < right)
            quickSort(a, pl, right);
    }
cs

 

2. 병합 정렬

정렬을 마친 배열의 병합을 응용하여 분할 정복법에 따라 정렬하는 알고리즘을 병합 정렬이라고 한다.

 

정렬을 마친 배열의 병합 : 시간복잡도 O(n)

static void merge(int[] a, int na, int[] b, int nb, int[]c) {
    int pa=0;
    int pb=0;
    int pc=0;
    
    while(pa < na && pb < nb)
        c[pc++= (a[pa] <= b[pb]) ? a[pa++] : b[pb++];
        
    while(pa<na)
        c[pc++= a[pa++];
    while (pb<nb)
        c[pc++= b[pb++];
    }
cs

 

-병합 정렬 알고리즘의 순서

배열의 요소 개수가 2개 이상인 경우

1. 배열의 앞부분을 병합 정렬로 정렬합니다.

2. 배열의 뒷부분을 병합 정렬로 정렬합니다.

3. 배열의 앞부분과 뒷부분을 병합합니다.

 

static void _mergeSort(int[] a, int left, int right) {
        if (left < right) {
            int i; // a 인덱스
            int center = (left + right) / 2;
            int p = 0// buff에 복사하기 위한 인덱스, 복사한 길이
            int j = 0// buff 인덱스
            int k = left;
 
            _mergeSort(a, left, center);
            _mergeSort(a, center + 1, right);
 
            for (i = left; i <= center; i++)
                buff[p++= a[i];
 
            while (i <= right && j < p)
                a[k++= (buff[j] <= a[i]) ? buff[j++] : a[i++];
 
            while (j < p)
                a[k++= buff[j++];
        }
    }
 
    static void mergeSort(int[] a, int n) {
        buff = new int[n]; // 작업용 배열을 생성
        _mergeSort(a, 0, n - 1); // 배열 전체를 병합 정렬
        buff = null// 작업용 배열을 해제
    }
cs

 

mergesort메소드는 병합한 결과를 일시적으로 저장할 작업용 buff를 생성한다.

그런 다음 실제로 정렬 작업을 수행할 _mergeSort 메서드를 호출한다.

 

병합 순서

1. 배열의 앞부분 (a[left] ~ a[center]) 을 (buff[0] ~ buff[center -left])에 복사한다.

2. 배열의 뒷부분 (a[center+1] ~ a[right])과 buff로 복사한 배열의 앞부분 p개를 병합한 결과를 배열 a에 저장한다.

3. 배열 buff에 남아 있는 요소를 배열 a에 복사한다.

 


출처 : Do it! 자료구조와 함께 배우는 알고리즘 입문 : 자바 편 [시바타 보요, 옮긴이 : 강민 (이지스퍼블리싱)]

'Records > 자료구조&알고리즘' 카테고리의 다른 글

트리  (0) 2021.01.31
정렬 -3  (0) 2021.01.30
정렬 -1  (0) 2021.01.29
재귀 알고리즘  (0) 2021.01.27
  (0) 2021.01.23
Comments