-
다양한 정렬 알고리즘Computer Science/Algorithm 2021. 9. 25. 10:47
정렬 알고리즘의 종류
ㆍ 선택 정렬
ㆍ 삽입 정렬
ㆍ 쉘 정렬
ㆍ 계수 정렬
ㆍ 기수 정렬
ㆍ 병합 정렬 (Top-Down)
ㆍ 병합 정렬 (Bottom-Up)
구현 방법
추상 클래스
public abstract class AbstractSort { public static void sort(Comparable[] a) { }; /** compare the size of two elements */ protected static boolean less(Comparable v, Comparable w) { return v.compareTo(w) < 0; } /** change two elements */ protected static void exch(Comparable[] a, int i, int j) { Comparable t = a[i]; a[i] = a[j]; a[j] = t; } /** show all elements in an array */ protected static void show(Comparable[] a) { for (int i = 0; i < a.length; i++) { System.out.print(a[i] + " "); } System.out.println(); } /** check if the array is sorted */ protected static boolean isSorted(Comparable[] a) { for (int i = 1; i < a.length; i++) { if (less(a[i], a[i - 1])) return false; } return true; } }
ㆍ 각각의 정렬 알고리즘들이 상속받을 추상 클래스를 구현하였다.
선택 정렬
public class Selection extends AbstractSort { public static void sort(Comparable[] a) { int N = a.length; for (int i = 0; i < N - 1; i++) { int min = i; for (int j = i + 1; j < N; j++) { if (less(a[j], a[min])) min = j; } exch(a, i, min); } } }
ㆍ 입력된 배열 리스트에서 최솟값을 찾고, 이 값을 현재 위치의 값과 교환한다.
ㆍ 그리고 현재 위치를 다음으로 이동하면서 앞에 과정을 반복해나가는 방식이다.삽입 정렬
public class Insertion extends AbstractSort { public static void sort(Comparable[] a) { int N = a.length; for (int i = 0; i < N; i++) { for (int j = i; j > 0 && less(a[j], a[j - 1]); j--) exch(a, j, j - 1); } } }
ㆍ 현재 위치를 i라고 한다. (0 < i < n)
ㆍ i 번째 원소를 0부터 i-1까지 정렬된 배열 리스트에 추가한다.
ㆍ i를 n-1까지 증가하면서 위 과정을 반복한다.쉘 정렬
public class Shell extends AbstractSort { public static void sort(Comparable[] a) { int N = a.length; int h = 1; while (h < N / 3) h = 3 * h + 1; while (h >= 1) { for (int i = h; i < N; i++) { for (int j = i; j >= h && less(a[j], a[j - h]); j -= h) exch(a, j, j - h); } h = h / 3; } } }
ㆍ hr, hr-1, ..., h1까지의 수열을 가정한다. (h1 = 1, hi-1 < hi)
ㆍ 처음에는 hr개 떨어진 원소들 간에 삽입 정렬을 한다.
ㆍ 이후 hr-1부터 h1까지 h를 줄이면서 삽입 정렬을 하는 방식이다.계수 정렬
public class Counting { public static int[] sort(int[] A, int K) { int i, N = A.length; int[] C = new int[K]; int[] B = new int[N]; for (i = 0; i < N; i++) C[A[i]]++; for (i = 1; i < K; i++) C[i] += C[i - 1]; for (i = N - 1; i >= 0; i--) B[--C[A[i]]] = A[i]; return B; } }
ㆍ 키 값이 0 ~ K-1 사이의 정수일 경우 적용 가능한 정렬이다.
ㆍ 입력 배열: A[n], 임시 배열: C[K], 결과 배열: B[n]을 사용하여 정렬을 한다.
ㆍ A[] 배열에 나오는 모든 값들에 대해 그 빈도수를 C[] 배열에 계산한다.
ㆍ A[i] = 72이며, C[0] 부터 C[71]까지의 합이 53일 때, B[53]에 72를 저장하는 방식이다.ㆍ 계수 정렬이 동작하는 과정은 위 사진과 같다.
기수 정렬
public class Radix { public static void sort(int[] A) { int i, m = A[0]; int exp = 1; int N = A.length; int[] B = new int[N]; for (i = 1; i < N; i++) if (A[i] > m) m = A[i]; while (m / exp > 0) { int[] C = new int[10]; for (i = 0; i < N; i++) C[(A[i] / exp) % 10]++; for (i = 1; i < 10; i++) C[i] += C[i - 1]; for (i = N - 1; i >= 0; i--) B[--C[(A[i] / exp) % 10]] = A[i]; for (i = 0; i < N; i++) A[i] = B[i]; exp *= 10; } } }
ㆍ 낮은 자릿수부터 비교하여 정렬하는 형태의 알고리즘이다.
ㆍ 낮은 자릿수의 정렬이 끝나면 높은 자릿수 순서대로 위 과정을 반복한다.병합 정렬(Top-Down)
public class MergeTD extends AbstractSort { private static void merge(Comparable[] a, Comparable[] aux, int low, int middle, int high) { /** copy the contents of the a[] to the aux[] */ for (int k = low; k <= high; k++) aux[k] = a[k]; int i = low; int j = middle + 1; /** compare the aux[] and save the merged result back to the a[] */ for (int k = low; k <= high; k++) { if (i > middle) a[k] = aux[j++]; else if (j > high) a[k] = aux[i++]; else if (less(aux[j], aux[i])) a[k] = aux[j++]; else a[k] = aux[i++]; } } public static void sort(Comparable[] a) { Comparable[] aux = new Comparable[a.length]; sort(a, aux, 0, a.length - 1); } private static void sort(Comparable[] a, Comparable[] aux, int low, int high) { if (high <= low) return; int middle = low + (high - low) / 2; sort(a, aux, low, middle); sort(a, aux, middle + 1, high); merge(a, aux, low, middle, high); } }
ㆍ 배열을 두 부분으로 분할한다.
ㆍ 각 부분을 재귀적으로 정렬한다.
ㆍ 두 부분을 병합하는 순으로 정렬이 이루어진다.ㆍ Top-Down 병합 정렬의 동작 과정은 위 사진과 같다.
병합 정렬 (Bottom-Up)
public class MergeBU extends AbstractSort { private static void merge(Comparable[] in, Comparable[] out, int low, int middle, int high) { int i = low; int j = middle + 1; /** merge in[] and store in out[] */ for (int k = low; k <= high; k++) { if (i > middle) out[k] = in[j++]; else if (j > high) out[k] = in[i++]; else if (less(in[j], in[i])) out[k] = in[j++]; else out[k] = in[i++]; } } public static void sort(Comparable[] a) { Comparable[] src = a; Comparable[] dst = new Comparable[a.length]; Comparable[] tmp; int N = a.length; /** array size of the parts to be merged */ for (int n = 1; n < N; n *= 2) { /** array position of the part to be merged */ for (int i = 0; i < N; i += 2 * n) merge(src, dst, i, i + n - 1, Math.min(i + 2 * n - 1, N - 1)); tmp = src; src = dst; dst = tmp; } if (src != a) System.arraycopy(src, 0, a, 0, N); } }
ㆍ 배열에서 크기 1인 부분 즉, 배열 내 원소 단위부터 병합을 한다.
ㆍ 부분의 크기를 2, 4, 8, ... 로 증가하면서 위 과정을 반복한다.ㆍ Bottom-Up 병합 정렬의 동작 과정은 위 사진과 같다.
참고 문헌 및 자료
ㆍ R.Sedgewick and K. Wayne, Algorithms (4th Ed.), Addison-Wesley.
ㆍ E. Horowitz, S. Sahni, S. Anderson-Freed, Fundamentals of Data Structures in C, Silicon Press, 2nd Edition.
GitHub - qlsdud0604/algorithm-study: 자료구조 및 알고리즘 공부 기록 공간
:books: 자료구조 및 알고리즘 공부 기록 공간. Contribute to qlsdud0604/algorithm-study development by creating an account on GitHub.
github.com
728x90'Computer Science > Algorithm' 카테고리의 다른 글
다익스트라 알고리즘(Dijkstra Algorithm) (0) 2021.09.25 위상 정렬(Topological Sorting) (0) 2021.09.25 크루스칼 알고리즘(Kruskal Algorithm) (0) 2021.09.25 BFS(너비 우선 탐색) (0) 2021.09.25 DFS(깊이 우선 탐색) (0) 2021.09.25