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