Software Courses/Data Structure

Shell sort (쉘 정렬)

김 정 환 2020. 12. 23. 13:08
반응형

쉘 정렬

    - 삽입 정렬의 문제점

        * 삽입할 위치가 현재 삽입할 요소와 멀리 떨어져 있다면, 많은 요소들을 옮겨야 함

 

    - 삽입 정렬의 문제점을 보완하는 정렬

    - 쉘 정렬은 특정 간격(k)에 있는 요소들을 부분 배열으로 하고 삽입 정렬을 진행하여 정렬

 

    - 쉘 정렬의 원리

        * 배열의 요소들이 정렬되어 있으면 삽입 정렬의 시간복잡도 O(N)

        * 배열의 요소들을 어느 정도 정렬 시켜 놓으면 삽입 정렬은 빠름

        * 어느 정도 정렬 시키기 위해서 배열을 간격 별로 모아서 부분 배열을 만들어 정렬

 

 

 

동작

    - 초기 간격(k)를 구함 : 정렬할 배열의 길이 / 2

    - 간격(k) 만큼 떨어진 요소들을 부분 집합으로 하고 삽입 정렬

    - 위 과정으로 한 번의 정렬이 끝나면, k = k / 2 하여 위 과정 반복

    - 간격(k)의 크기가 1이 될 때까지 반복

 

    - 예시

        * 1번 : 간격(k=4)로 부분 배열을 만들고, 부분 배열 내에서 삽입 정렬 진행

 

        * 2번 : 간격(k=2)로 부분 배열을 만들고, 부분 배열 내에서 삽입 정렬 진행

 

        * 3번 : k=1일 때, 전체가 부분 배열이 되어, 마치 삽입 정렬을 하는 것과 같음

 

구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 시작 인덱스부터 gap 간격에 있는 요소들로 부분 배열을 만들어 삽입 정렬  
int gap_insertion_sort(int list[], int first, int last, int gap){
    
  int i, j, value;
 
  // 삽입 정렬은 두 번째 인뎃스부터 진행하므로
  // 시작 인뎃스는 first + gap  
  for (i = first + gap; i <= last; i += gap)
  {
    // 삽입할 요소 선택  
    value = list[i];
 
    // 삽입할 value 이전에 있는 요소들과 비교 
    // 요소들은 간격 단위로 위치하므로 j -= gap으로 이동 
    // 이동 인덱스 j는 시작 위치 first와 같거나 커야 하고
    // 비교되는 list[j]의 값은 삽입할 value보다 커야 한다. 
    for (j = i - gap; j >= first && list[j] > value; j -= gap)
    {
      // 비교되는 list[j]가 삽입할 value보다 크다면 뒤로 옮긴다.
      // 옮길 때는 gap 간격으로 옮긴다. 
      list[j + gap] = list[j];
    }
    
    // 멈춘 곳에 삽입할 value를 삽입한다. 
    list[j + gap] = value;
  }
  
}
 
// 쉘 정렬
int shell_sort(int list[], int n){
    
  int gap, i;
 
  // 초기 gap은 배열 크기의 1/2
  // 이후 gap을 1/2 해준다. 
  for (gap = n/2; gap > 0; gap /= 2){
 
    // 배열의 i번째부터 gap 간격에 있는
    // 요소들을 찾아서 삽입 정렬 
    for (i = 0; i < gap; i++)
      gap_insertion_sort(list, i, n - 1, gap);
  }
  
}
cs

 

 

특징

    - 간격(k)에 의해 만들어진 비연속적은 부분 배열에서 삽입 정렬이 일어나기 때문에 요소들은 더 큰 거리를 이동한다. 더 큰 거리를 이동했다는 의미는 선택된 요소가 최종 위치에 더 가깝게 배치된다는 뜻이다. 따라서 연산량이 줄어 더 빠르다.

 

    - 간격(k)를 결정하는 방법은 여러 가지 이다. 일반적으로 간격을 반으로 나누거나, 반으로 나누어서 + 1 하여 홀수로 만든다. 

 

    - 삽입 정렬은 정렬된 배열에서 빠르게 정렬하는 특징이 있다. 쉘 정렬에서는 부분 배열을 만들기 때문에 큰 배열보다 정렬할 요소가 적어서 덜 복잡하다고 할 수 있다. 덜 복잡한 부분 배열을 삽입 정렬로 처리하면서 전체 배열을 정렬로 만든다. 따라서 삽입 정렬보다 더 빠르다.

 

 

 

참고

    - 블로그 1

    - 블로그 2

    - 블로그 3

    - 위키피디아

 

 

반응형

'Software Courses > Data Structure' 카테고리의 다른 글

Merge sort (병합 정렬)  (0) 2020.12.23
Bubble sort (버블 정렬)  (0) 2020.12.23
Insertion sort (삽입 정렬)  (0) 2020.12.22
Selection sort(선택 정렬)  (0) 2020.12.22
Shortest path (최단 경로)  (0) 2020.12.22