내일배움캠프 32일차 - 자료구조 & 알고리즘 5주차 : Map, Set

Map - 이름표로 데이터에 접근

map은 key-value 쌍을 저장하는 자료구조
key는 이름표(찾는 기준), value는 실제 데이터.

시간복잡도: 검색 / 삽입 /삭제 모두 O(log n)
 - 내부적으로 이진 탐색 트리(BST) 라는 구조를 사용하기 때문.
 - ex) 1만개 데이터 → 약 14번이면 찾는다.

※ 이진 탐색 트리(BST)란?
데이터를 크기 순서대로 정리해서 빠르게 찾는 구조.
"왼쪽은 작은 값, 오른쪽은 큰 값" - 이 규칙 하나로 검색 범위를 절반씩 줄여나간다.

map의 핵심 규칙

규칙1: key는 중복 불가. 같은 키로 다시 넣으면 기존 값이 사라진다.

규칙2: 순회하면 key 기준 정렬. 넣은 순서가 아니라 key의 오름차순으로 나온다.


map 주요 연산 정리

연산
설명시간 복잡도
m["key"] = value삽입 또는 수정O(log n)
m.insert({"key",value})삽입 (수정x)O(log n)
m["key"]값 읽기 ( [ ] 자동생성 주의! )O(log n)
m.count("key")존재 여부 반환 (0 또는 1)O(log n)
m.erase("key")삭제O(log n)
for(auto& p : m)순회 (p.first / p.second)
O(n)

※ map.insert() 사용 시에 값이 이미 있으면 덮어 씌우지 않는다


[ ] 자동생성의 함정

없는 키를 []로 읽기만 해도 기본값(int는 0)으로 자동 생성된다.
의도치 않게 map 크기가 늘어나는 버그의 원인이 된다.

 : 검색 목적이라면 []를 직접 쓰지 않고 count()로 먼저 확인하고 있을 때만 []로 접근하기


Map의 사용 예시 - 카운팅 패턴 : 자동생성이 오히려 편리해지는 방법

map에서 가장 자주 쓰이는 패턴이다.

동작 원리:

1. n이 처음 등장: countMap[n]은 없는 키 → 0으로 자동 생성++1
2. n이 이미 있음: countMap[n]은 기존 값 → ++값 증가

"함정"이라고 했던 자동생성이, 카운팅에서는 오히려 편리한 기능이 된다.


map.find() vs map.count()

map.find()는 key의 위치를 iterator로 반환하고(없으면 end()값 반환),

map.count()key의 유무만을 반환한다는 특징이 있다.


Set - 값만 있는 맵

"이 값이 존재하는가?" 만 관심이 있을 때 쓴다.

(map = 사전, set = 출석부 에 비유된다)


중복 제거 + 자동 정렬

set은 map의 특성을 가지고 있어 중복제거자동정렬의 기능을 가진다.

insert순서: 30,10,20,10,30 → {10,20,30}

그 외에도 insert(), count(), erase(), 순회 모두 map과 거의 동일한 인터페이스를 가진다.


unordered_map - 정렬을 포기하면 더 빨라진다

사용법은 map / set 과 거의 동일하다.
unordered_map해시(Hash)를 사용한다는 차이가 있다. (map이진탐색트리)



mapunordered_map
내부 구조이진 탐색 트리해시 테이블
검색 속도O(log n)O(1) 평균
순회 순서key 정렬 순보장 없음
추천 용도정렬빠른 검색

정렬이 필요하면 map / 빠른 검색이 필요하면 unordered_map을 사용한다.

둘의 사용법은 insert()count()erase()[] 모두 동일하다.


해시(Hash) - O(1)검색의 비밀

v[3]하면 메모리에서 바로 3번 칸을 찾아간다. 숫자 인덱스로 바로 접근하므로 O(1)이다.

그렇다면 "김철수"같은 문자열도 숫자로 바꿀 수 있다면, 배열처럼 바로 접근할 수 있지 않을까?

 → 이것이 해시 함수(Hash function)의 아이디어. 어떤 데이터든 고정 크기의 숫자(해시값) 출력


해시 테이블의 원리

해시검색: "김철수" → hash() → 2 → 배열[2] → 바로 찾음! O(1)


해시충돌 - 같은 칸에 두명이?

해시함수가 "김철수" → 2, "정하나" → 2 를 반환한다면? 해시 충돌(Hash Collision)이 발생한다.

해시충돌(Hash Collision) 예시


해시 충돌 해결 방법: 같은 해시끼리는 리스트로 연결한다.
 → 같은 해시 내에서 리스트 검색이 발생

이것이 unordered_map이 "평균 O(1)" 이라고 하는 이유이다.


map, set의 실제 사용사례

게임 개발

map은 게임에서 데이터 관리의 핵심이다.

게임에서의 map사용 예시

UE5에서는 TMapTSet이라는 이름으로 동일한 구조를 제공한다.

웹/서버

웹에서는 key-value 구조는 사실상 모든 곳에 있다.

{"name": "철수", "score": 78}

이것이 바로 JSON - 웹의 표준 데이터 형식이자 key-value 구조이다.

서버 캐시(Redis)도 거대한 해시 테이블이고,
URL 쿼리(?key=value), HTTP 헤더, 쿠키도 전부 key-value를 사용한다.

CS 전반

해시 테이블은 컴퓨터 과학에서 가장 중요한 자료구조 중 하나다.

 - 데이터베이스의 인덱스
 - 파일 무결성 검증(체크섬)
 - 암호학 (암호화 해시)
 - 블록체인

"데이터를 숫자로 바꾸는" 해시의 아이디어는 CS 전반에 걸쳐있다.
(Python의 dict, JavaScript의 Object/Map도 같은 원리를 사용한다)


오늘의 핵심

 - map은 key-value 쌍을 저장: vector는 숫자 인덱스, map은 의미있는 키로 접근

 - [] 자동 생성 주의: 없는 키를 []로 읽기만 해도 기본값으로 자동 생성, 검색은 count() 먼저

 - 카운팅 패턴 countMap[n]++: 없으면 0 자동생성 → +1, 있으면 기존 값 +1
    자동 생성이 오히려 편리해지는 역전의 패턴.

 - set은 "값만 있는 map": 중복 불가 + 자동 정렬을 가진 STL. "있는가?"만 확인할 때 사용.

 - 시간복잡도 차이: mapO(log n), unordered_map평균 O(1) 의 연산속도을 가진다.

댓글

이 블로그의 인기 게시물

내일배움캠프 사전캠프 - 사전캠프설 연휴 커피 파밍 이벤트 작품 [ EXTREMITY ]

내일배움캠프 29일차 - 커리어데이 2일차 : 클라이언트 프로그래머로서 포트폴리오, 입사준비팁