반응형

수 n개가 주어졌을 때, ( 1 <= n <= 10,000,000 ) 오름차순으로 정렬 하는 프로그램을 작성하라.


n개 수의 값들은 10,000보다 작거나 같은 값들이다.


이 프로그램을 보면 배열의 크기를 10,000,000의 크기로 잡고, 퀵 정렬(Quick Sort)을 이용해서 정렬을 마무리 한 뒤,


출력을 차례대로 하면 되겠구나 생각하였다.


하지만 이런식의 코딩을 하게 되면 큰 오류를 범하게 되는데,


arr의 배열이 int당 4byte라 치면 40,000,000byte -> 39062kbyte -> 38mb라는 큰 메모리를 요구하게 된다.


이는 메모리를 과용하는 일이므로 좋지 못한 알고리즘을 가진 프로그램이 될 수 있다.


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <stdio.h>
 
 
int arr[10000002];
 
void Swap(int arr[], int a, int b) // a,b 스왑 함수 
{
    int temp = arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
}
 
int Partition(int arr[], int left, int right)
{
    int pivot = arr[left]; // 피벗의 위치는 가장 왼쪽에서 시작
    int low = left + 1;
    int high = right;
 
 
    while (low <= high) // 교차되기 전까지 반복한다 
    {
        while (pivot >= arr[low] && low <= right) // 피벗보다 큰 값을 찾는 과정 
        {
            low++// low를 오른쪽으로 이동 
        }
 
        while (pivot <= arr[high] && high >= (left+1) ) // 피벗보다 작은 값을 찾는 과정 
        {
            high--// high를 왼쪽으로 이동
        }
 
        if (low <= high)// 교차되지 않은 상태이면 스왑 과정 실행 
        {
            Swap(arr, low, high); //low와 high를 스왑 
        }
 
    }
    Swap(arr, left, high); // 피벗과 high가 가리키는 대상을 교환 
    return high;  // 옮겨진 피벗의 위치정보를 반환 
 
}
 
 
void QuickSort(int arr[], int left, int right)
{
    if (left <= right)
    {
        int pivot = Partition(arr, left, right); // 둘로 나누어서
        QuickSort(arr, left, pivot - 1); // 왼쪽 영역을 정렬한다.
        QuickSort(arr, pivot + 1, right); // 오른쪽 영역을 정렬한다.
    }
}
 
 
int main()
{

int n;
int i;
 
scanf("%d",&n);
 
 
for(i = 0 ; i < n ; i++ ){ scanf("%d",&arr[i]);}
 
QuickSort(arr,0,n-1);
 
for(i = 0 ; i < n ; i++ ){ printf("%d ",arr[i]); }
 
 
}
 
 
Crocus


따라서 다음과 같은 문제는 아래의 알고리즘과 같은 방법으로 해결 할 수 있다.



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
#include <stdio.h>
 
#define INDEX 10001
 
int main()
{
    int count, i, j, k;
    int arry[INDEX] = {0,};
    scanf("%d", &count);
    
    for(i = 0; i < count; i++)
    {
        scanf("%d", &k);
        arry[k] = arry[k] + 1;
    }
 
    for(i = 1; i < INDEX; i++ )
    {
        if(arry[i] != 0)
        {
            for(j = 0; j < arry[i]; j++)
            printf("%d\n", i);
        }
    }
 
}
 
Crocus


이 알고리즘은 알게 되면 쉽지만,


막상 처음 접하시는 분들은 생각하기가 까다로울 수도 있다.


알고리즘에 대해서 설명하자면


INDEX는 배열 arry[]가 가질 수 있는 값의 범위이자 배열의 크기라 볼 수 있다.


arry[] = arry[] + 1;의 의미는


scanf로 만약 1을 받으면 arry[1]에 1을 더하라는 것, 즉 1번 배열에 1을 더하라는 것이다.


즉, n번 배열에 n을 더하면 되는 것이니. 1이 몇개인지 2가 몇개인지 ... 10000까지의 개수를 배열의 번호에 있는 값으로 파악 할 수 있다.


마지막 if(arry[i] != 0)은 이제 scanf로 받은 적이 없는 값들을 걸러내는 작업이라고 보면 된다.



단순한 수 정렬 문제로써 퀵정렬로 해결하면 되는것 처럼 보일지 모르지만, 


조금 더 생각해보면 이런 알고리즘이 있듯이, 아직 생각지 못한 이보다 더 좋은 알고리즘도 있을지도 모른다..



반응형

'Applied > 알고리즘 문제풀이' 카테고리의 다른 글

1,2,3을 이용하여 값 구하기  (0) 2016.02.23
큰수 A+B  (0) 2016.01.25
파도반 수열  (1) 2015.12.12
Prefix Sum (수열의 구간 합 구하기)  (1) 2015.12.06
특수 알고리즘 해결문서  (0) 2015.12.06