cs/자료구조

HashMap (해시맵)

icodesiuuuu 2024. 11. 1. 13:06

1. HashMap이란?

HashMap은 키-값 쌍으로 데이터를 저장하는 자료 구조입니다. 키(Key)는 고유하며, 같은 키로 두 번 데이터를 넣으면 기존 값이 새로운 값으로 덮어쓰입니다.

Java의 HashMap은 해시 테이블(Hash Table)을 기반으로 구현되며, 해싱을 사용하여 키와 값의 위치를 빠르게 찾아갈 수 있습니다. HashMap은 내부에서 배열과 연결 리스트(그리고 Java 8부터는 트리)를 혼합하여 데이터를 저장하며, null 키와 null 값을 허용하는 특징이 있습니다.

 

2. HashMap의 기본 동작 원리

HashMap의 핵심은 해싱(Hashing)이라는 개념에 있습니다. 해싱은 키를 해시 함수에 넣어 정수로 변환하고, 이 값을 기반으로 특정 위치에 값을 저장하는 방식입니다. HashMap의 중요한 특징을 살펴보면:

  1. 해시 함수: HashMap에서 해시 함수는 hashCode() 메서드를 통해 얻은 해시 코드를 활용하여 배열의 인덱스를 계산합니다.
  2. 해시 충돌: 다른 키가 같은 인덱스를 가질 수 있는데, 이를 충돌이라고 합니다. Java의 HashMap은 이 충돌을 해결하기 위해 체이닝(Chaining) 방식과 Java 8 이후부터는 트리(Tree)를 사용하여 충돌을 해결합니다.
  3. 재해싱: 데이터가 일정량 이상 쌓이면 해시 테이블 크기를 늘리고 다시 해시 테이블을 구성하는 작업을 수행합니다. HashMap의 기본 **로드 팩터(Load Factor)**는 0.75로, 테이블의 75%가 차면 크기를 두 배로 늘리고 재해싱을 합니다.

 

3. HashMap 주요 메서드 및 사용법

기본적인 메서드들

Java의 HashMap은 다양한 메서드를 제공합니다. 가장 자주 쓰이는 몇 가지 메서드를 코드 예제와 함께 알아보겠습니다.

 
import java.util.HashMap;

public class HashMapExample {
    public static void main(String[] args) {
        // HashMap 생성
        HashMap<String, Integer> map = new HashMap<>();

        // 1. put(): 요소 추가
        map.put("Alice", 25);
        map.put("Bob", 30);
        map.put("Charlie", 35);

        // 2. get(): 키로 값 찾기
        System.out.println("Alice's age: " + map.get("Alice")); // 25 출력

        // 3. remove(): 요소 제거
        map.remove("Bob");

        // 4. containsKey(): 키가 존재하는지 확인
        System.out.println("Contains Charlie? " + map.containsKey("Charlie")); // true 출력

        // 5. containsValue(): 값이 존재하는지 확인
        System.out.println("Contains age 30? " + map.containsValue(30)); // false 출력

        // 6. size(): 요소 개수 확인
        System.out.println("Size of map: " + map.size()); // 2 출력

        // 7. isEmpty(): 비어있는지 확인
        System.out.println("Is map empty? " + map.isEmpty()); // false 출력
    }
}

주의할 점

  1. null 값과 키는 허용되지만, null 키는 오직 하나만 허용됩니다.
  2. 삽입 순서를 보장하지 않습니다. 순서가 중요하다면 LinkedHashMap을 고려하세요.

 

4. HashMap의 해시 충돌 처리 및 재해싱

해시 충돌 처리

해시 충돌이 발생하면 HashMap은 체이닝을 통해 해결합니다. 동일한 해시 값을 가진 키는 연결 리스트로 연결됩니다. Java 8 이후에는 연결 리스트의 크기가 일정 수준 이상으로 커지면 트리로 변환하여 성능을 높입니다.

재해싱

HashMap의 기본 용량은 16이며, 로드 팩터는 0.75입니다. 만약 요소가 증가하여 용량의 75%를 초과하면 HashMap은 크기를 두 배로 늘리고 모든 요소를 다시 해싱합니다.

 

5. HashMap을 활용한 예제: 학생 성적 관리

HashMap을 활용하여 학생 이름을 키로, 성적을 값으로 저장하여 관리해보겠습니다. 이 예제에서는 학생의 이름을 기반으로 성적을 추가, 수정, 삭제하고, 전체 학생의 성적을 출력하는 기능을 구현합니다.

import java.util.HashMap;
import java.util.Map;

public class StudentScores {
    private HashMap<String, Integer> scores;

    // 생성자
    public StudentScores() {
        scores = new HashMap<>();
    }

    // 학생 추가
    public void addStudent(String name, int score) {
        scores.put(name, score);
        System.out.println(name + "의 성적이 추가되었습니다.");
    }

    // 학생의 성적 조회
    public Integer getScore(String name) {
        return scores.get(name);
    }

    // 학생의 성적 수정
    public void updateScore(String name, int score) {
        if (scores.containsKey(name)) {
            scores.put(name, score);
            System.out.println(name + "의 성적이 수정되었습니다.");
        } else {
            System.out.println(name + " 학생이 존재하지 않습니다.");
        }
    }

    // 학생 삭제
    public void removeStudent(String name) {
        if (scores.remove(name) != null) {
            System.out.println(name + " 학생이 삭제되었습니다.");
        } else {
            System.out.println(name + " 학생이 존재하지 않습니다.");
        }
    }

    // 전체 학생의 성적 출력
    public void printAllScores() {
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            System.out.println(entry.getKey() + " : " + entry.getValue());
        }
    }

    public static void main(String[] args) {
        StudentScores studentScores = new StudentScores();
        
        // 학생 추가
        studentScores.addStudent("Alice", 85);
        studentScores.addStudent("Bob", 92);
        
        // 특정 학생 성적 조회
        System.out.println("Alice's score: " + studentScores.getScore("Alice"));
        
        // 학생 성적 수정
        studentScores.updateScore("Alice", 90);

        // 전체 학생 성적 출력
        studentScores.printAllScores();

        // 학생 삭제
        studentScores.removeStudent("Bob");
        
        // 삭제 후 전체 학생 성적 출력
        studentScores.printAllScores();
    }
}

실행 결과:

 
Alice의 성적이 추가되었습니다.
Bob의 성적이 추가되었습니다.
Alice's score: 85
Alice의 성적이 수정되었습니다.
Alice : 90
Bob : 92
Bob 학생이 삭제되었습니다.
Alice : 90

 

6. HashMap의 장점과 단점

장점

  • 빠른 접근 속도: 키 기반으로 해시를 사용하여 값을 빠르게 검색할 수 있습니다.
  • 유연성: null 키와 값을 허용합니다.

단점

  • 동기화 지원 안됨: HashMap은 기본적으로 비동기화이므로 멀티스레드 환경에서 안전하지 않습니다. 멀티스레드 환경에서는 ConcurrentHashMap을 사용해야 합니다.
  • 순서 보장 안됨: HashMap은 삽입 순서를 보장하지 않습니다.

 

'cs > 자료구조' 카테고리의 다른 글

Priority Queue(우선순위 큐)  (0) 2024.11.22
Graph (그래프)  (0) 2024.10.15