Data+

21. STL hash_map

by Qerogram

* STL 컨테이너에는 크게 sequence 컨테이너, 연관 컨테이너로 나뉜다.

- sequence는 앞서 배웠던, vector, list, deque와 같이 순서 있게 자료를 보관한다.

- 연관 컨테이너는 어떠한 Key와 짝을 이루어 자료를 보관한다. python의 딕셔너리를 생각하자.

(종류는 map, set, hash_map, hash_set 등이 있다. 만약 중복되는 key를 사용하려면 multi를 붙인 걸 사용)

- hash사용 시엔 정렬이 필요 없이 빠른 검색을 원할 때,

- hash없이 사용시엔 정렬 된 상태로 자료 저장시에 사용한다.

- hash_map, hash_set은 표준이 아니라서 gcc에서는 using namespace __gnu_cxx;로 커버한다.


* hash_map의 자료구조는 해시 테이블이다.

- Key를 해시 함수에 대입하여, 버킷 번호가 나오면 그 버킷의 빈 슬롯에 자료를 저장한다.

(db 테이블이라 생각하면 쉽겠다).


 버킷번호

 슬롯1

슬롯2

슬롯3 

 

 

 

1

 

 


2

 

 

 


* hash_map<Key 자료형, Value 자료형> 변수 명;

- hash_map<int, float> hash1;

* 동적할당 또한 가능하다.

- hash_map<int, float>* hahsh1 = new hash_map<int, float>;


* 주요 멤버는 앞서 배운 sequence container와 유사하다.

- insert

-> 직접 대입, 원하는 위치 대입, 요소 대입(hash_map)

1
2
3
4
5
6
hash_map<intfloat> hashmap1, hashmap2;
hashmap1.insert(hash_map<intfloat>::value_type(1045.6f));
 
hashmap1.insert(hashmap1.begin(), hash_map<intfloat>::value_type(1150.2f));
 
hashmap2.insert(hashmap1.begin(), hashmap1.end());
cs


- erase

-> 특정 위치에 있는 요소 삭제, 지정한 구역에 있는 요소 삭제, 지정한 키와 같은 요소 삭제.

1
2
3
hashmap1.erase(hashmap1.begin());
hashmap1.erase(hashmap1.begin(), hashmap1.end());
hashmap1.erase(11);
cs


- 검색

- return된 반복자가 const냐 아니냐는 차이로 2가지 방법이 존재하지만 사용법은 같다.

-> const라면 Value, Key 변경 불가 const가 아니라면 Key만 변경 불가.

1
2
3
4
hash_map<intfloat>::iterator FindIter = hashmap1.find(10);
if(FindIter != hashmap1.end()) {
    FindIter->second = 290.44f;
}
cs

=> second가 Value에 해당한다.


# 활용

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
#include <iostream>
#include <hash_map>
using namespace std;
using namespace __gnu_cxx;
 
struct GameCharacter {
  GameCharacter() { }
  GameCharacter(int CharCd, int Level, int Money) {
    _CharCd = CharCd;
    _Level = Level;
    _Money = Money;
  }
  int _CharCd;
  int _Level;
  int _Money;
};
 
void print(hash_map<int, GameCharacter> Characters) {
  hash_map<int, GameCharacter>::iterator iterPos = Characters.begin();
  for(iterPos; iterPos!=Characters.end(); ++iterPos) {
    cout << "캐릭터 코드 : " << iterPos->second._CharCd << " | 레벨 : " << iterPos->second._Level << " | 돈 : " << iterPos->second._Money << endl;
  }
}
 
 
int main() {
  hash_map<int, GameCharacter> Characters;
  GameCharacter Character1(1271000);
  GameCharacter Character2(15,20,111000);
  GameCharacter Character3(300,34,3345000);
  Characters.insert(hash_map<int,GameCharacter>::value_type(12, Character1));
  Characters.insert(hash_map<int ,GameCharacter>::value_type(15, Character2));
  Characters.insert(hash_map<int, GameCharacter>::value_type(300, Character3));
  print(Characters);
  
  int Count = Characters.size();
  cout << "저장 된 요소 수 : " << Count << endl;
  
  hash_map<int, GameCharacter>::iterator FindIter = Characters.find(15);
  cout << endl;
  if(Characters.end() == FindIter) {
    cout << "캐릭터 코드가 20인 캐릭터가 없습니다." << endl;
  } 
  else {
    cout << "캐릭터 코드가 15인 캐릭터를 찾았습니다." << endl;
    cout << "캐릭터 코드 : " << FindIter->second._CharCd << " | 레벨 : " << FindIter->second._Level << " | 돈 : " << FindIter->second._Money << endl;
  }
  
  cout << endl;
  print(Characters);
  cout << endl;
  Characters.erase(15);
  print(Characters);
  
  Characters.erase(Characters.begin(), Characters.end());
  cout << endl;
  if(Characters.empty()) {
    cout << "Characters는 비어있습니다." << endl;
  }
  
  return 0;
}
cs


* 결과

