map

-> map의 원소는 key와 value를 한 쌍으로 가진다.

-> 각 원소들은 삽입 시에 key값에 따라 자동 정렬이 발생한다.(순회 가능)

-> 노드 기반 컨테이너들 중 유일하게 key값을 통한 임의 접근이 가능하다.

-> 리소스 탐색용으로 많이 사용된다.

-> 단, 중복된 key값은 허용하지 않는다.

 

map

->map은 key와 value를 한 쌍으로 가진 컨테이너이다.

-> key로 사용할 자료형과 value로 사용할 자료형을 <>안에 명시해주면 된다.

-> 명시한 순서대로 key와 value의 타입이 결정된다.

map<int, int> Mymap;

map의 원소 삽입

map은 원소 삽입 시 key 값에 따라 자동 정렬이 발생한다.

-> 자동 정렬이 발생하기 때문에 앞, 뒤 원소 삽입의 의미가 없으므로 push 함수를 지원하지 않는다.

 

map의 원소

pair 객체(구조체)

map은 원소로 객체를 가진다.

pair<int, int> Mypair(1, 100);

구조체이기 때문에 읽기/쓰기가 가능하다. 

Mypair.first  = 10;
Mypair.second = 100;

               (key)                   (value)
cout << Mypair.first << ", " << Mypair.second << endl;

map의 원소 삽입 방법

#1. pair 객체

pair<int, int> Mypair<1, 100>;
Mymap,insert(Mypair);

auto iter = Mymap.begin();

for(; iter != Mymap.end(); ++iter)
{
 iter->second += 10;
 cout << iter->first << ", " << iter->second << endl; 
}

pair<int, int>(1, 100);
Mymap.insert(pair<int, int>(1, 100));
Mymap.insert(pair<int, int>(2, 200));
Mymap.insert(pair<int, int>(3, 300));

map의 key값(iter->first)은 상수이기때문에 대입이 불가능하다.

 

#2. make_pair()

인자로 2가지 정볼르 받아 첫 번째 인자는 key값으로, 두 번째 인자는 value값으로 만든 pair를 반환한다.

Mymap.insert(make_pair(1, 100));

Mymap.insert(make_pair(2, 200));

Mymap.insert(make_pair(3, 300));

 

#3. value_type

map 컨테이너 내부에 구현된 pair객체라고 생각하면 된다.

map<int, int>::value_type MyValuetype(1, 100);
cout << MyValuetype.first << ", " << MyValuetype.second << endl;
MyValuetype.first  = 10;		// 불가능
MyValuetype.second = 1000;

Mymap.insert(MyValuetype);
Mymap.insert(map<int, int>::value_type(2, 200));
Mymap.insert(map<int, int>::value_type(3, 300));

value_type의 key값(first) 또한 상수이기때문에 대입이 불가능하다.

 

#4. index 방식

-> []를 사용한다.

Mymap[1] = 100;

Mymap[2] = 200;

for(auto pair : Mymap)
{
  cout << pair.first << ", " << pair, second << endl;
}

insert 와 []의 차이점

-> insert : 중복된 key값이 있을 경우 무시한다.

-> [] : 중복된 key값이 있을 경우 value를 수정한다.

 

map은 중복되는 key값을 허용하지 않기 때문에 []을 통한 삽입은 자주 사용하지 않는다.

 

#5. emplace()

모든 컨테이너의 삽입 용어를 획일화 하기 위해 추가되었다.

vector : emplace_back()

list     : emplace_back() / emplace_front()

map   : emplace()

Mymap.emplace(1, 100);
Mymap.emplace(2, 200);
Mymap.emplace(3, 300);

단, key의 타입이 다를 경우 오류가 발생한다.

 

#6. 유니폼 초기화

-> {}를 사용한다.

Mymap.insert({1, 100});

-> 초기화가 필요한 것들에 대해서 모든 초기화가 가능하다.

-> 가독성이 떨어진다는 단점이 있다.

 

map의 삽입 정리

map<int, int>		Mymap;

    // index 방식
	Mymap[0] = 0;
    
    // pair 객체
	Mymap.insert(pair<int, int>(1, 100));
    
    // 첫 번째 인자는 key값으로, 두 번째 인자는 value값으로 만든 pair를 반환
	Mymap.insert(make_pair(2, 200));
    
    // map 컨테이너 내부에 구현된 pair 객체
	Mymap.insert(map<int, int>::value_type(3, 300)); 
    
    // 획일화된 삽입 용어(C++11 문법)
	Mymap.emplace(4, 400);
    
    // 유니폼 초기화(C++11 문법)
	Mymap.insert({ 5, 500 });
}

 

map의 반복자

map<int, int> Mymap;

map<int, int>::iterator iter = Mymap.begin();

++iter;
++iter;

