Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 10773
- Process Communication
- IT
- c
- process control
- 2941
- The Balance of the World
- Zero That Out
- 백준
- system programming
- QA
- 1874
- 4949
- file IO
- 바샤
- 입력 버퍼
- 시스템 프로그래밍
- 전자책
- For Beginners
- 5622
- 해바
- Parenthesis
- LJESNJAK
- 브런치
- c++
- 시프
- 균형잡힌 세상
- Baekjoon
- BAKA
- File 조작
Archives
- Today
- Total
해바
2751) 11. 정렬 : 수 정렬하기 2 본문
문제
https://www.acmicpc.net/problem/2751
2751번: 수 정렬하기 2
첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 숫자가 주어진다. 이 수는 절댓값이 1,000,000보다 작거나 같은 정수이다. 수는 중복되지 않는다.
www.acmicpc.net
풀이
Quick Sort로 풀고 보나 마나 맞겠지 했다가 시간 초과가 떠서 당황했다. 시간 초과의 원인은,
최악의 경우(ex. 정렬 혹은 역정렬) $O(n^2)$의 시간 복잡도를 가지기 때문이었다.
Quick Sort
아래 define으로 정의된 SWAP 함수를 매크로 함수라고 한다. 처음에 그냥 void swap(int* x, int* y) 꼴로 함수를 짜면 원본 값이 전해지지 않아 제대로 정렬이 이루어지지 않는다. 값이 복사되기 때문인데, 자세한 설명은 여기 참고.
#include "cstdio"
#define SWAP(x, y, temp) ( (temp) = (x), (x) = (y), (y) = (temp) )
int partition(int* data, int left, int right) {
int low(left), high(right + 1), pivot(data[left]), temp(0);
while(low < high) {
do ++low; while(low <= high && data[low] < pivot); // 왼쪽에서부터 pivot보다 값이 작을 동안 비교하며 올라감
do --high; while(high >= left && data[high] > pivot); // 오른쪽에서부터 pivot보다 값이 클 동안 비교하며 내려옴
if(low < high) SWAP(data[low], data[high], temp); // low와 high가 교차하지 않았으면 값 교환
}
SWAP(data[left], data[high], temp); // 반복문을 빠져나온 건 low와 high가 교차했단 의미이므로 값 교환
return high; // pivot 위치를 반환
}
void qSort(int* data, int left, int right) {
if(left < right) {
int mid(partition(data, left, right));
qSort(data, left, mid - 1);
qSort(data, mid + 1, right);
}
}
int main() {
int repeat(0);
scanf("%d", &repeat);
int* data(new int[repeat]);
for(int i(0); i < repeat; i++) scanf("%d", &data[i]);
qSort(data, 0, repeat - 1);
for(int i(0); i < repeat; i++) printf("%d\n", data[i]);
delete[] data;
return 0;
}
그렇기 때문에 항상 $O(nlogn)$의 시간복잡도를 갖는 알고리즘 중 Merge Sort를 만들어보기로 했다(개념 및 코드는 여기 참고).
Merge Sort
#include "cstdio"
void merge(int* data, int left, int mid, int right) {
int* result = new int[right + 1], i(left), j(mid + 1), cur(left);
while(i <= mid && j <= right) {
// 배열을 합병하면서 오름차순으로 정렬
if(data[i] <= data[j]) result[cur++] = data[i++];
else result[cur++] = data[j++];
}
/* original array에서(왼쪽 파티션을 다 helper에 카피했다면) 오른쪽 파티션의 끝나지 않은 부분은 이미 정렬되어 있는 상태이고,
오른쪽 이기 때문에 helper array에 카피 후 다시 original array에 다시 카피 해 오는 작업은 불필요함 (cracking coding interview)*/
while(i <= mid) result[cur++] = data[i++];
// 남은 값들을 전부 정렬하는 배열로 옮김
for(int idx(left); idx < cur; idx++) data[idx] = result[idx];
// 정렬된 배열을 원본 배열로 옮김
delete [] result;
}
void mSort(int* data, int left, int right) {
if(left < right) {
int mid((left + right) / 2);
mSort(data, left, mid);
mSort(data, mid + 1, right);
merge(data, left, mid, right);
}
}
int main() {
int repeat(0);
scanf("%d", &repeat);
int* data = new int[repeat];
for(int i(0); i < repeat; i++) scanf("%d", &data[i]);
mSort(data, 0, repeat - 1);
for(int i(0); i < repeat; i++) printf("%d\n", data[i]);
delete[] data;
return 0;
}
Merge/Quick Sort는 헷갈려서 몇 번 더 짜면서 복습해야겠다.
직접 짜본답시고 삽질이 많았지만, 이 문제를 간단하게 푸는 방법은 역시 C++ STL을 이용하는 것이다.. 다 필요 없고 sort(data, data + repeat) 만 넣어주면 훨씬 빠르고 가볍게 작동한다.
'C, C++' 카테고리의 다른 글
2750) 11. 정렬 : 수 정렬하기 (0) | 2019.08.26 |
---|---|
1874) 15. 스택 : 스택 수열 (0) | 2019.08.25 |
4949) 15. 스택 : 균형잡힌 세상(The Balance of the World) (0) | 2019.08.23 |
9012) 15. 스택 : 괄호(Parenthesis) (0) | 2019.08.20 |
10773) 15. 스택 : 제로(Zero That Out) (0) | 2019.08.18 |
Comments