자료구조 - Set

강성준·2024년 8월 8일
post-thumbnail

🙋‍♂️ Set이란?

Set이란
자바 컬렉션에 HashSetSet인터페이스의 구현 클래스이다.
Set은 따로 저장 순서를 유지하지 않으며, 또한 중복 값을 허용하지 않는 특징이 있다.

Set은 기본적으로 ArrayList처럼 순열 자료구조(Collection)에 해당한다.
하지만, Set은 순서라는 개념이 존재하지 않는다.
(하지만 순서를 유지하고 싶다면 LinkedHashSet을 사용하면 된다.)

🪄 구현체

Set 인터페이스의 구현체로는 아래와 같이 3가지 구현제가 있다.

  • HashSet
  • TreeSet
  • LinkedHashSet

HashSet

HashSet은 아래와 같은 특징을 가지고 있다.

  • null 입력 가능 (하지만 한 번만 저장이 가능하다. 중복 X)
  • 객체를 중복 저장할 수 없다.
  • 순서를 보장하지 않는다.
  • 내부적으로 HashMap을 사용한다.

TreeSet

TreeSet은 아래와 같은 특징을 가지고 있다.

  • null 입력 가능 (하지만 한 번만 저장이 가능하다. 중복 X)
  • 객체를 중복 저장할 수 없다.
  • 오름차순으로 데이터를 정렬한다.
  • 내부적으로 TreeMap을 사용한다.

TreeMap이란?
이진 트리를 기반으로 한 Map.
Tree 구조로 이루어져있어 데이터를 저장할 때 즉시 오름차순 정렬된다.
이러한 특징으로 인해 HashMap에 비해 추가, 삭제가 더 오래걸린다.
(정렬된 상태의 Map이 필요하다면 사용하는 것이 좋다.)

LinkedHashSet

LinkedHashSet은 아래와 같은 특징을 가지고 있다.

  • null 입력 가능 (하지만 한 번만 저장이 가능하다. 중복 X)
  • 객체를 중복 저장할 수 없다.
  • 입력한 순서(저장 순서)대로 데이터를 정렬한다.
  • 내부적으로 LinkedHashMap을 사용한다.

LinkedHashMap이란?
HashMap의 특징인 key의 순서가 지켜지지 않는 것과 반대로
입력된 순서대로 key의 순서가 보장된다. 사용법은 HashMap과 동일하다.

🙇‍♂️ 연습 문제

  1. List<Integer> 이 주어진다. 이 목록에서 일부 요소는 반복될 수 있다. 여기서 모든 중복 요소를 제거하고 고유한 요소만 포함하는 새 목록을 반환하는 메서드를 작성하자.
public List<Integer> removeDuplicates(List<Integer> myList) {
	// 비어 있는 목록이 들어왔을때 빈 목록 반환
	if(myList.size() == 0) return new ArrayList<>();
    
    Set<Integer> set = new HashSet<>();
    
    for(int i = 0; i < myList.size(); i++) {
    	set.add(myList.get(i));		// 이렇게만 해도 중복된 값은 안들어간다.
    }
    
    // 새로운 목록에 set을 담아 반환
    return new ArrayList<>(set);
}

  1. 주어진 문자열에 모든 고유 문자가 포함되어있는지 여부를 판단하는 메서드를 작성하자.
    입력문자열의 모든 문자가 고유한지, 중복 문자가 있는지에 대한 여부를 반환해야한다.

ex) "abcdefg" -> true, "" -> true, hello -> false

public boolean hasUniqueChars(String str) {
	// 비어있는 문자열이 들어왔을 때 처리
	if(str = null) return false;
    
    Set<Character> set = new HashSet<>();
    
    for(int i = 0; i < str.length(); i++) {
    	char currentChar = str.charAt(i);	// 한글자씩 검사하기 위해 변수에 담음
        if(!set.add(currentChar)) {		// add 메서드는 boolean을 반환함(false가 반환되면 저장되지 않았다는것. 즉 반복되는 문자가 있다는 것)
        	return false;
        }
    }
    
    // 반복문 내 조건에 걸리지 않았다면 문자열 내 모든 문자가 고유한 문자라는 것
    return true;
}

  1. 두 개의 int형 배열 arr1 arr2가 주어졌다. target 정수가 주어졌을때 target 정수와 같은 합을 이루는 모든 정수 쌍을 찾는 메서드를 작성하자.

ex)
int[] arr1 = {1,2,3,4,5};
int[] arr2 = {2,4,6,8,10};
int target = 7;

// 결과
[5, 2], [3, 4], [1, 6]

public List<int[]> findPairs(int[] arr1, int[] arr2, int target) {
	// 비어있는 배열이 들어왔을 경우 처리
	if(arr.length == 0 || arr.length == 0) return new ArrayList<>();
    
    Set<Integer> set = new HashSet<>();
    
    // arr1의 요소들을 set에 저장
    for(int num : arr1) {
    	set.add(num)
    }
    
    List<int[]> pairs = new ArrayList<>();
    
    for(int num : arr2) {
    	// target에서 arr2의 현재 요소를 빼면 필요한 숫자가 무엇인지 알 수 있다.
    	int temp = target - num;
        
        // 그 숫자가 set내에 존재하는지 확인한다.
        if(set.contains(temp)) {
        	// 존재한다면 List내에 새로운 배열을 만들어 추가한다.
        	pair.add(new int[]{num, temp});
        }
    }
    
    // 반복이 끝나면 List를 반환한다.
    return pairs;
}

😄 마무리

Set은 중복되는 데이터를 제거하기 위해서 사용한다면 효과적인 선택이 될 수 있다.
실제 연습 문제를 풀때 Set을 사용하지 않는다면 중복을 제거하기 위해 추가적인 코드가 더 작성 되어야 한다. 방식에 따라서 완전 탐색이 필요할 수 있다. 그러한 부분에서 성능적인 부담이 커지게 되는데 그 부분을 Set을 이용한다면 쉽고 빠르게 해결할 수 있다. 개발자가 개발할때는 자료구조를 선택하는데 있어서 생각을 하고 선정하여 코드에 활용하는 능력이 중요할 것 같다.

profile
Java, Spring Framework로 백엔드 개발을 하는 개발자입니다.

0개의 댓글