ABOUT ME

-

  • 쉘 정렬
    개발 지식/알고리즘 2020. 7. 9. 04:58

    JAVA로 작성되었습니다.

    쉘 정렬

    • 삽입 정렬을 개산한 알고리즘, 바탕은 삽입정렬을 기본으로 진행한다.
    • 가까운 위치에 삽입되는 (어느정도 정렬이 되어있는) 삽입정렬이 빠른 것을 이용하여 삽입정렬을 하기 전 배열을 어느정도 정렬한 상태에서 삽입정렬을 진행하는정렬 방식이다.
    • 이때 gap이라는 것이 존재하는데 gap만큼 배열을 띄엄띄엄 정렬하는데 사용한다.

     

    1. 갭을 설정한다. 갭의 값은 이전 갭의 절반으로 설정한다.
      (초기 값은 배열의 크기 / 2 로 설정한다)
      (홀수를 권장하므로 2로 나누었을 때 짝수가 나온다면 +1을 하여 홀수로 정한다.)
    2. 원본 배열에서 다음 요소와 인덱스의 차이가 gap만큼 있는 부분 배열들을 생성한다.
      (리스트의 길이가 11(0~10)이고 갭이 5라면
      (0, 5, 10), (1, 6), (2, 7), (3, 8), (4, 9))
    3. 부분 배열들을 각각 삽입정렬해준다.
    4. 각각의 부분들의 정렬이 완료되면 다음 갭 (나누기 2)으로 부분 삽입정렬을 다시 실행한다.
    5. 갭이 1이 될 때까지 정렬을 진행한다. ( = 어느정도 정렬된 배열의 삽입정렬)

    정렬 시각화

    - 1

    6 2 4 0 2 5 1 8 7 4 10
    6         5         10
      2         1        
        4         8      
          0         7    

    ->

    5 1 4 0 2 6 2 8 7 4 10
    5         6         10
      1         2        
        4         8      
          0         7    
            2         4  

    - 2

    5 1 4 0 2 6 2 8 7 4 10
    5     0     2     4  
      1     2     8     10
        4     6     7    

    ->

    0 1 4 2 2 6 4 8 7 5 10
    0     2     4     5  
      1     2     8     10
        4     6     7    

    - 3

    0 1 4 2 2 6 4 8 7 5 10
    0 1 4 2 2 6 4 8 7 5 10

    ->

    0 1 2 2 4 4 5 6 7 8 10
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    public class ShellSort {
        public int[] array_selection(int[] arr, int gap, int start_index) {
            for (int i = start_index + gap; i < arr.length; i += gap) {
                int j, value = arr[i];
                for (j = i - gap; j >= start_index && arr[j] > value; j -= gap) {
                    arr[j + gap] = arr[j];
                }
                arr[j + gap] = value;
            }
    
            return arr;
        }
    
        public int[] array_shell(int[] arr) {
            for (int gap = arr.length / 2; gap > 0; gap = gap / 2) {
                if (gap % 2 == 0) { gap++; }
    
                for (int i = 0; i < gap; i++) {
                    ShellSort shellSort = new ShellSort();
                    arr = shellSort.array_selection(arr, gap, i);
                }
            }
    
            return arr;
        }
    
        public List<Integer> list_shell(List<Integer> list, int prev_gap) {
            // 이전 gap의 절반을 gap으로 설정, 짝수가 나오면 +1을 하여 홀수로 설정
            int gap = (prev_gap  % 2 == 0) ? prev_gap / 2 + 1 : prev_gap / 2;
            // 0부터 +gap 한 애들 삽입정렬
            // 그렇다면 갭의 크기만큼 반복문이 있겠지?
            for (int i = 0; i < gap; i++) {
                // 리스트의 길이가 10(0~9)이고 갭이 5라면
                // (0, 5), (1, 6), (2, 7), (3, 8), (4, 9) 다섯번 반복하는 삽입정렬
                // ex) 0과 5를 삽입정렬 -> 1과 6을 삽입정렬 -> ...
               for (int j = i + gap; j < list.size(); j += gap) {
                   int k, value = list.get(j);
                   for (k = j - gap; k >= i && list.get(k) > value; k -= gap) {
                       list.set(k + gap, list.get(k));
                   }
                   list.set(k + gap, value);
               }
            }
            if (gap != 1) {
                list = list_shell(list, gap);
            }
            return list;
        }
        public static void main(String[] args) {
            List<Integer> list = new ArrayList<Integer>();
            Random random = new Random();
            ShellSort shellSort = new ShellSort();
            ListAccuracy listAccuracy = new ListAccuracy();
    
            int[] arr = new int[10];
    
            for (int i = 0; i < arr.length; i++) {
                arr[i] = random.nextInt(10);
            }
            System.out.print("before: ");
            listAccuracy.array_print(arr);
    
            shellSort.array_shell(arr);
            System.out.print("after: ");
            listAccuracy.array_print(arr);
    
            for (int i = 0; i < 10; i++) {
                list.add(random.nextInt(10));
            }
            List<Integer> origin_copy = new ArrayList<Integer>(list);
            System.out.println("before: " + list);
    
            list = shellSort.list_shell(list, list.size());
            System.out.println("after: " + list);
    
            // 윈본과 일치율을 확인하는 코드가 작성되어있다.
            // 합병정렬에서 구현한 코드와 동일하다.
            listAccuracy.accuracy_test(origin_copy, list);
        }
    }

    '개발 지식 > 알고리즘' 카테고리의 다른 글

    합병 정렬  (0) 2020.07.09
    탐색 (선형 탐색, 트리 탐색, AVL, 회전 연산)  (0) 2020.07.01
    트리 (완전 이진, 포화 이진, Max-heap, Min-heap)  (0) 2020.06.30
    스택, 큐  (0) 2020.06.30
    메모리 관리  (0) 2020.06.30

    댓글

Designed by Tistory.