65. 배열 정렬
1. 키워드
- 버블 정렬(Bubble Sort)
- 퀵 정렬(Quick Sort)
- 스왑(Swap)
qsort
(Quick Sort)
2. 배열 정렬하기
- 이번에는 정렬 알고리즘 중에서 가장 간단한 알고리즘인 버블 정렬을 구현해 보고, C에서 제공하는 퀵 정렬 함수 사용 방법을 알아보자.
3. 버블 정렬 구현하기
1
부터10
까지 숫자가 무작위로 들어있는 배열을 버블 정렬 알고리즘으로 정렬해 보자.
#include <stdio.h>
void bubble_sort(int arr[], int count) // 매개변수로 정렬할 배열과 요소의 개수를 받음
{
int temp;
for (int i = 0; i < count; i++) // 요소의 개수만큼 반복
{
for (int j = 0; j < count - 1; j++) // 요소의 개수 - 1만큼 반복
{
if (arr[j] > arr[j + 1]) // 현재 요소의 값과 다음 요소의 값을 비교하여
{ // 큰 값을
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp; // 다음 요소로 보냄
}
}
}
}
int main()
{
int numArr[10] = {8, 4, 2, 5, 3, 7, 10, 1, 6, 9}; // 정렬되지 않은 배열
bubble_sort(numArr, sizeof(numArr) / sizeof(int)); // 버블 정렬 함수 호출
for (int i = 0; i < 10; i++)
{
printf("%d ", numArr[i]);
}
printf("\n");
return 0;
}
// 1 2 3 4 5 6 7 8 9 10
- 버블 정렬 알고리즘의 규칙은 다음과 같다.
1] 처음부터 끝까지 요소를 순회하면서 모든 요소를 비교
2] 현재 값과 다음 값을 비교하여 큰 값을 다음으로 보냄(오름차순)
- 이제
bubble_sort
함수를 살펴보자. bubble_sort
함수는int arr[]
과 같이 정렬할 배열을 매개변수로 받는다.- 또한, 매개변수
arr[]
로는 요소의 개수를 모르니 요소의 개수도 함께 받는다.
for
반복문으로 배열을 처음부터 끝까지 순회한다.- 이때 요소 하나를 반복할 때마다 다시
처음
부터끝 - 1
까지, 즉,0
부터count - 1
까지 반복한다. - 여기서
-1
을 하는 이유는 현재 값과 다음 값을 비교할 때 맨 마지막 요소는 배열의 인덱스를 벗어난 값과 비교하게 된다. - 따라서 배열의 인덱스를 벗어나지 않도록 마지막 요소의 바로 앞에서 반복을 끝낸다.
for (int i = 0; i < count; i++) // 요소의 개수만큼 반복
{
for (int j = 0; j < count - 1; j++) // 요소의 개수 - 1만큼 반복
{
- 현재값
arr[j]
와 그다음에 있는 값arr[j + 1]
을 비교하여 큰 값을 다음 요소로 보낸다. - 즉, 작은 값이 먼저 오는 오름차순 정렬이다.
- 부등호를 반대로 해주면 내림차순이 된다.
- 여기서 큰 값을 다음 요소로 보낼 때는 기존 값을 임시 변수
temp
에 저장해놓고 다음 요소에 있는 값을 가져온 뒤temp
의 값을 다음 요소에 저장해서 값을 서로 바꾼다. - 이를 스왑이라 한다.
if (arr[j] > arr[j + 1]) // 현재 요소의 값과 다음 요소의 값을 비교하여
{ // 큰 값을
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp; // 다음 요소로 보냄
}
- 이제 정렬되지 않은 배열
numArr
을bubble_sort
함수에 넣은 뒤printf
로 각 요소를 출력해 보면 배열이1
부터10
까지 순서대로 정렬된 것을 볼 수 있다.
int main()
{
int numArr[10] = {8, 4, 2, 5, 3, 7, 10, 1, 6, 9}; // 정렬되지 않은 배열
bubble_sort(numArr, sizeof(numArr) / sizeof(int)); // 버블 정렬 함수 호출
for (int i = 0; i < 10; i++)
{
printf("%d ", numArr[i]);
}
printf("\n");
return 0;
}
4. 퀵 정렬 함수 사용하기
- 퀵 정렬 함수
qsort
에는 정렬할 배열 또는 메모리의 주소, 요소 개수, 요소 크기, 비교 함수를 넣어준다.
- 실제로 정렬을 한다면 정렬할 배열의 자료형도 제각각이고 비교 방식도 여러 가지이므로 비교 함수는 우리가 구현해서 함수의 메모리 주소(함수 포인터)를 넣어주게 된다.
#include <stdio.h>
#include <stdlib.h> // qsort 함수가 선언된 헤더 파일
int compare(const void *a, const void *b) // 오름차순 비교 함수 구현
{
int num1 = *(int *)a; // void 타입 포인터를 int 타입 포인터로 변환한 뒤 역참조하여 값을 가져옴
int num2 = *(int *)b; // void 타입 포인터를 int 타입 포인터로 변환한 뒤 역참조하여 값을 가져옴
if (num1 < num2) // a가 b보다 작을 때는
return -1; // -1 반환
if (num1 > num2) // a가 b보다 클 때는
return 1; // 1 반환
return 0; // a와 b가 같을 때는 0 반환
}
int main()
{
int numArr[10] = {8, 4, 2, 5, 3, 7, 10, 1, 6, 9}; // 정렬되지 않은 배열
// 정렬할 배열, 요소 개수, 요소 크기, 비교 함수를 넣어줌
qsort(numArr, sizeof(numArr) / sizeof(int), sizeof(int), compare);
for (int i = 0; i < 10; i++)
{
printf("%d ", numArr[i]);
}
printf("\n");
return 0;
}
// 1 2 3 4 5 6 7 8 9 10
- 먼저
qsort
함수를 사용하기 전에 비교 함수compare
를 만들어야 한다. - 다음은 오름차순 정렬 조건이다.
1] a < b
일 때는 -1
을 반환
2] a > b
일 때는 1
을 반환
3] a == b
일 때는 0
을 반환
- 이건
qsort
를 사용하기 위한 약속이다. - 만약
a < b
일 때1
을 반환하면 반대로 내림차순 정렬이 된다.
- 비교 함수를 정의할 때는 반드시
int
타입 반환값과const void
타입 포인터 매개변수가 두 개 있어야 한다. - 하지만
const void
타입 포인터로는 값을 비교할 수 없으므로 정렬할 배열의 자료형에 따라const void
타입 포인터를 변환한 뒤 역참조하여 값을 가져온다. - 여기서는 정렬할 배열이
int
타입이므로const void
타입 포인터를int
타입 포인터로 변환한 뒤 역참조하여 값을 가져왔다. - 값을 가져온 뒤에는 각 값을 비교하여
-1
,1
,0
을 반환한다.
int compare(const void *a, const void *b) // 오름차순 비교 함수 구현
{
int num1 = *(int *)a; // void 타입 포인터를 int 타입 포인터로 변환한 뒤 역참조하여 값을 가져옴
int num2 = *(int *)b; // void 타입 포인터를 int 타입 포인터로 변환한 뒤 역참조하여 값을 가져옴
if (num1 < num2) // a가 b보다 작을 때는
return -1; // -1 반환
if (num1 > num2) // a가 b보다 클 때는
return 1; // 1 반환
return 0; // a와 b가 같을 때는 0 반환
}
const void *
const void *
는void
타입 상수를 가리키는 포인터라는 뜻이다.- 즉,
qsort
함수를 통해compare
함수가 포인터를 전달 받았을 때 포인터가 가리키는 값이 상수이다. - 따라서
compare
함수 안에서는 값을 임의로 변경해서는 안 된다.
- 이제
qsort
함수를 호출한다. qsort
함수에 정렬할 배열, 요소 개수, 요소 크기, 비교 함수를 넣어준다.- 요소 크기는
sizeof
로 구하면 되고, 비교 함수는()
(괄호)를 붙이지 않은 함수 포인터를 넣는다.
int numArr[10] = {8, 4, 2, 5, 3, 7, 10, 1, 6, 9}; // 정렬되지 않은 배열
// 정렬할 배열, 요소 개수, 요소 크기, 비교 함수를 넣어줌
qsort(numArr, sizeof(numArr) / sizeof(int), sizeof(int), compare);
printf
로 각 요소를 출력해 보면1
부터10
까지 순서대로 정렬된 것을 볼 수 있다.
내림차순
- 내림차순 비교 함수는 오름차순에서 부등호만 반대로 바꾸면 된다.
1] a > b
일 때는 -1
을 반환
2] a < b
일 때는 1
을 반환
3] a == b
일 때는 0
을 반환
int compare(const void *a, const void *b) // 오름차순 비교 함수 구현
{
int num1 = *(int *)a; // void 타입 포인터를 int 타입 포인터로 변환한 뒤 역참조하여 값을 가져옴
int num2 = *(int *)b; // void 타입 포인터를 int 타입 포인터로 변환한 뒤 역참조하여 값을 가져옴
if (num1 > num2) // a가 b보다 클 때는
return -1; // -1 반환
if (num1 < num2) // a가 b보다 작을 때는
return 1; // 1 반환
return 0; // a와 b가 같을 때는 0 반환
}
- 오름차순과 내림차순을 좀 더 간단하게 구현하려면 다음과 같이 매개변수를 뺀 값을 반환하면 된다.
- 즉, 값을 반환할 때 반드시
-1
,1
,0
일 필요는 없다. - 값이 같을 때만
0
이면 되고, 값이 크거나 작을 때는 음수와 양수를 반환하면 된다.