cout << iter->first << ", " << iter->second << endl;

map은 노드기반 컨테이너이기 때문에 양방향접근 반복자를 사용한다.

 

 

map의 중간 삽입

Mymap.insert(pair<int, int>(1, 100));
Mymap.insert(make_pair(2, 200));
Mymap.insert(map<int, int>::value_type(3, 300));
Mymap.emplace(4, 400);
Mymap.insert({ 5, 500 });

map<int, int>::iterator iter = Mymap.begin();
++iter;
++iter;

Mymap.insert(iter, {10, 1000});

for(auto pair : Mymap)
  cout << pair.first << ", " << pair.second << endl;

여기서 우리가 원하는 값은 1, 2, 10, 3, 4, 5 이다.

하지만 map은 key값에 따라 자동 정렬이 발생한다.

그렇기 때문에 결과는 1, 2, 3, 4, 5, 10이 나오게 된다.

-> 중간 삽입의 의미가 없게된다.

 

map의 중간 삭제

Mymap.insert(pair<int, int>(1, 100));
Mymap.insert(make_pair(2, 200));
Mymap.insert(map<int, int>::value_type(3, 300));
Mymap.emplace(4, 400);
Mymap.insert({ 5, 500 });

map<int, int>::iterator		iter = Mymap.begin();
map<int, int>::iterator		iter_end = Mymap.end();
++iter;
++iter;

Mymap.erase(iter);
iter = Mymap.begin();

for(; iter != iter_end; ++iter)
{
   cout << iter->first << ", " << iter->second << endl;
}

map의 중간 삭제는 자동 정렬 발생과는 상관이 없으므로

정상적으로 원하는 값이 나오게 된다.(다른 컨테이너 방식과 같음)

 

map의 탐색_find()

cout << Mymap[10] << endl;

탐색을 하기 위해 []를 사용할 경우 key값이 있으면 value를 반환한다.

 

하지만, key값이 없을 경우 원소를 삽입하게된다.

-> 새로운 원소를 삽입 후에 그 원소에 있는 value 값을 반환

 

find()의 사용 방법은 다음과 같다.

map<int, int>		Mymap;

Mymap.insert(pair<int, int>(1, 100));
Mymap.insert(make_pair(2, 200));
Mymap.insert(map<int, int>::value_type(3, 300));
Mymap.emplace(4, 400);
Mymap.insert({ 5, 500 });

auto iter = Mymap.find(4);

if(iter != Mymap.end())
{
   cout << iter->first << ", " << iter->second << endl;
}

find 함수의 문제점

-> find함수는 단순 비교이다.

map<const char*, int> Mymap;

Mymap.emplace("AAA", 10);
Mymap.emplace("BBB", 20);
Mymap.emplace("CCC", 30);

auto iter = Mymap.find("BBB");

char szBuff[16] = "AAA";
auto iter = Mymap.find(szBuff);

if(iter != Mymap.end())
{
   cout << iter->first << ", " << iter->second << endl;
}
else
{
   cout << "탐색 불가" << endl;
}

 

-> key값으로 저장하는 것은 문자열, Data영역의 주소이다.

-> 탐색하고자 하는 szBuff는 지역 변수 stack영역에 할당이 되므로 탐색 불가가 출력이 된다.

-> 즉, 문자열을 비교하는 것이 아니라 단순 주소를 비교하고 있는 것이다.

 

map 컨테이너의 key값이 포인터일 경우 탐색 방법

-> 알고리즘 함수의 find_if를 사용한다.

-> find_if는 단항 조건자여야 한다.

-> 즉, 함수 객체를 통해서 탐색을 하면 된다.

class CStringCmp
{
public:
   CStringCmp(const char* _pString) : m_pString(_pString) {}
   
public:
   template <typename T>
   bool operator()(T& _dst)
   {
     return !strcmp(m_pString, _Dst.first);
   }
   
private:
   const char* m_pString;
};

void main()
{
  map<const char*, int>		Mymap;
  Mymap.emplace("AAA", 10);
  Mymap.emplace("BBB", 20);
  Mymap.emplace("CCC", 30);

  char	szBuff[16] = "AAA";

	
  auto iter = find_if(Mymap.begin(), Mymap.end(), CStringCmp(szBuff));

  if (iter != Mymap.end())
  {
   	 cout << iter->first << ", " << iter->second << endl;
  }
  else
  {
     cout << "탐색 불가" << endl;
  }
}

'Programming > STL' 카테고리의 다른 글

C++(STL Container) 반복자(iterator)  (0) 2020.09.28
C++(STL Container) vector  (0) 2020.09.27
C++(STL Container) list  (0) 2020.09.27
C++ STL이란?  (0) 2020.09.27
STL map / unordered_map 과 map이 사용하는 자료구조  (0) 2020.05.07

+ Recent posts