'퀵정렬'에 해당되는 글 1건

  1. 2007/07/14 퀵 정렬

퀵 정렬

Study/C++ / C 2007/07/14 02:34 posted by 전중
 ■ 퀵 정렬 개념

 ▷ 주어진 입력 리스트를 피봇(pivot) 또는 제어키(control key)이라 불리는 특정 키 값보다 작은 값을 가지는 레코드들의 리스트와 큰 값을 가지는 레코드들의 리스트로 분리한 다음, 이러한 두 개의 서브 리스트들을 재귀적으로 각각 재배열하는 과정을 수행하는 방식

 퀵 정렬 방법은 하나의 커다란 입력 데이터의 집합을 정렬하는 것보다는 두개의 작은 입력 데이터들을 정렬하는 것이 빠르다는 일반적인 사실에 바탕을 둠 

 분할 및 정복 방법 사용


 ▷ 피봇(Pivot)이라 부르는 특정한 데이터를 기준으로 피봇보다 작은 값을 가진 데이터들은
배열의 왼쪽 부분에, 큰 값을 가진 데이터는 오른쪽에 위치하도록 배열

 퀵 정렬은 기본적으로 순환(recursive) 알고리즘 형태를 취하며, 오름차순으로 정렬할 경우 레코드 R1을 제어 키 또는 피봇 키로 하여 왼쪽으로 가면서 R1보다 큰 키 값을 찾고, 오른쪽으로부터 왼쪽으로 가면서 R1보다 작은 키 값을 찾아 서로 교환한다. 위의 과정이 수행될 때 오른쪽과 왼쪽이 서로 교차하면 중지하고 R1을 제일 나중에 찾은 R1보다 작은 키 값과 교환하면 R1보다 작은 키 값을 갖는 레코드들과 큰 키 값을 갖는 레코드들로 분할되어 하나의 파일이 제어키 R1을 기준으로 두 개의 서브 파일로 재배열된다. 재배열된 서브파일에 대해 독립적으로 위의 수행 과정을 반복하면 정렬이 완료된다.

퀵 정렬 알고리즘 단계 : 분할과 정복 방식

① 피봇(Pivot) : 정렬할 데이터 S에서 하나 v를 선택한다.

② 분할 : S1 = {v보다 작은 수}, v, S2 = {v보다 큰 수}

③ 재귀적 수행 : return {퀵 정렬(S1), v, 퀵 정렬(S2)}


특징

평균 연산 시간에 있어서 내부 정렬 방법 중 가장 우수

     - 실제 수행속도가 가장 빠른 정렬 알고리즘

스택 공간을 사용

재귀 호출을 기반으로 동작


예제로 보는 퀵 정렬 단계

   

img1.gif


퀵 정렬 과정 사례 

초기 데이터                                          

0

1

2

3

4

5

6

7

8

9

8

1

4

9

6

3

5

2

7

0

3수의 중위수 피봇

  • 왼쪽, 중앙, 오른쪽 세수를 정렬한다.
  • 중앙의 수를 피봇한다.
  • 피봇된 수를 오른쪽-1의 위치에 있는 수와 SWAP한다.

0

1i

2

3

4

5

6

7 j

8

9

0

1

4

9

7

3

5

2

6

8

왼쪽




중앙




피봇

오른쪽

분할 : S1 = {v보다 작은 수}, v, S2 = {v보다 큰 수}

1. i 위치의 수를 피봇수와 비교하면서 증가시킴, 클 때 중단
2. j 위치의 수를 피봇수와 비교하면서 감소시킴, 작을 때 중단
3. i<j이면 i,j의 위치에 있는 수를 SWAP한다.

0

1

2

3 i

4

5

6

7 j

8

9

0

1

4

2

7

3

5

9

6

8

왼쪽








피봇

오른쪽


0

1

2

3

4 i

5

6 j

7

8

9

0

1

4

2

5

3

7

9

6

8

왼쪽








피봇

