반응형
나열된 두 종류의 수가 있다고 생각해보자.
ex)
9 2 1 4 5
2 3 5 6 1
9 2 1 4 5는 나열된 수이고
2 3 5 6 1을 통해 위의 수가 있다면 1 없다면 0을 출력해야 한다.
즉, 2는 위에 있으니 1, 3은 없으니 0, 5는 있으니 1, 6은 없으니 0 1은 있으니 1
1 0 1 0 1이 출력된다.
이 알고리즘을 짤때 바로 생각드는건 2중 for문을 이용하여 9를 지정하고 2~1까지 조사하는법을 생각 해 볼 것이다.
하지만, 수의 개수가 많아지면 어떻게 될까?
시간복잡도 O(n)은 상상 할 수 없을정도로 커질 것이다.
어떤 방법이 있을까 생각해보면
위의 9 2 1 4 5를 Quick Sort(퀵 정렬)로 정렬하고
아래의 값들을 Binary Search(이진 탐색)을 이용하여 찾는다면
시간 복잡도가 확실히 줄어들 것이다.
(물론 퀵의 최악과, 이진의 최악상태로 있다면 O(n)이 늘어나겠지만, 2중 for문보다는 어떻게 해도 O(n)은 낮다.)
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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | #include <stdio.h> void Swap(int arr[], int a, int b); // a,b 스왑 함수 int Partition(int arr[], int left, int right); void QuickSort(int arr[], int left, int right); int arr[1000005] ={0,}; int main() { int tCase; // 테스트 케이스 int i,j,n,k,tmp; // i,j = for문 변수, n,k = 몇가지 숫자 입력받을지 int check = 0; // 바이너리 서치 통과되면 check = 1 아니면 check = 0 int first = 0; // 이진 탐색 변수 int last = 0; int middle = (first + last) / 2; scanf("%d",&tCase); for(tCase ; tCase > 0 ; tCase --) { scanf("%d",&n); for(i = 0 ; i < n ; i ++) { scanf("%d",&k); arr[i] = k; } QuickSort(arr,0,n-1); // 퀵정렬로 위의 상태 정렬 tmp = n; // ex)위의 수가 5가지고 아래 수가 4가지면 바이너리 서치 에러나니 tmp에 저장 scanf("%d",&n); for(i = 0 ; i < n ; i ++) { scanf("%d",&k); // 여기서 부터 바이너리 서치로 조사한다. first = 0; last = tmp-1; middle = (first + last)/2; while(first <= last) { middle = (first+last)/2; // 탐색 대상의 중앙을 검색 if(k == arr[middle]) // 중앙에 저장된 것이 타겟이라면 { printf("1\n"); check = 1; break; // 탐색 완료 } else // 타겟이 아니라면 탐색 대상을 반으로 줄인다. { if(k < arr[middle]) { last = middle-1; } else { first = middle+1; } } } // while end if(check == 0) // 탐색 실패 { printf("0\n"); } check = 0; // 다시 초기화 } // for end } // tCase end } // main end // 퀵정렬 이용 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); // 오른쪽 영역을 정렬한다. } } | Crocus |
자료구조를 배워야 하는 이유와, 어떻게 응용해야 되는지가 이 코드에 담겨 있는 것 같다.
반응형
'Applied > 알고리즘 문제풀이' 카테고리의 다른 글
[1912번] 연속 합 (Dynamic Programming) (0) | 2016.07.04 |
---|---|
두 사각형 겹치는 넓이 구하기 (2) | 2016.04.08 |
재귀 함수를 이용한 순열(Permutation) 알고리즘 (0) | 2016.03.19 |
진법 변환 (0) | 2016.03.19 |
각 자릿수 내림차순 정렬 (0) | 2016.03.01 |