정렬(Sorting)은 데이터를 특정 기준에 따라 순서대로 배열하는 과정을 말합니다. 정렬은 많은 알고리즘 문제의 기본이 되는 기술로, 다양한 방식으로 구현됩니다. 이번 글에서는 대표적인 정렬 알고리즘과 각각의 특징을 정리해보겠습니다.
public class BubbleSort {
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// Swap arr[j] and arr[j+1]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
bubbleSort(arr);
for (int num : arr) {
System.out.print(num + " ");
}
}
}
public class SelectionSort {
public static void selectionSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
// 남아있는 배열 중에서 최소값을 찾는다.
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// Swap arr[i] and arr[minIndex]
// 찾은 최소값을 정렬되지 않은 부분의 첫 번째 요소와 교환한다.
int temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
}
public static void main(String[] args) {
int[] arr = {64, 25, 12, 22, 11};
selectionSort(arr);
for (int num : arr) {
System.out.print(num + " ");
}
}
}
public class InsertionSort {
public static void insertionSort(int[] arr) {
int n = arr.length;
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
// arr[0..i-1]에서 key보다 큰 요소들을 한 칸씩 뒤로 밀기
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key; // key를 적절한 위치에 삽입
}
}
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6};
insertionSort(arr); // 배열 정렬 수행
for (int num : arr) {
System.out.print(num + " "); // 정렬된 배열 출력
}
}
}
// 병합정렬
public class MergeSort {
// 메인 메서드
public static void main(String[] args) {
int[] array = {21, 10, 12, 20, 25, 13, 15, 22};
mergeSort(array, 0, array.length - 1);
printArray(array);
}
// 병합 정렬 메서드
public static void mergeSort(int[] array, int left, int right) {
if (left < right) {
int middle = (left + right) / 2;
// 왼쪽 부분을 병합 정렬
mergeSort(array, left, middle);
// 오른쪽 부분을 병합 정렬
mergeSort(array, middle + 1, right);
// 병합
merge(array, left, middle, right);
}
}
// 병합 메서드
public static void merge(int[] array, int left, int middle, int right) {
int n1 = middle - left + 1;
int n2 = right - middle;
// 임시 배열 생성
int[] leftArray = new int[n1];
int[] rightArray = new int[n2];
// 데이터 복사
for (int i = 0; i < n1; i++) {
leftArray[i] = array[left + i];
}
for (int j = 0; j < n2; j++) {
rightArray[j] = array[middle + 1 + j];
}
// 병합
int i = 0, j = 0;
int k = left;
while (i < n1 && j < n2) {
if (leftArray[i] <= rightArray[j]) {
array[k] = leftArray[i];
i++;
} else {
array[k] = rightArray[j];
j++;
}
k++;
}
// 남은 요소들 복사
while (i < n1) {
array[k] = leftArray[i];
i++;
k++;
}
while (j < n2) {
array[k] = rightArray[j];
j++;
k++;
}
}
// 배열을 출력하는 메서드
public static void printArray(int[] array) {
for (int i : array) {
System.out.print(i + " ");
}
System.out.println();
}
}

public class QuickSort {
// 퀵 정렬 메서드
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
// 분할 위치 계산
int pi = partition(arr, low, high);
// 분할된 부분 배열을 재귀적으로 정렬
quickSort(arr, low, pi - 1); // 피벗보다 작은 부분 정렬
quickSort(arr, pi + 1, high); // 피벗보다 큰 부분 정렬
}
}
// 분할 메서드 (피벗을 기준으로 배열을 나눔)
public static int partition(int[] arr, int low, int high) {
// 피벗은 배열의 마지막 요소
int pivot = arr[high];
int i = (low - 1); // 작은 값의 인덱스를 추적
// 배열을 순회하면서 피벗보다 작은 값을 앞쪽으로 이동
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++; // 작은 값의 인덱스를 증가시킴
// arr[i]와 arr[j]를 교환
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 피벗을 적절한 위치에 배치
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
// 피벗의 인덱스를 반환
return i + 1;
}
// 메인 메서드
public static void main(String[] args) {
int[] arr = {10, 7, 8, 9, 1, 5}; // 정렬할 배열
quickSort(arr, 0, arr.length - 1); // 퀵 정렬 호출
// 정렬된 배열 출력
for (int num : arr) {
System.out.print(num + " ");
}
}
}
public class HeapSort {
// 힙 정렬 메서드
public static void heapSort(int[] arr) {
int n = arr.length;
// 힙 생성 (최대 힙)
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i); // 힙 속성 만족을 위한 재구성
}
// 힙에서 요소 추출
for (int i = n - 1; i > 0; i--) {
// 현재 루트를 배열 끝으로 이동 (최대값을 맨 뒤로 보냄)
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
// 크기가 줄어든 힙에 대해 다시 힙화
heapify(arr, i, 0);
}
}
// 힙화 메서드 (최대 힙으로 만들기)
public static void heapify(int[] arr, int n, int i) {
int largest = i; // 부모 인덱스
int left = 2 * i + 1; // 왼쪽 자식 인덱스
int right = 2 * i + 2; // 오른쪽 자식 인덱스
// 왼쪽 자식이 부모보다 크면 largest를 왼쪽 자식으로 변경
if (left < n && arr[left] > arr[largest]) largest = left;
// 오른쪽 자식이 부모 또는 왼쪽 자식보다 크면 largest를 오른쪽 자식으로 변경
if (right < n && arr[right] > arr[largest]) largest = right;
// 만약 부모가 가장 크지 않다면, 자식과 교환 후 다시 힙화
if (largest != i) {
int swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
// 교환 후, 바뀐 자식에 대해 다시 힙화
heapify(arr, n, largest);
}
}
// 메인 메서드
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6, 7}; // 정렬할 배열
heapSort(arr); // 힙 정렬 호출
// 정렬된 배열 출력
for (int num : arr) {
System.out.print(num + " ");
}
}
}
이번 공부를 통해 정렬에 대해 기본적인 개념과 구현 방법에 대해 알아보았습니다.
퀵 정렬과 힙 정렬 두 알고리즘에 대한 깊은 이해가 부족하여 이 주제에 대해서는 추가적인 공부가 필요할 것 같습니다. 정렬 알고리즘에 대한 이해를 더 깊에 쌓기 위해, 다양한 자료와 연습을 통해 이 부분을 보완할 예정입니다. 😊