오른쪽

i>j이면 피봇 수와 i의 위치에 있는 수를 SWAP한다.

0

1

2

3

4

5 j

6 i

7

8

9

0

1

4

2

5

3

6

9

7

8

왼쪽






피봇



오른쪽

재귀적 수행 : return {퀵 정렬(S1), v, 퀵 정렬(S2)}

0

1

2

3

4

5


6


7

8

9

0

1

4

2

5

3


6


9

7

8














퀵 정렬 알고리즘


-----------------------------------------------------------------------------

void Quicksort(int A[], int N) {Qsort(A,0, N-1); }      /* 퀵 정렬 호출 함수 */


int Median3(int A[], int Left, int Right)                       /* 세 수의 중위수 계산 함수 */

{      int Center= (Left + Right) / 2;              /* A[Left]<= A[Center]<= A[Right]*/

        lf( A[Left] > A[Center] ) Swap( &A[Left], &A[Center] );

        if( A[Left] > A[Right] )  Swap( &A[Left], &A[Right] );

        if( A[Center] > A[Right]) Swap(&A[Center], &A[Right]);

        swap( &A[Center], &A[Right-1] );   /* 피봇된 수를 오른쪽-1의 위치에 있는 수와 SWAP */

        return A[Right-1];                            /*return 피봇 */

}


#define Cutoff(3)                                                     /* 퀵 정렬 함수 */

void Qsort( int A[], int Left, int Right )       /* 배열 A의 왼쪽 끝 첨자:Left, 오른쪽 끝 첨자:Right */

         {     int i, j, Pivot;                            

/*1*/       if( Left + Cutoff <= Right )           

/*2*/       {     Pivot = Median3( A, Left, Right);  

/*3*/              i=Left; j=Right-1;

/*4*/              for( ; ; )

/*5*/             {    while( A[++i ] < Pivot ){}

/*6*/                   while( A[--j ] > Pivot ){}

/*7*/                   if( i < j )

/*8*/                        swap( &A[ i ], &A[ j ] );

/*9*/                   else   break;

                      }

/*10*/            swap( &A[ i ], &A[ Right-1] );

/*11*/            Qsort( A, Left, i-1 );

/*12*/            Qsort( A, i+1, Right );  

                }

                else                          

/*13*/           InsertionSort( A+Left , Right-Left+1)        

           }


②세 수의 중위수 계산, Pivot에 중앙값 넣기

⑤배열의 왼쪽에서부터 중앙값보다 큰 원소까지

   이동

⑥배열의 오른쪽에서부터 원소의 값이 중앙값보다

   작은 원소까지 이동

⑦⑧⑨정렬이 끝나지 않았으면 중앙값보다 작은

   원소는 왼쪽에, 큰 원소는 오른쪽에 들어가도록

   교체함. 정렬이 끝났으면 무한루프를 벗어남

⑩중앙값보다 큰 첫 번째 요소와 중앙값을 교환해

   중앙값을 작은 값과 큰 값 사이에 끼워 넣음.

   중위치 정렬

⑪왼쪽부분리스트(중앙값보다 작은부분)의 퀵정렬

⑫오른쪽부분리스트(중앙값보다 큰부분)의 퀵정렬

⑬원소가 Cutoff보다 작거나 같은 서브트리의

   삽입정렬

-----------------------------------------------------------------------------


성능

▷ 최악의 경우: O(n2)

평균: O(nlogn)

최선의 경우는 n 개의 데이터가 저장된 배열이 각 분할 단계에서 정확히 이등분 될 때

교환 비교 회수가 매우 적음 : 단순하고 매우 빠른 속도로 수행

안정성은 없음

난수 배열 반쯤 정렬된 배열 자료에 대해서는 성능이 우수

▷ 피봇이 중간 값을 갖도록 해야 수행속도가 좋아짐


##[퀵소트 다른 내용 보기]

출처 : 한국교원대학교 교육대학원 컴퓨터교육과

TAG