HashSet 완전 정복: 개념, 예제, 그리고 List와의 차이점까지!

chocobiv·2025년 4월 16일
post-thumbnail

1️⃣ HashSet이란?

Java Collection Framework 중 하나로, 중복을 허용하지 않는 데이터 저장 구조
내부적으로 HashMap을 사용한다.

주요 특징: 순서 없음, 중복 없음, 빠른 탐색

Set<String> set = new HashSet<>();


2️⃣ 어떨 때 사용할까?

  1. 중복 제거가 필요할 때

  2. 빠른 탐색이 필요할 때 (시간복잡도 O(1))

  3. 리스트보다 존재 여부 체크가 더 중요할 때


🧐 왜 HashSet을 사용하면 빠를까?
1. 탐색 시간
일반적인 배열에서는 값을 찾기 위해 앞에서부터 끝까지 일일이 비교해야 함 → O(n)
HashSet은 내부적으로 해시함수를 통해 값을 저장하고 조회하기 때문에 → O(1)

set.contains();

contains()로 해당 값이 set에 있는지를 거의 즉시 확인할 수 있다.


2. 삽입 시간
HashSet에 값을 넣는 것도 해시를 기반으로 하기 때문에 일반적으로 O(1)

set.add();

즉, n개의 원소를 HashSet에 넣는 데 O(n),
m개의 원소를 각각 탐색하는 데 O(m) → 총 O(n + m)



3️⃣ 기본 예제

import java.util.*;

public class HashSetExample {
    public static void main(String[] args) {
        Set<String> fruits = new HashSet<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Apple"); // 중복, 저장되지 않음

        System.out.println(fruits); // [Apple, Banana] 순서 보장 안 됨
        System.out.println(fruits.contains("Banana")); // true
    }
}


4️⃣ HashSet vs ArrayList 차이

항목HashSetArrayList
중복 허용❌ 허용하지 않음✅ 허용함
순서 유지❌ 순서 보장 안 됨✅ 입력 순서 유지
탐색 시간✅ O(1) (빠름)❌ O(n) (느림)
인덱스로 접근❌ 불가능✅ 가능 (get(index))
주요 목적중복 제거 / 포함 여부 확인순서 유지 / 순차적 데이터 처리

활용 예: 배열 중복 제거

int[] arr = {1, 2, 2, 3, 4, 4};
Set<Integer> unique = new HashSet<>();
for (int num : arr) {
    unique.add(num);
}
System.out.println(unique); // [1, 2, 3, 4]


5️⃣ 헷갈릴 수 있는 포인트 정리

1. HashSet은 순서를 유지하지 않는다 → 출력 순서에 의존하면 안 됨

😵‍💫 오해하기 쉬운 점
"Apple → Banana → Cherry"를 넣었으니 이 순서대로 출력될 거야!
HashSet입력 순서가 아닌 해시값 기준으로 저장됨. 출력 순서는 예측 불가.

📌 예제

	Set<String> set = new HashSet<>();
	set.add("Apple");
	set.add("Banana");
	set.add("Cherry");
	System.out.println(set); // 출력 예: [Banana, Cherry, Apple]

해결 방법이 필요하면?
순서를 유지하고 싶다면 LinkedHashSet 사용


2. contains()는 빠르지만, get(index)는 불가능함

😵‍💫 오해하기 쉬운 점
set.get(1) 하면 두 번째 값이 나올 줄 알았는데?
HashSet은 인덱스를 기반으로 값을 꺼낼 수 없음. 순서도 없고, 인덱스도 없음.

📌 잘못된 코드

Set<String> set = new HashSet<>();
set.add("A");
set.add("B");

// 오류 발생!
String s = set.get(1); 		// ❌ get()은 존재하지 않음

해결 방법이 필요하면?

인덱스 접근이 필요하면 ArrayList를 사용하거나 Set을 리스트로 변환

List<String> list = new ArrayList<>(set);
System.out.println(list.get(1));

3. HashSet은 내부적으로 HashMap<K, Object>로 구현됨

😵‍💫 오해하기 쉬운 점
"contains로 찾았으니 몇 번째에 있는지도 알 수 있겠지?"
HashSet은 값이 존재하는지 여부만 확인 가능. 인덱스 위치는 알 수 없음.

📌 예제

Set<Integer> set = new HashSet<>();
set.add(10);
set.add(20);

System.out.println(set.contains(20)); 	// ✅ true
// set.indexOf(20); 					// ❌ 불가능, 메서드 없음

4. HashSet에 null을 넣을 수 있다

😵‍💫 오해하기 쉬운 점
"null은 예외 터질 것 같은데?"
HashSetnull 값을 1개까지 저장 가능

📌 예제

Set<String> set = new HashSet<>();
set.add(null);
set.add(null); 				// 중복이므로 저장 안 됨

System.out.println(set); 	// [null]


6️⃣ 마무리 요약

  1. HashSet은 빠르고 효율적인 중복 제거 및 탐색용 컬렉션

  2. 내부 구조는 해시 기반, 순서 없음

  3. 실무에서 자주 쓰이며, 특히 브루트포스 최적화, 중복 제거 등에서 유용


profile
공부하는 velog

0개의 댓글