캐릭터 코드 : 12 | 레벨 : 7 | 돈 : 1000
캐릭터 코드 : 15 | 레벨 : 20 | 돈 : 111000
캐릭터 코드 : 300 | 레벨 : 34 | 돈 : 3345000
저장 된 요소 수 : 3

캐릭터 코드가 15인 캐릭터를 찾았습니다.
캐릭터 코드 : 15 | 레벨 : 20 | 돈 : 111000

캐릭터 코드 : 12 | 레벨 : 7 | 돈 : 1000
캐릭터 코드 : 15 | 레벨 : 20 | 돈 : 111000
캐릭터 코드 : 300 | 레벨 : 34 | 돈 : 3345000

캐릭터 코드 : 12 | 레벨 : 7 | 돈 : 1000
캐릭터 코드 : 300 | 레벨 : 34 | 돈 : 3345000

Characters는 비어있습니다.


* lower_bound와 upper_bound

- hash_map에 저장한 요소 중에서 Key 값으로 해당 요소의 시작 위치를 얻을 때 사용하는 멤버이다.

ex) 23, 4, 5, 18, 14, 30이라는 순서로 Key값을 가진 요소가 저장 되어 있다면, 18과 크거나 같은 것을 찾으면 18 14 30이 나온다.

- Key가 있다면 해당 요소 반복자를 리턴한다(lower_bound)

- Key가 있다면 그 요소 다음 위치의 반복자를 리턴한다(upper_bound)

- gcc에서는 lower_bound, upper_bound를 정식 멤버로 등록하지 않기 때문에 에러가 난다.

# 사용

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
#include <iostream>
#include <hash_map>
using namespace std;
using namespace __gnu_cxx;
 
struct GameCharacter {
  GameCharacter() { }
  GameCharacter(int CharCd, int Level, int Money) {
    _CharCd = CharCd;
    _Level = Level;
    _Money = Money;
  }
  int _CharCd;
  int _Level;
  int _Money;
};
 
void print(hash_map<int, GameCharacter> Characters) {
  hash_map<int, GameCharacter>::iterator iterPos = Characters.begin();
  for(iterPos; iterPos!=Characters.end(); ++iterPos) {
    cout << "캐릭터 코드 : " << iterPos->second._CharCd << " | 레벨 : " << iterPos->second._Level << " | 돈 : " << iterPos->second._Money << endl;
  }
}
 
 
int main() {
  hash_map<int, GameCharacter> Characters;
  GameCharacter Character1(1271000);
  GameCharacter Character2(15,20,111000);
  GameCharacter Character3(7,34,3345000);
  GameCharacter Character4(1412112200);
  GameCharacter Character5(2535000);
  Characters.insert(hash_map<int,GameCharacter>::value_type(12, Character1));
  Characters.insert(hash_map<int ,GameCharacter>::value_type(15, Character2));
  Characters.insert(hash_map<int, GameCharacter>::value_type(7, Character3));
  Characters.insert(hash_map<int, GameCharacter>::value_type(14, Character4));
  Characters.insert(hash_map<int, GameCharacter>::value_type(25, Character5));
  cout << "저장한 캐릭터 리스트" << endl;
  print(Characters);
  /*
  cout << "lower_bound(14)" << endl;
  hash_map<int, GameCharacter>::iterator Iter = Characters.lower_bound(14);
  while(Iter!=Characters.end()) {
    cout << "캐릭터 코드 : " << Iter->second._CharCd << " | 레벨 : " << Iter->second._Level << " | 돈 : " << Iter->second._Money << endl;
    ++Iter;
  }
  cout << endl;
  
  cout << "upper_bound(7)" << endl;
  Iter = Characters.upper_bound(7);
  while(Iter!= Characters.end()) {
    cout << "캐릭터 코드 : " << Iter->second._CharCd << " | 렙레 : " << Iter->second._Level << " | 돈 : " << Iter->second._Level << endl;
    ++Iter;
  }
  */
  return 0;
}
cs

* 결과(예상)

캐릭터 코드 : 12 | 레벨 : 7 | 돈 : 1000 캐릭터 코드 : 7 | 레벨 : 34 | 돈 : 3345000

캐릭터 코드 : 15 | 레벨 : 20 | 돈 : 111000

캐릭터 코드 : 14 | 레벨 : 12 | 돈 : 112200

캐릭터 코드 : 25 | 레벨 : 3 | 돈 : 5000 lower_bound(14)

캐릭터 코드 : 14 | 레벨 : 12 | 돈 : 112200

캐릭터 코드 : 25 | 레벨 : 3 | 돈 : 5000


upper_bound(7)

캐릭터 코드 : 15 | 레벨 : 20 | 돈 : 111000

캐릭터 코드 : 14 | 레벨 : 12 | 돈 : 112200

캐릭터 코드 : 25 | 레벨 : 3 | 돈 : 5000

* 참고 : Thinking About C++ STL Programming

'코딩 > C&C++' 카테고리의 다른 글

23. STL set  (0) 2017.04.20
22. STL map  (0) 2017.04.20
20. STL deque2  (0) 2017.04.19
19. STL deque1  (0) 2017.04.18
18. STL vector3  (0) 2017.04.18

블로그의 정보

Data+

Qerogram

활동하기