배열 A[1...N]의 N개 데이터를 Sort하는 가장 빠른 방법?
- 비교기반 정렬 (Comparison based Sorting) = Ω(N lgN)
- 선택정렬, 삽입정렬, 버블정렬 -> O(N^2)
- 쉘 정렬 -> O(N√N) / 최악 : O(N^2)
- 합병 정렬, 퀵 정렬, 힙 정렬, BST -> O(N lgN)
- 기수 정렬 -> O(N) [비교기반 정렬이 아님]
1. 선택 정렬 (Selection Sort)
전체를 탐색한 후, 최소or최대값을 왼쪽으로 이동시킴
- 왼쪽부터 차례로 검사하면서 가장 큰 수를 가장 왼쪽으로 이동
- 가장 왼쪽은 반복할때마다 한 칸씩 오른쪽으로 당겨짐
정상적으로 정렬된 것을 확인할 수 있음.
2. 삽입 정렬 (Insertion Sort)
뒤에서 시작해서 앞으로 가면서 작은 것을 만나면 멈춤.
Sort된 Data에는 Selection Sort보다 빠름.
- k의 데이터를 k-1 데이터와 비교하면서 k-1보다 k가 크면 swap을 반복
- k-1가 k보다 크면 정지.
Selection Sort와 달리 Instruction Count가 계속 달라짐. 24~37까지 본듯
Sort 된 data를 한번 더 Insertion Sort하면 Instruction Count가 9로 고정됨.
3. 버블 정렬 (Bubble Sort)
인접 두 원소를 비교하며 교환하는 작업을 반복
count == 0이 될때까지 j-1이 j보다 크면 위치교환을 반복.
해당 코드는 작은 숫자가 위로 오게 됨. (큰 숫자가 위로 오게 할려면 j-1 < j)
Sort에 걸리는 시간은 대부분 45근처로 나오되, 일부 정렬된 경우가 같이 있다면 저렇게 30근처까지 줄어들기도 함.
대신 2번 After Sort와 같이 역순으로 정렬된 데이터를 입력하면 무조건 최대의 시간을 사용함.
4. 쉘 정렬 (Shell Sorting)
간격별 subList를 만들고, 그걸 삽입정렬함. -> 약간 정렬된 데이터는 빠르게 끝남.
위 이미지와 같이 gap이 size의 절반으로 시작하고, gap 차이만큼의 원소들을 묶어서 subList로 만든 후 Insertion Sort.
gap이 1이하가 되면 끝.
이런식으로 구현했고, 정렬은 잘 작동한다.
이런식으로 정렬된 데이터는 똑같고, 이번 test에서는 Shell Sort가 Insertion Sort보다 빨랐다.
Insertion Sort가 더 빠른 경우도 존재함. 최악이 O(N^2)로 같으니까 데이터 형태에 따라 다른듯함.
5. 병합 정렬 (Merge Sort)
계속 배열을 반갈죽 내다가, 배열 내용이 1개가 되면 그 1개들 끼리 정렬해서 2개짜리가되고 이런식으로 배열을 계속 쪼개고 쪼개가지고 쪼개진 배열들끼리 정렬하는 방식이다.
이번 테스트코드는 10개의 데이터이므로
1. 1~5 / 6~10
2. 1~2 / 3~5 / 6~7 / 8~10
3. {1} / {2} / {3} / 4~5 / {6} / {7} / {8} / 9~10
4. {1, 2} / {3} / {4} / {5} / {6,7} / {8} / {9} / {10}
5. {1, 2} / {3} / {4, 5} / {6, 7} / {8} / {9, 10}
6. {1, 2} / {3, 4, 5} / {6, 7 } / {8, 9, 10}
7. {1, 2, 3, 4, 5} / {6, 7, 8, 9, 10}
8. {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
이런식으로 진행됬을 것, 근데 이거 빠른거 맞나?
정렬은 잘 작동한것을 볼 수 있다. Instruction Count는 34로 고정.
선택정렬이 45인것에 비해 벌써 30%? 정도 빨라진것을 볼 수 있음.
6. 퀵 정렬 (Quick Sort) | 같은 O(N lgN) 정렬 중에 가장 빠름
첫번째 원소를 pivot으로 두고, 그 원소보다 작은 원소와 큰 원소를 분리해서 배치함.
Pivot부터 오른쪽으로 진행하는 반복과 Pivot 정반대에서 왼쪽으로 진행하는 반복을 통해, pivot을 중점으로 정렬하고
pivot원소를 중앙으로 이동. 이것을 반복
list[0]을 pivot 원소로 지정하고
pivot보다 작은것, 큰것끼리 모은 후에 모아진 집단 사이에 pivot을 넣음. (for문 부분 + swap)
이 작업을 반복 (doQuick 2줄)
Quick Sort는 Pivot원소가 중앙으로 가면 갈수록 빠른 정렬이 가능해진다.
- 좌우 크기가 비슷하면 O(N lgN) 평균 속도
- 정렬된 데이터 -> O(N^2) Insertion Sort로 정렬된 데이터를 Quick Sort에 넣으면 근접해진다.
(함수 호출의 Inst count를 빼면 Insertion Sort를 거친건 24, 안거친건 6~ 까지 보임)
7. Heap 정렬
Heap을 구성한 후, 배열로 구성한다.
8. BST
- A[1...N] 배열에 N개 data의 BST(Balanced BST)를 구성함 : O(N lgN)
- 이 BST를 in-order로 방문하면서 data를 A에 다시 입력 : O(N)
=> O(N lgN) + O(N) = O(N lgN)
9. 선형 정렬(Linear Sort)
9-1) 기수 정렬 (Radix Sort, Bucket Sort) -> O(N)
A[1...N] 배열에 N개의 K자릿수의 10진 정수가 들어있음. (중복은 없으며, 배열 size N은 10^k보다 작다.)
이런식으로, 일의 자릿수부터 각 자릿수별로 정렬해서 다음 bucket에 입력.
bucket에 입력된 데이터를 위에서 부터 차례대로 수집.
수집한 데이터를 다음 자릿수로 다시 정렬.. 이것을 반복함.
9-2) 해시 데이터 (Hashing Sort) -> O(N)
해시는 매우 큰 size의 배열에 저장해서, 모든 항목을 검사할 필요 없이 데이터를 뽑아낼 수 있는 알고리즘임.
예를 들어, 32767이라는 숫자를 저장할때 Hash[32767]에 저장하는 느낌?
배열 내의 데이터를 모두 Hash에 넣은 뒤, 위에서부터 차례대로 수거하면 정렬됨.
{27, 05, 13, 49}가 있으면 Hash[05] = 05; Hash[13] =13; Hash[27] = 27; Hash[49] = 49; 가 되서
Hash[0]~Hash[M]까지 검사하면서 데이터를 수거하면 {05, 13, 27, 49}가 됨.
이 Hash는 정렬을 위한 알고리즘이 아님. ( 속도만을 위한 효율을 버린 알고리즘이 정렬을 위할 수는 없다.. )
'2-2공부 > 자료구조' 카테고리의 다른 글
기말준비-해싱(Hashing) (0) | 2021.12.09 |
---|---|
기말준비-그래프(Graph) (0) | 2021.12.09 |
기말준비-우선순위 큐 (Priority Queue) (0) | 2021.12.08 |
기말준비-트리(Tree) (0) | 2021.12.08 |
기말준비-큐(Queue) (0) | 2021.12.08 |