[Data Structure] 쉘 정렬 - Shell Sort
2022. 1. 1. 17:21ㆍMajor`/자료구조
쉘 정렬 (Shell Sort)
Unstable Sort
- 정렬할 리스트의 간격에 따라서 각 부분 리스트를 정렬하는 정렬 알고리즘
- 간격(gap) = 리스트/2/2/2,...... → 계속해서 2로 나눠준다 (1이 될 때 까지)
- 만약 gap이 짝수이면 1을 더해준다 (간격이 홀수이면 더 성능이 좋다)
- 부분 리스트의 개수는 gap과 동일하다
- 보통 전체에서 h/2를 하지만 이보다 h/3 + 1 이 더 빠르다
시간복잡도
- 최선 : O(n)
- 평균/최악 : O(n1.5)
장점
- Insertion Sort의 단점을 보완하고 개념을 확대해서 만든 정렬
- Insertion Sort보다 성능이 우수하다
- 데이터가 본인의 index에서 멀리 떨어져 있을 경우, 교환을 여러번하는 Bubble Sort의 단점을 해결
단점
- 일정한 간격에 따라서 배열을 해석해야하고, 간격을 잘못 설정하면 성능이 저하된다
과정
- 정렬할 리스트(A)를 간격에 따라서 부분 리스트를 생성 -- (1)
- 각 부분 리스트를 정렬 -- (2)
- 간격이 1이 될 때 까지 (1), (2) 반복
※ Example
배열 A : {10, 8, 6, 20, 4, 3, 22, 1, 0, 15, 16} / 크기 = 11
▶ Gap = 5 (11/2) → 부분 리스트 5개
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
List 0 | 10 | 3 | 16 | ||||||||
List 1 | 8 | 22 | |||||||||
List 2 | 6 | 1 | |||||||||
List 3 | 20 | 0 | |||||||||
List 4 | 4 | 15 |
- List 0
- List 0[5] = 3 (value)
- → gap만큼 아래로 내려가서 해당 요소와 비교 (index = 5-gap)
- → List 0[index] (10) > List 0[5] (3)
- → 서로 자리 change → List 0[index+gap] = List 0[index]
- → 더 이상 내려갈 수 없기 때문에 List 0[index+gap] = value
- → List 0[5+gap+gap,... < 10] 까지 동일하게 수행
- List 1,2,3,4도 동일한 방식으로 수행
3 | 8 | 1 | 0 | 4 | 10 | 22 | 6 | 20 | 15 | 16 |
▶ Gap = 3 (5/2+1) → 부분 리스트 3개
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
List 0 | 3 | 0 | 22 | 15 | |||||||
List 1 | 8 | 4 | 6 | 16 | |||||||
List 2 | 1 | 10 | 20 |
- List 0
- List 0[first+gap] = List 0[0+3] = List 0[3] = 0 (value)
- → gap 만큼 내려가서 해당 요소와 비교 (index = 3-gap)
- → List 0[index] (3) > List 0[3] (0)
- → 서로 자리 change → List 0[index+gap] = List 0[index] 후, index-=gap
- → 더 이상 내려갈 수 없기 때문에 List 0[index+gap] = value
- → List 0[3+gap+gap+,.... < 10] 까지 동일하게 수행
- List 1
- List 1[first+gap] = List 1[1+3] = List 1[4] = 4 (value)
- → gap 만큼 내려가서 해당 요소와 비교 (index = 4-gap)
- → List 1[index] (8) > List 1[4] (4)
- → 서로 자리 change 후, index-=gap
- → 더 이상 내려갈 수 없기 때문에 List 1[index+gap] = List 1[1] = value(4)
- List 1[4+gap] = List 1[7] = 6(value)
- → List 1[4] (8) > List 1[7] (6)
- → 서로 자리 cahnge 후, index-=gap
- → gap만큼 또 내려가면 해당 요소는 value보다 크므로 변화 X
- 계속해서 반복
0 | 4 | 1 | 3 | 6 | 10 | 15 | 8 | 20 | 22 | 16 |
0 | 1 | 3 | 4 | 6 | 8 | 10 | 15 | 16 | 20 | 22 |
▶ Shell Sort
static void shell_sort(int [] A){
for(int gap = A.length/2; gap>0; gap/=2){
if(gap%2==0) gap+=1; // gap이 짝수면 홀수로 만들어주기
System.out.println("## Gap : " + gap);
for(int i=0; i<gap; i++) { // gap개수만큼 부분 리스트 생성
gap_list_sort(A, i, A.length, gap);
}
}
}
static void gap_list_sort(int []A, int first, int last, int gap){
// gap에 따른 부분 리스트 (부분 리스트개수 = gap)
for(int i=first+gap; i<last; i+=gap){
int value = A[i]; // index가 gap인 위치의 요소
int index = i-gap; // value보다 낮은 위치의 요소들을 비교
while((index>=0) && (A[index]>value)){
// value보다 낮은 위치의 요소가 value보다 크면
A[index+gap] = A[index];
// 서로 위치를 change
index-=gap;
// gap만큼 내려가서 해당 위치의 요소와도 비교
}
A[index+gap] = value;
// index가 gap인 위치에서부터 시작해서 gap만큼 내려가서 해당 위치에 value insert
/*
gap = 3, A[0] = 3, A[3] = 0, A[6] = 22, A[9] = 15
index가 gap인 위치의 요소 = 0 (value)
0의 index-gap 위치에 있는 요소와 비교 ( A[index-gap](3) > value )
-> index-gap 위치에 있는 요소와 index-gap+gap에 있는 요소와 서로 change
index가 gap+gap+,.... 인 요소들도 똑같이 반복
*/
}
}
▶ Full Code
package Sort;
import java.util.Calendar;
public class Shell_Sort_6 {
public static void main(String[] args) {
int [] A = new int[11]; // 정렬할 배열 A
for(int i=0; i<A.length; i++)
A[i] = (int)(Math.random()*151); // 0~151
// 정렬 전 A 출력
System.out.print("A[]");
for(int i=0; i<A.length; i++){
if(i%20==0) System.out.println();
System.out.print(A[i] + "\t");
}
System.out.println("\n");
shell_sort(A);
}
static void shell_sort(int [] A){
Calendar before = Calendar.getInstance();
for(int gap = A.length/2; gap>0; gap/=2){
if(gap%2==0) gap+=1; // gap이 짝수면 홀수로 만들어주기
System.out.println("## Gap : " + gap);
for(int i=0; i<gap; i++) { // gap개수만큼 부분 리스트 생성
System.out.println("-> 부분 리스트 " + i + " 정렬 전");
for(int t=i; t<A.length; t+=gap){
//if(t%20==0) System.out.println();
System.out.print(A[t] + "\t");
}
System.out.println();
gap_list_sort(A, i, A.length, gap);
System.out.println("-> 부분 리스트 " + i + " 정렬 후");
for(int t=i; t<A.length; t+=gap){
//if(t%20==0) System.out.println();
System.out.print(A[t] + "\t");
}
System.out.println("\n");
}
System.out.println();
}
Calendar after = Calendar.getInstance();
// 정렬 후 A 출력
System.out.print("result[]");
for(int i=0; i<A.length; i++){
if(i%20==0) System.out.println();
System.out.print(A[i] + "\t");
}
System.out.println("\n");
int time = after.get(Calendar.MILLISECOND) - before.get(Calendar.MILLISECOND);
System.out.println("걸린 시간 : " + time + "ms");
}
static void gap_list_sort(int []A, int first, int last, int gap){
// gap에 따른 부분 리스트 (부분 리스트개수 = gap)
for(int i=first+gap; i<last; i+=gap){
int value = A[i]; // index가 gap인 위치의 요소
int index = i-gap; // value보다 낮은 위치의 요소들을 비교
while((index>=0) && (A[index]>value)){
// value보다 낮은 위치의 요소가 value보다 크면
A[index+gap] = A[index];
// 서로 위치를 change
index-=gap;
// gap만큼 내려가서 해당 위치의 요소와도 비교
}
A[index+gap] = value;
// index가 gap인 위치에서부터 시작해서 gap만큼 내려가서 해당 위치에 value insert
/*
gap = 3, A[0] = 3, A[3] = 0, A[6] = 22, A[9] = 15
index가 gap인 위치의 요소 = 0 (value)
0의 index-gap 위치에 있는 요소와 비교 ( A[index-gap](3) > value )
-> index-gap 위치에 있는 요소와 index-gap+gap에 있는 요소와 서로 change
index가 gap+gap+,.... 인 요소들도 똑같이 반복
*/
}
}
}