본문 바로가기
언어 배우기!/C++ 공부하기

[C++] Map 기본 사용법! (BOJ 17219: 비밀번호 찾기)

by soeayun 2023. 9. 6.

https://www.acmicpc.net/problem/17219

 

17219번: 비밀번호 찾기

첫째 줄에 저장된 사이트 주소의 수 N(1 ≤ N ≤ 100,000)과 비밀번호를 찾으려는 사이트 주소의 수 M(1 ≤ M ≤ 100,000)이 주어진다. 두번째 줄부터 N개의 줄에 걸쳐 각 줄에 사이트 주소와 비밀번

www.acmicpc.net

 

 이 문제는 C++의 map을 사용하면 쉽게 풀 수 있다!

 

그 전에 map에 대해 간단히 짚고 넘어가겠다!

 

Map이란?

 map은 각 노드가 key와 value가 쌍을 이루고 있는 트리로 pair 객체로 저장되기 때문에 first-key로 second-value를 저장한다. 중복을 허락하지 않으며 기본 형태는 map<key,value> m; 으로 key를 통해 value를 찾기 용이하게 되어있다. 그래서 map은 pair로 이루어진 set 자료구조라고도 불린다

 

 또 가장 큰 특징으로는 자료를 저장할 때 내부에서 자동으로 오름차순으로 정렬된다는 것이다. 만약 내림차순으로 정렬하고 싶은 경우에는 map<key,value,greater> m와 같이 사용하면 된다.

 

데이터 삽입?

 map에서 데이터 삽입은 insert를 통해 가능하다. 이때 특징은 insert를 수행할 때 map의 중복되는 값을 허락하지 않는 특성에  따라 key가 중복되면 insert가 수행되지 않는다는 것이다. 즉, key는 고유한 값이어야 map 자료형을 사용 가능하다.

 

 m.insert({"iPhone",400})

 

과 같은 형식으로 insert가 가능하면 만약 저장한 변수를 insert하고 싶을 때는 결국 pair을 통해 저장되므로 make_pair을 사용하여

 

m.insert(make_pair(phone,price))

 

와 같은 형식으로 삽입이 가능하다.

 

map에 데이터가 있는지 확인하기

 map에 찾고자 하는 데이터가 있는지 확인하는 방법은 크게 2가지가 있다!!

 

1. find() 이용하기

 find()를 이용하면 만약 찾고자 하는 값이 map에 있다면 위치를 찾아 iterator을 반환하는 하고 만약 없다면 end iterator을 반환한다.

 이때 iterator란 포인터와 상당히 비슷하며, 컨데이너(map)에 저장되어있는 원소들을 참조할 때 사용된다.  즉, iterator는 pair를 가리키는 포인터 역할을 하는 객체로 first와 second를 이용해 key값과 data값을 출력할 수 있다고 생각하면 이해하기 편할 것이다. 아래 블로그는 이 반복자(iterator)에 대해 설명을 잘해두고 있다!

https://eehoeskrap.tistory.com/263

 

[C++] 반복자 (Iterator)

C++ 반복자(Iterator) C++ 라이브러리는 반복자를 제공하는데 이것을 사용하면 라이브러리의 방식대로 자료구조를 액세스 할 수 있다. 따라서 라이브러리가 효과적으로 동작한다는 것을 보장 할 수

eehoeskrap.tistory.com

 

 다시 돌아와서  find를 통해 찾은 iterator을 저장하는 방법은 크게 2가지가 있다.

1-1) map<자료형,자료형>::iterator it=m.find();

 이 방법은 본래 저장되어있는 map과 같은 형식의 자료형으로 iterator을 선언하여 find()에서 찾은 iterator을 복사하여 it->first 혹은 it->second로 접근이 가능하다.

 

1-2) auto result=m.find();

 여기서는 auto를 사용하여 iterator을 받았다.

 

 auto란 ?

 선언된 변수의 초기화 식을 사용하여 해당 형식을 추론하도록 컴파일러에 지시한 것으로 초깃값의 형식에 맞추어 선언하는 변수의 형식이 자동으로 결정되는 것이다. 즉, 타입 추론을 하는 것인데 변수를 초기화할때만 작동할 수 있으므로 초기화 값을 사용하지 않으면 이 기능을 사용할 수는 없다. 또한 컴파일러가 혼자 잘못 추론할 수 있으므로 너무 남용을 하면 안된다.

 하지만 여기서는 iterator로 초기화되어 있고 그렇기 때문에 auto라고 적게 된다면 자동으로 iterator이라는 것을 컴파일러가 생각할 수 있다.

 

 2) [ ]로 직접 접근

 만약 이 문제와 같이 무조건 이미 저장된 key값에 접근한다면 m[key값]을 통해 바로 map m에 저장되어 있는 value 값에 접근 가능하다.

 

 

소스코드 - auto 이용

#include <iostream>
#include <iostream>
#include <algorithm>
#include<bits/stdc++.h>
#include<map>
using namespace std; //모든 식별자가 고유하도록 보장하는 코드 영역

int main() {    
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  map<string,string> map1;
  
  int n,k;
  cin>>n>>k;
  for(int i=0;i<n;i++)
    {
      string tmp1,tmp2;
      cin>>tmp1>>tmp2;
      map1.insert(make_pair(tmp1,tmp2));
    }
  for(int i=0;i<k;i++)
    {
      string tmp;
      cin>>tmp;
      auto result=map1.find(tmp);
      cout<<result->second<<"\n";
    }
}

 

 

소스코드 - [ ] 이용

#include <iostream>
#include <iostream>
#include <algorithm>
#include<bits/stdc++.h>
#include<map>
using namespace std; //모든 식별자가 고유하도록 보장하는 코드 영역

int main() {    
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  map<string,string> map1;
  
  int n,k;
  cin>>n>>k;
  for(int i=0;i<n;i++)
    {
      string tmp1,tmp2;
      cin>>tmp1>>tmp2;
      map1.insert(make_pair(tmp1,tmp2));
    }
  for(int i=0;i<k;i++)
    {
      string tmp;
      cin>>tmp;
      string k=map1[tmp];
      //map<string,string>::iterator k=map1.find(tmp);//iterator는 pair를 가리키는 포인터 역할을 하는 객체로 first와 second를 이용해 key값과 data값을 출력할 수 있다.


      cout<<k<<"\n";
    }
}