(C++)이진탐색(Binary Search)

전성영·2022년 4월 27일
0

이진탐색(이분탐색)(Binary Search)란?

정렬되어 있는 리스트에서 탐색 범위를 절반씩 좁혀가며 데이터를 탐색하는 방법이다.

  • 일반적인 탐색 기법으로는 앞에서부터 요소를 순차적으로 탐색하기 때문에 시간 복잡도는 데이터의 개수만큼 이 된다. 즉 O(n) 이 된다.
  • 만일 데이터의 개수가 무수히 많아진다면 굉장히 비효율적인 알고리즘이 된다.
  • 하지만 이분 탐색을 사용하면 O(log n) 의 시간 복잡도로 탐색을 수행할 수 있다.

이분탐색 구현코드

void a()
{
   int arr[501];
   for (int i = 1; i < 501; i++)
      arr[i] = i;

   int target; // 타겟 값
   cin >> target;

   int left = 1, right = 500; // left, right 초기화
   while (left <= right)
   {
   //중앙값 초기화
      int mid = (left + right) / 2;
     
         if (mid == target)
         {
            cout << "Search" << '\n';
            break;
         }
         else if (mid > target)
         {
            right = mid - 1;
         }
         else
         {
            left = mid + 1;
         }
   }
}

이제 이분탐색을 할 때 사용하는 함수를 알아보자!!

1. binary_search()함수

binary_search(arr_begin,arr_end,find_value) :
검색해주는 함수로서 찾는 값이 존재하면 True, 아니면 False를 리턴한다.

이를 코드에 적용시켜보면

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;

int n, m;
vector<string>vec;
vector<string>vec2;
string name;
int main()
{
   cin >> n >> m;

   for (int i = 0; i < n; i++)
   {
      cin >> name;
      vec.push_back(name);
   }

   sort(vec.begin(), vec.end());

   string str;
   for (int j = 0; j < m; j++)
   {
      cin >> str;

      if (binary_search(vec.begin(), vec.end(), str))// search를 하면
      { 
         vec2.push_back(str);
      }
   }

   sort(vec2.begin(), vec2.end());

   cout << vec2.size() << '\n';
   for (int i = 0; i < vec2.size(); i++)
   {
      cout << vec2[i] << '\n';
   }

   return 0;
}

간단하게만 설명하자면

if (binary_search(vec.begin(), vec.end(), str))
{ 
    vec2.push_back(str);
}

str이 있다면 vec2라는 백터에 str을 저장한다는 코드이다.

다음으론 upper_bound()lower_bound()를 알아보자.

upper_bound, lower_bound 는 오름차순 정렬이 되있다는 전제가 깔려있어야 한다!

2. lower_bound 란?

  • 이진탐색(Binary Search)기반의 탐색 방법이다.
  • lower_bound는 찾으려 하는 key 값이 "없으면" key 값보다 큰(바로 다음 index) 정수를 찾는다.
  • 같은 원소가 여러개 있으면 가장 앞에 있는 index 값을 구한다.

3. upper_bound 란?

  • lower_bound와 마찬가지로 이진 탐색(Binary Search) 기반의 탐색법이다.
  • upper_bound는 key 값을 초과하는 가장 첫 번째 원소의 위치를 구하는 것 이다!
  • 같은 원소가 여러 개 있으면 가장 앞에 있는 index값을 구한다.

lower_bound : 찾고자 하는 값 이상이 처음 나타나는 위치
upper_bound : 찾고자 하는 값의 다음 값이 최초로 나타나는 위치

즉, 1 2 4 4 6 7에서

lower_bound(~,~,4)의 결과 : 2 (4 이상의 값이 처음 나타나는 위치)
upper_bound(~,~,4)의 결과 : 4 (4를 초과하는 값이 처음 나타나는 위치)

(추가)만약 주어진 수 보다 큰 수를 입력하게 되면 저 위에 예를 들면 8이 입력됐다? 그럼 index + 1 이 출력 즉 6이 출력된다!

이것을이용해서 upper - lower 을 빼주면 2가 나오고
이 값은 저장된 4의 개수가 된다.

for (int i = 0; i < m; i++)
{
   cin >> num;
   auto a = lower_bound(vec.begin(), vec.end(), num) - vec.begin();
   auto b = upper_bound(vec.begin(), vec.end(), num)- vec.begin();

   cout << b - a << " ";
}

ex) 중복값을 구하는 문제라면

1 1 2 3 4 4 5 6 6 7이 vector에 입력이 되어있고 num에 6이 들어간다고 한다면
a에는 6이 처음 발견되는 index인 7
b에는 6보다 큰 값이 처음 발견되는 index 값인 9가 들어가게 되고
b - a를 해준다면 num값이 vector안에 몇 개가 들어가 있는지 쉽게 알 수 있다.

정렬을 공부하면서 아직도 우물 안 개구리고 부족한 부분이 많다고 느낀다..
포기하지 않고 계속 나아간다면 나도 어느샌가 알고리즘 고수가 되어있을 것이라고 생각한다.
BFS, DFS 등등 열심히 차근차근 공부해 보자!
끗!

profile
Slow and Steady

0개의 댓글