-
쉘 정렬개발 지식/알고리즘 2020. 7. 9. 04:58
JAVA로 작성되었습니다.
쉘 정렬
- 삽입 정렬을 개산한 알고리즘, 바탕은 삽입정렬을 기본으로 진행한다.
- 가까운 위치에 삽입되는 (어느정도 정렬이 되어있는) 삽입정렬이 빠른 것을 이용하여 삽입정렬을 하기 전 배열을 어느정도 정렬한 상태에서 삽입정렬을 진행하는정렬 방식이다.
- 이때 gap이라는 것이 존재하는데 gap만큼 배열을 띄엄띄엄 정렬하는데 사용한다.
- 갭을 설정한다. 갭의 값은 이전 갭의 절반으로 설정한다.
(초기 값은 배열의 크기 / 2 로 설정한다)
(홀수를 권장하므로 2로 나누었을 때 짝수가 나온다면 +1을 하여 홀수로 정한다.) - 원본 배열에서 다음 요소와 인덱스의 차이가 gap만큼 있는 부분 배열들을 생성한다.
(리스트의 길이가 11(0~10)이고 갭이 5라면
(0, 5, 10), (1, 6), (2, 7), (3, 8), (4, 9)) - 부분 배열들을 각각 삽입정렬해준다.
- 각각의 부분들의 정렬이 완료되면 다음 갭 (나누기 2)으로 부분 삽입정렬을 다시 실행한다.
- 갭이 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