μ •λ ¬ κΈ°λ³Έ
Β - Last update: 2023-05-22

μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜ κ΄€λ ¨ κΈ°λ³Έ 정리

O(n^2) μ•Œκ³ λ¦¬μ¦˜

Selection Sort

μ„±λŠ₯ μš”κ΅¬μ‚¬ν•­μ΄ μ—†κ±°λ‚˜, n이 μž‘μ„ λ•Œ μ‚¬μš©ν•˜λŠ” 방식. κ΅¬ν˜„μ„ μžŠμ–΄λ²„λ¦΄ 수 μ—†μ„λ§ŒνΌ κ°„λ‹¨ν•˜λ‹€.

void selSort(T arr[], int size) {
for(int i = 0; i < size; ++i) {
for(int j = i + 1; j < size; ++j) {
if (arr[i] > arr[j]) {
T tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
}

Insertion Sort

데이터가 λ’€μͺ½μœΌλ‘œ 1κ°œμ”© μΆ”κ°€λ˜λŠ” κ²½μš°μ—, O(n)으둜 제일 λΉ λ₯΄λ‹€. λ˜ν•œ memory의 localityλ₯Ό 살릴 수 μžˆλŠ” λ°©μ‹μœΌλ‘œ 유λͺ…ν•˜λ‹€.

이 방식은, i-1λ²ˆμ§ΈκΉŒμ§€ μ›μ†Œλ“€μ΄ 이미 μ •λ ¬λ˜μ–΄μžˆλ‹€κ³  κ°€μ •ν•˜κ³ , i번쨰 μ›μ†Œλ₯Ό μ μ ˆν•œ 곳에 μ‚½μž…ν•˜λŠ” λ°©μ‹μ΄λΌμ„œ, Insertion sort 라고 λΆˆλ¦°λ‹€. 이 λ°©μ‹μ˜ 경우 swap보닀 assign 연산을 1회 쀄일 수 μžˆμ–΄μ„œ 더 λΉ λ₯΄λ‹€. μ‹€μ œλ‘œ, O(n^2) μ•Œκ³ λ¦¬μ¦˜ 쀑에 제일 λΉ λ₯΄λ‹€κ³  ν•  수 μžˆλ‹€.

void insertionSort(T arr[], int size) {
for(int i = 1; i < size; ++i) {
T tmp = arr[i]; // λΉ„κ΅ν•˜κ³ μž ν•˜λŠ” μ›μ†Œλ₯Ό μž„μ‹œλ‘œ μ €μž₯ν•œλ‹€.
int j = i - 1;
for(; j >= 0; --j) { // j μœ„μΉ˜λ₯Ό 0κΉŒμ§€ κ°€λ©΄μ„œ μ‚½μž…ν•  곳을 μ°ΎλŠ”λ‹€.
if (arr[j] < tmp) break;
arr[j+1] = arr[j]; // swap λŒ€μ‹ μ—, λ’€μͺ½μœΌλ‘œ μ›μ†Œλ₯Ό 1개 λ―Όλ‹€.
}
arr[j+1] = tmp; // μ΅œμ’… λͺ©μ μ§€μ— μž„μ‹œλ‘œ μ €μž₯ν•œ μ›μ†Œλ₯Ό λ„£κ³  λ§ˆλ¬΄λ¦¬ν•œλ‹€.
}
}

O(n log n) μ•Œκ³ λ¦¬μ¦˜

Quick Sort

stable ν•˜μ§€λŠ” μ•Šμ§€λ§Œ, μž‘μ„±μ΄ 쉽고 λžœλ€ν•œ 뢄포λ₯Ό κ°€μ§€λŠ” 데이터에 λŒ€ν•΄μ„œ μ„±λŠ₯이 λΉ λ₯΄λ‹€. μ•„λž˜ μ½”λ“œμ˜ ꡬ간은 [s, e] 이닀.

void qSort(T arr[], int s, int e) {
int l = s, r = e;
T pivot = arr[(s + e) >> 1];
while(l < r) {
while(arr[l] < pivot) ++l;
while(pivot < arr[r]) --r;
if (i > j) break;
T tmp = arr[l];
arr[l] = arr[r];
arr[r] = tmp;
++l; --r;
}
qSort(arr, s, r);
qSort(arr, l, e);
}

Merge Sort

stable ν•œ μ •λ ¬ 쀑에 제일 빠름. μ•ˆμ •μ . worst에도 O(n log n)이 보μž₯λ˜μ–΄ PSμ—μ„œ 자주 쓰인닀. Quick Sort λŒ€λΉ„ λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰μ΄ 2배이기 λ•Œλ¬Έμ—, κ°œμΈμ μœΌλ‘œλŠ” 덜 μ„ ν˜Έν•˜λŠ” νŽΈμ΄μ§€λ§Œ, stable이 ν•„μš”ν•œ κ²½μš°μ—λŠ” μ–΄μ©” 수 없이 μ‚¬μš©λ˜μ–΄μ•Ό ν•œλ‹€.

ꡬ간은 λ§ˆμ°¬κ°€μ§€λ‘œ [s, e] 둜 λ‚˜λˆ„λŠ” 것이 μƒκ°ν•˜κΈ°μ— κ°„λ‹¨ν•˜λ‹€.

T tmp[MAX_SIZE];
void mergeSort(T arr[], int s, int e) {
if (s >= e) return;
int mid = (s + e) >> 1;
mergeSort(arr, s, mid);
mergeSort(arr, mid + 1, e);
int i = s, j = mid + 1;
int k = s;
for(;i <= mid && j <= e;) {
if (arr[i] < arr[j])
tmp[k++] = arr[i++];
else
tmp[k++] = arr[j++];
}
for(;i <= mid; ++i, ++k)
tmp[k] = arr[i];
for(;j <= e; ++j, ++k)
tmp[k] = arr[j];
for(i = s; i <= e; ++i)
arr[i] = tmp[i]; // realloc
}

λ”±νžˆ 더 λΉ λ₯΄μ§„ μ•Šμ§€λ§Œ λ‘λ‡ŒνšŒμ „μ„ μœ„ν•΄ μ•„λž˜μ™€ 같은 μ½”λ“œ μΆ•μ•½ 버전도 ν•œλ²ˆ κΈ°μ–΅ν•΄λ³΄μž. 두 쑰건을 λ§Œμ‘±ν•  λ•Œ i++λ₯Ό μ“°κ³ , λ‚˜λ¨Έμ§€μ˜ 경우 j++λ₯Ό μ“°λŠ” 것. i++의 μ‚¬μš©μ‘°κ±΄λ§Œ μ •ν•΄μ§€λ©΄ λ‚˜λ¨Έμ§€λŠ” j++κ°€ λ˜λŠ” 것에 μ°©μ•ˆν•œλ‹€.

  1. ν˜„μž¬ jκ°€ e λ²”μœ„λ₯Ό 이미 μ΄ˆκ³Όν–ˆκ±°λ‚˜ (무쑰건 iλ₯Ό 써야함)
  2. λ˜λŠ” iκ°€ λ²”μœ„ μ•ˆμ΄λ©΄μ„œ, arr[i] <= arr[j] 일 λ•Œ. (λ“±ν˜Έ 쑰건이 μžˆμ–΄μ•Ό stable이닀)

μ΄λ ‡κ²Œ μΆ•μ•½ν•˜λ©΄, Quick Sort보닀 였히렀 μ½”λ“œ μž‘μ„±λŸ‰μ΄ 적닀.

T tmp[MAX_SIZE];
void mergeSort(T arr[], int s, int e) {
if (s >= e) return;
int mid = (s + e) >> 1;
mergeSort(arr, s, mid);
mergeSort(arr, mid + 1, e);
int i = s, j = mid + 1;
int k = s;
for(;k <= e;++k)
// μ•„λž˜μ—μ„œ arr[i] <= arr[j] 의 κ΄„ν˜Έκ°€ λΉ μ§€μ§€ μ•Šμ•„μ•Ό stable μž„μ— 유의!
tmp[k] = ((j > e) || (i <= mid) && (arr[i] <= arr[j])) ? arr[i++] : arr[j++];
for(i = s; i <= e; ++i)
arr[i] = tmp[i]; // realloc
}

특수 μ•Œκ³ λ¦¬μ¦˜

Bucket Sort

Radix Sort, Bucket Sort λͺ¨λ‘ 같은 κ°œλ…μ΄λ‹€. ν”νžˆλ“€ 10진법을 Radix Sort에 μ‚¬μš©ν•˜κ³€ ν•˜λŠ”λ°, 사싀 그럴 ν•„μš”κ°€ μ—†λ‹€. λ©”λͺ¨λ¦¬ 곡간은 훨씬 더 많이 μ‚¬μš©ν•  수 μžˆμœΌλ―€λ‘œ, 65536진법 = 1<<16 진법을 μ‚¬μš©ν•˜μ—¬, short 만큼의 1 << 16 배열에 Counting ν•΄μ„œ λ„£λŠ” λ°©μ‹μœΌλ‘œ λ°˜λ³΅ν•˜λ©΄, int λ²”μœ„μ˜ μˆ˜λ„ μ‰½κ²Œ μ •λ ¬ν•  수 μžˆλ‹€. Counting ν•œ 배열을 μ΄μš©ν•˜λ©΄, 총 μ‹œκ°„λ³΅μž‘λ„ O(n) 에 정렬이 μ™„μ„±λœλ‹€. (μ •ν™•νžˆλŠ” λ¬Όλ‘  O(n)의 μƒμˆ˜λ°° λ˜κ² λ‹€) 사싀 μœ„ μ•Œκ³ λ¦¬μ¦˜λ“€κ³Ό λΉ„κ΅ν•˜λ©΄ 말도 μ•ˆλ  μ •λ„λ‘œ λΉ λ₯Έ μ•Œκ³ λ¦¬μ¦˜μ΄λΌκ³  λ³Ό 수 μžˆλ‹€.

이 경우 T type generic을 μ“Έ 수 μ—†κ³ , ꡬ체적인 λ²”μœ„μ˜ 수 λ²”μœ„κ°€ ν•„μš”ν•˜λ‹€. κ°€μž₯ κ°„λ‹¨ν•œ unsigned int의 μ˜ˆμ‹œκ°€ μ•„λž˜μ™€ κ°™λ‹€.

unsigned int cnt[1<<16 | 1];
unsigned int acc[1<<16 | 1];
unsigned int tmp[ARR_SIZE];
unsigned int cnt2[1<<16 | 1];
unsigned int acc2[1<<16 | 1];
void bucketSort(unsigned int arr[]) {
// ν•˜μœ„ λΆ€λΆ„ μ •λ ¬
for(int i = 0; i < ARR_SIZE; ++i)
cnt[arr[i] & 0xFFFF]++;
for(int i = 1; i <= (1<<16); ++i)
acc[i] = acc[i - 1] + cnt[i - 1];
for(int i = 0; i < ARR_SIZE; ++i)
tmp[acc[arr[i] & 0xFFFF]++] = arr[i];
// μƒμœ„ λΆ€λΆ„ μ •λ ¬
for(int i = 0; i < ARR_SIZE; ++i)
cnt2[arr[i] >> 16]++;
for(int i = 1; i <= (1<<16); ++i)
acc2[i] = acc2[i - 1] + cnt2[i - 1];
for(int i = 0; i < ARR_SIZE; ++i)
arr[acc[tmp[i] >> 16]++] = tmp[i];
}

ν•˜μœ„ bit -> μƒμœ„ bit 순으둜 정렬을 ν•˜λŠ” μ΄μœ λŠ” μƒμœ„ bit의 영ν–₯λ ₯이 더 크기 λ•Œλ¬Έμ΄λΌκ³  μ΄ν•΄ν•˜λ©΄ 쉽닀.

🏷️ 주제 λͺ©λ‘: