문제의 조건은 3가지로 단순합니다. 

1. 금메달 수가 더 많은 나라  
2. 금메달 수가 같으면, 은메달 수가 더 많은 나라 
3. 금, 은메달 수가 모두 같으면, 동메달 수가 더 많은 나라  

얼핏보면 if문을 사용하여 조건을 걸어 풀 수 있지만  

'전체 메달 수의 총합은 1,000,000 이하이다.' 라는 입력 전제조건을  활용하여 
금,은,동 메달에 각각 점수를 부여하여 각각의 메달의 최대치(1,000,000)를 획득해도 
그보다 높은 메달 1개 보다 낮은 점수를 부여하여 풀 수있는 알고리즘입니다. 

다음은 score배열에 각각의 메달에 가중치를 부여하여 계산하여 저장하는 구문입니다. 

for (int i = 0; i < country_num; i++)  { 
     score[i][0] = arr[i][0]; // 1) 
     score[i][1] = (arr[i][1] * 1000000000000) + (arr[i][2] * 1000000)+ (arr[i][3] * 1); // 2) 


country_num은 입력받은 국가 개수입니다. 
score 배열은 국가 넘버, 국가 별 점수를 저장한 배열입니다. 
arr는 입력받은 배열입니다. 
1. 첫번째 열이 모두 국가 넘버이기 때문에 score배열 첫번째 행에 모두 저장합니다. 
2. arr배열의 두번째, 세번째, 네번째 열이 금,은,동메달 순이므로 각각에 가중치를 곱한 후 score배열에 저장합니다. 


두번째로 동일 점수에 대한 등수 계산법입니다. 
간단하게 구현 가능합니다. 

int count = 1; 
for (int i = 0; i < country_num; i++){ 
     if (score[i][0] == country){ 
          for (int j = 0; j < country_num; j++){ 
               if (score[i][1] < score[j][1]) count++; 
          
          break; 
     

cout << count; 

두번째로 들어온 입력 (등수를 알고싶은 국가K)을 country변수에 저장한 후 
반복문을 사용하여 배열의 인덱스를 알아냅니다(각 국가가 순서대로 입력되지 않기 때문에) 
인덱스를 알아낸 상태에서 다시 반복문을 사용하여 자신의 점수보다 큰 점수를 count하면 됩니다. 
break 사용 이유는 인덱스를 이미 찾은 상태이므로 더이상 반복문을 실행하지 않아도 되기 때문입니다. 

다음 실행 코드 전체입니다. 

 * score 배열의 자료형을 unsigned long long으로 한 이유는 가중치의 총 합이 10^19이 넘어가는 숫자이기 때문에 long long을 사용해도 범위(-9x10^19~9x10^19)안에 속하지만 가중치에 음수가 없기 때문에 편의상 unsigned long long으로 표현했습니다.

*전체 소스코드 

#include <iostream> 

using namespace std; 

int main() 

     int country_num = 0; 
     int country = 0; 
     int **arr = NULL; 
     unsigned long long **score = NULL; 

     cin >> country_num >> country; 

     arr = new int*[country_num]; 
     score = new unsigned long long*[country_num]; 

     for (int i = 0; i < country_num; i++) { 
          arr[i] = new int[4]; 
          score[i] = new unsigned long long[2]; 
     

     for (int i = 0; i < country_num; i++) 
          for (int j = 0; j < 4; j++) 
               cin >> arr[i][j]; 

     for (int i = 0; i < country_num; i++) { 
          score[i][0] = arr[i][0]; 
          score[i][1] = (arr[i][1] * 1000000000000) + (arr[i][2] * 1000000) + (arr[i][3] * 1); 
     

     int count = 1; 
     for (int i = 0; i < country_num; i++) { 
          if (score[i][0] == country) { 
               for (int j = 0; j < country_num; j++) { 
                    if (score[i][1] < score[j][1]) 
                         count++; 
                    
               break; 
          
     
     cout << count; 

     for (int i = 0; i < country_num; i++) 
          delete[] arr[i]; 
     delete[] arr; 

     return 0; 



질문사항은 댓글로 달아주세요!


'자료구조, 알고리즘' 카테고리의 다른 글

정렬 알고리즘 종류  (0) 2018.09.12
검색 알고리즘 종류  (2) 2018.09.11
자료구조 그래프(Graph)  (1) 2018.09.06
자료구조 힙(Heap)  (0) 2018.09.05
자료구조 이진 탐색 트리(Binary Search Tree)  (0) 2018.09.01
자료구조 트리(Tree)  (0) 2018.08.30
[자료구조] 큐 QUEUE  (0) 2018.08.19
[자료구조] 스택 STACK  (0) 2018.08.19


지속해서 업데이트 됩니다. (11/13)
ctrl + d를 눌러 북마크를 추가할 수 있습니다. 
모든 질문은 커뮤니티 Q&A 게시판에서 받습니다.


C/C++

  

C#



Python



Java



Android



HTML/CSS



JavaScript



PHP



DataStructure



Algorithm



Database



Network





현재 많은 수의 알고리즘이 존재하지만 그중 실제 구현에서는 몇가지 알고리즘만 사용됩니다.


자바, C++ 등의 언어에서는 라이브러리로 O(n log n) 하한의 정렬 알고리즘을 제공하여 그냥 사용하면 되지만, 정렬 알고리즘을 더 깊게 공부하거나, 효율적인 정렬 알고리즘을 사용하려는 개발자를 위해 정렬 알고리즘에 대한 이해는 필수입니다.


실제 구현 시 사용되는 몇가지 알고리즘에 대해 비교 설명 해보겠습니다.

(각 알고리즘에 대한 상세 설명 및 구현방법은 생략합니다. 추후에 정리해서 올릴게요!)



비교 정렬 알고리즘 성능


이름

최적(Best)

평균(Average)

최악(Worst)

메모리

안정성(Stable)*

퀵(Quick) 정렬

n log n

n log n

n^2

log n ~ n

No

합병(Merge) 정렬

n log n

n log n

n log n

n

Yes

 삽입(Insertion) 정렬

n

n^2

n^2

1

Yes

힙(Heap) 정렬

n log n

n log n

n log n

1

No

Intro Sort

n log n

n log n

n log n

log n

No

 선택(Selection) 정렬

n^2

n^2

n^2

1

No

쉘(Shell) 정렬

n log n

gap에 따라 다름

1

No

거품(Bubble) 정렬

n

n^2

n^2

1

Yes


Stable(안정성) : 같은 값에 대해 정렬 시도 후 위치가 바뀌지 않으면 Stable 하다고 하며, 위치가 서로 바뀔 수 있다면 Not Stable 하다고 합니다.



1. 퀵 정렬(Quick Sort) 

- 분할 및 정복 알고리즘으로, 피벗이라는 요소를 사용하여 배열을 분할 합니다.

- 낮은 오버헤드로 다른 O(n log n) 정렬 알고리즘 보다 빠른 성능을 보입니다.

- 최악의 경우 성능이 O(n^2)입니다만, 드문 경우로써 피벗 요소를 잘 선택하여 O(n log n)의 성능을 얻을 수 있습니다.


2. 합병 정렬(Merge Sort)

- 비교 기반 분할 정복 정렬 알고리즘 입니다.

- Python과 Java의 표준 정렬 루틴에 사용되는 Timsort 알고리즘에 사용됩니다.


3. 힙 정렬(Heap Sort) 

- 특별한 유형의 데이터 구조 이진트리를 생성하여 사용합니다.

- 퀵 정렬보다 대부분 다소 느리지만 최악의 경우 O(n log n)이라는 이점이 있습니다. 


4. 삽입 정렬(Insertion Sort) 

- 작은 데이터 셋(data set)에 널리 사용됩니다. 

- 대부분 정렬 된 목록에 비교적 효율적이며, 더 복잡한 알고리즘의 일부로 사용되는 간단한 정렬 알고리즘입니다.


5. Intro Sort

- 하이브리드 정렬 알고리즘으로 퀵 정렬과 힙 정렬을 결합 하여 구현된 알고리즘입니다.

C++ STL(표준 라이브러리)에서 제공합니다.


6. 쉘 정렬(Shell Sort)

- 적은 수의 코드와 합리적으로 빠르며, 임베디드 및 구형 메인 프레임 메모리에 사용됩니다.


7. 거품 정렬(Bubble Sort)

- 구현하기 가장 간단한 알고리즘이지만 O(n^2)으로 정렬 되지 않은 대형 데이터 셋에서 거의 사용되지 않습니다.

- 거의 정렬된 데이터에서 효율적으로 사용됩니다. O(n)




비 비교 정렬 알고리즘 성능


이름

최적(Best)

평균(Average)

최악(Worst)

메모리

안정성(Stable)

버킷(Bucket) 정렬

-

n+k

(n^2) * k

2^k

Yes

 계수(Counting) 정렬

-

n+r

n+r

n+r

Yes

기수(Radix) 정렬

-

n * (k / d)

n * (k / d)

n+(2^d)

Yes



1. 버킷 정렬(Bucket Sort) 

- 배열을 유한 개수의 버킷으로 분할하여 계산하는 분할 정복 정렬 알고리즘입니다.

- 데이터 셋 요소가 모든 버킷에 고르게 분산될 때 가장 최적한 성능을 보입니다.

- 버킷을 할당하기 위한 메모리가 많이 필요합니다.


2. 계수 정렬(Counting Sort)

- 정수 정렬 알고리즘으로 정수 배열(리스트)에 한정적입니다.

- 숫자 크기(r)에 따라 매우 큰 영향을 받을 수 있으며 n에 비해 r이 매우 커지는 경우 비 효율적입니다.


3. 기수 정렬(Radix Sort)

- 자리수 d에 따라 공간 복잡도가 매우 커질 수 있습니다.





이상 정렬 알고리즘에 대해 비교 분석 해 보았습니다.

질문 또는 오타나 잘못된 정보가 있는 경우 댓글로 달아주세요!

공감♡ 버튼을 눌러주시면 더욱 유용하고 좋은 포스팅으로 찾아 뵙겠습니다.



'자료구조, 알고리즘' 카테고리의 다른 글

[BOJ] 8979 올림픽 - 문제 풀이  (1) 2019.03.29
검색 알고리즘 종류  (2) 2018.09.11
자료구조 그래프(Graph)  (1) 2018.09.06
자료구조 힙(Heap)  (0) 2018.09.05
자료구조 이진 탐색 트리(Binary Search Tree)  (0) 2018.09.01
자료구조 트리(Tree)  (0) 2018.08.30
[자료구조] 큐 QUEUE  (0) 2018.08.19
[자료구조] 스택 STACK  (0) 2018.08.19



안녕하세요 열코입니다.

이번시간에는 기본적인 검색(탐색) 알고리즘 종류들에 대해 알아보도록 하겠습니다.


1. 선형 검색 (Linear Search)

- 배열의 가장 좌측부터 시작하여 찾으려는 값과 하나씩 배열의 각 요소와 비교합니다.

- 찾으려는 값을 발견한다면 배열의 해당 인덱스를 반환(return)합니다.

- 찾으려는 값이 없다면 -1을 반환합니다.

- 시간복잡도 O(n)

- 이진 검색 및 해시 테이블과 같은 다른 검색 알고리즘이 훨씬 빠르기 때문에 실제로 거의 사용하지 않습니다.


- 소스코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int search(int arr[], int n, int x) { // 매개변수 : 배열이름, 배열의 길이, 찾으려는 값
 
    int i;
 
    for (i = 0; i < n; i++) { // 배열 전체 순차 탐색
 
        if (arr[i] == x) { // 찾는 값 발견
 
            return i; // 해당 위치(인덱스) 반환
 
        }
 
    }
 
    return -1// 찾으려는 값을 발견하지 못하면 -1 반환
 
}
cs



2. 이진 검색 (Binary Search)

- 검색 반경을 반으로 나눠어 반복하는 검색 방법입니다.

- 정렬 된 배열에서 사용 가능합니다.

- 찾으려는 값을 배열의 중간값과 비교하여 그 값이 더 작다면 우측 배열, 크다면 좌측 배열로 이동하여 반복

- 시간 복잡도 O(log 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
int binarySearch(int arr[], int l, int r, int x) { // 매개변수 : 배열이름, 배열 시작 인덱스, 배열 끝 인덱스, 찾으려는 값
 
   if (r >= l) 
 
   { 
 
        int mid = l + (r - l)/2// 중간 값 선택
 
        if (arr[mid] == x) // 비교하여 찾는 값이라면
 
            return mid; // 해당 인덱스 반환
 
 
        if (arr[mid] > x) // 찾으려는 값보다 크다면
 
            return binarySearch(arr, l, mid-1, x); // 좌측 배열 탐색
 
 
        return binarySearch(arr, mid+1, r, x); // 우측 배열 탐색
 
   }
 
   return -1;  // 찾으려는 값이 없다면 -1 반환
 
cs


- C++ STL에서는 이진 검색을 라이브러리로 제공합니다.

- binary_search(시작위치, 끝위치, 찾으려는값) 식으로 사용합니다.

- lower_bound는 찾으려는 값이 여러개 존재할 때 사용합니다. (upper_bound는 큰 인덱스를 반환)

- 배열(또는 리스트) 안에 찾으려는 값이 1개(단일) 존재한다면 해당 값의 인덱스를 반환합니다.

- 배열 안에 찾으려는 값이 2개 이상 존재한다면 해당 값 중 가장 앞쪽(낮은) 인덱스(num of first position)를 반환합니다.

- 배열 안에 찾으려는 값이 없을 경우 찾으려는 값 다음 위치의 인덱스를 반환합니다.

- 자바에서 Array.binarySearch() 또는 Collections.binarySearch()을 라이브러리로 사용할 수 있습니다.

- 만약 자바에서 이진 탐색을 사용하려면 전에 Array.sort() 메소드를 호출하여 배열을 정렬할 필요가 있습니다.




※ 배열 또는 리스트에서 최소값, 최대값 검색

- 정렬된 배열 또는 리스트에서는 양쪽 끝 값이 최소값 또는 최대값입니다.

- Divide and Conquer를 사용하여 O(log 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
int findPeakUtil(int arr[], int low, int high, int n) 
 
 
    int mid = low + (high - low)/2
 
 
    if ((mid == 0 || arr[mid-1<= arr[mid]) && 
 
            (mid == n-1 || arr[mid+1<= arr[mid])) 
 
        return mid; 
 
 
    else if (mid > 0 && arr[mid-1> arr[mid]) 
 
        return findPeakUtil(arr, low, (mid -1), n); 
 
 
 
    else return findPeakUtil(arr, (mid + 1), high, n); 
 
 
 
int findPeak(int arr[], int n) 
 
 
    return findPeakUtil(arr, 0, n-1, n); 
 
cs



이상 ''에 대해 알아보았습니다.

질문 또는 오타나 잘못된 정보가 있는 경우 댓글로 달아주세요!

메인 페이지로 이동하시면 더 많은 자료를 볼 수 있습니다.





'자료구조, 알고리즘' 카테고리의 다른 글

[BOJ] 8979 올림픽 - 문제 풀이  (1) 2019.03.29
정렬 알고리즘 종류  (0) 2018.09.12
자료구조 그래프(Graph)  (1) 2018.09.06
자료구조 힙(Heap)  (0) 2018.09.05
자료구조 이진 탐색 트리(Binary Search Tree)  (0) 2018.09.01
자료구조 트리(Tree)  (0) 2018.08.30
[자료구조] 큐 QUEUE  (0) 2018.08.19
[자료구조] 스택 STACK  (0) 2018.08.19


* 문제
n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 숫자를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 숫자는 한 개 이상 선택해야 한다.
예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.

* 풀이
수열의 원소중 연속된 숫자를 선택해 가장 큰 합을 구하기 위해서 동적계획법(Dynamic Programming)을 사용합니다. 첫번째 원소부터 별도의 배열(dp배열)에 수열값과 그전까지 합한 값 중 큰값을 저장합니다. 그중 최댓값을 구하면 정답입니다. 이해가 안가시면 아래 코드를 주석과 함께 한 줄 씩 해석해 보시기 바랍니다.

* 소스코드

#include <iostream> 
#define MAX(a,b) ((a) > (b) ? (a) : (b)) 
using namespace std; 

int main(){ 
     int input_value = 0; 
     cin >> input_value; 
     int *data = new int[input_value]; 
     int *dp = new int[input_value];  // 배열 동적 할당
     int max = -1001; // max는 입력 값 중 가장 작은값보다 작은값

     for (int i = 0; i < input_value; i++)  
          cin >> data[i]; // 데이터 입력

     dp[0] = data[0]; // 첫번째 원소는 그대로 대입(그 자체로 최대값)

     for (int i = 1; i < input_value; i++) 
          dp[i] = MAX(data[i], data[i] + dp[i - 1]); 
          // dp배열에 원소 값과 그전 dp값을 합한 값 중 큰 값 대입

     for (int i = 0; i < input_value; i++) 
          if (max < dp[i]) max = dp[i]; // 최댓값 검색

     cout << max; 

     delete[] dp; 
     delete[] data; // 배열 동적 할당 메모리 해제

     return 0; 
}

질문 및 오류사항은 댓글로 달아주세요.


'자료구조, 알고리즘' 카테고리의 다른 글

정렬 알고리즘 종류  (0) 2018.09.12
검색 알고리즘 종류  (2) 2018.09.11
자료구조 그래프(Graph)  (1) 2018.09.06
자료구조 힙(Heap)  (0) 2018.09.05
자료구조 이진 탐색 트리(Binary Search Tree)  (0) 2018.09.01
자료구조 트리(Tree)  (0) 2018.08.30
[자료구조] 큐 QUEUE  (0) 2018.08.19
[자료구조] 스택 STACK  (0) 2018.08.19

to Top