스택(Stack)은 데이터를 효율적으로 관리할 수 있도록 돕는 자료 구조. 데이터를 넣고 빼는 방식에 독특한 특징이 있다.
스택은 가장 먼저 들어온 데이터가 가장 마지막에 나가고, 가장 마지막에 들어온 데이터가 가장 먼저 나가는 선형 구조. FILO와 LIFO는 스택의 동작 방식을 설명하는 같은 의미의 용어.
스택은 주로 두 가지 방식으로 구현.
스택에서 데이터를 다루기 위한 핵심 연산들이 있다.
퀵 정렬(Quick Sort)은 분할 정복 알고리즘을 기반으로 하는 효율적인 정렬 알고리즘. 특정 기준 값인 '피벗(Pivot)'을 중심으로 배열을 나눈 후, 각 부분을 재귀적으로 정렬하는 방식으로 동작.
#include <stdio.h>
// 두 원소의 값을 교환하는 함수
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 배열을 분할하고 피벗의 최종 위치를 반환하는 함수
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // 배열의 마지막 원소를 피벗으로 선택
int i = (low - 1); // 작은 원소들의 경계를 추적하는 인덱스
// 배열을 순회하며 피벗보다 작거나 같은 원소들을 왼쪽으로 이동
for (int j = low; j <= high - 1; j++) {
if (arr[j] <= pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
// 피벗을 올바른 위치로 이동
swap(&arr[i + 1], &arr[high]);
return (i + 1); // 피벗의 최종 위치 반환
}
// 퀵 정렬을 수행하는 재귀 함수
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);
}
}
// 메인 함수
int main() {
int arr[] = {10, 7, 8, 9, 1, 5};
int n = sizeof(arr) / sizeof(arr[0]);
printf("정렬 전 배열: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
quickSort(arr, 0, n - 1); // 퀵 정렬 수행
printf("정렬 후 배열: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
배열을 중간 지점에서 두 개로 나눕니다.
각각의 하위 배열에 대해 병합 정렬을 재귀적으로 적용합니다.
두 정렬된 배열을 병합하여 하나의 정렬된 배열을 만듭니다.
#include <stdio.h>
// 병합 함수
void merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1; // 왼쪽 배열의 크기
int n2 = r - m; // 오른쪽 배열의 크기
int L[n1], R[n2];
// 왼쪽 배열과 오른쪽 배열에 데이터 복사
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
// 두 배열을 병합하여 arr[l..r]에 저장
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// L[] 배열에 남은 요소 복사
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
// R[] 배열에 남은 요소 복사
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
// 병합 정렬 함수
void mergeSort(int arr[], int l, int r) {
if (l < r) {
// 중간 인덱스를 계산
int m = l + (r - l) / 2;
// 왼쪽과 오른쪽 배열을 재귀적으로 정렬
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
// 두 배열을 병합
merge(arr, l, m, r);
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int arr_size = sizeof(arr) / sizeof(arr[0]);
// 주어진 배열 출력
printf("주어진 배열: ");
for (int i = 0; i < arr_size; i++)
printf("%d ", arr[i]);
printf("\n");
// 병합 정렬 함수 호출
mergeSort(arr, 0, arr_size - 1);
// 정렬된 배열 출력
printf("정렬된 배열: ");
for (int i = 0; i < arr_size; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
이 알고리즘은 특히 큰 데이터 집합을 정렬할 때 유용하며, O(n log n)의 시간 복잡도를 가지므로 효율적입니다.