HashSet

- Set 인터페이스에서 지원하는 구현 클래스로 순서대로 입력되지 않고, 일정하게 유지되는 것이 특징이다.

- HashSet은 null 요소도 허용한다.

- 이 클래스의 가장 큰 특징은 중복을 허용하지 않는다는 것이다.

 

HashSet 변수 선언

HashSet<데이터타입> 변수명 = new HashSet<데이터타입>(); 으로 선언

HashSet<Integer> : Integer형의 HashMap 데이터가 들어감

HashSet<String> : String형의 HashMap 데이터가 들어감

HashSet<Integer> set1 = new HashSet<Integer>();
HashSet<String> set2 = new HashSet<String>();

 

집합

1. 교집합

변수명1.retainAll(변수명2);

 

2. 합집합

변수명1.addAll(변수명2);

 

3. 차집합

변수명1.removeAll(변수명2);


실습 코드

// 기초 수학 - 집합

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;

public class Main {
    public static void main(String[] args) {

//      1. 자바에서 집합 사용 - HashSet
        System.out.println("== HashSet ==");
        HashSet set1 = new HashSet();
        set1.add(1);
        set1.add(1);
        set1.add(1);
        // 데이터의 중복이 허용되지 않으니깐 1만 출력이 됨
        System.out.println("set1 = " + set1);
        set1.add(2);
        set1.add(3);
        System.out.println("set1 = " + set1); // 1, 2, 3 출력
        set1.remove(1); // set1: size = 3
        // 인덱스가 아니라 값이 들어가서 데이터 1이 삭제되어
        System.out.println("set1 = " + set1); // 2와 3만 출력
        System.out.println(set1.size()); // size = 2
        System.out.println(set1.contains(2)); // set1에 2라는 데이터가 들어있는지 확인 -> true
//      2. 집합 연산
        System.out.println("== 집합 연산 ==");

//      2-1. 교집합
        // 교집합 연산을 위한 집합 2개 생성
        HashSet a = new HashSet(Arrays.asList(1, 2, 3, 4, 5));
        HashSet b = new HashSet(Arrays.asList(2, 4, 6, 8, 10));

        a.retainAll(b); // 교집합 계산이 되어 a에는 교집합 연산만 남는다.
        System.out.println("교집합: " + a);
//      2-2. 합집합
        a. addAll(b);
        System.out.println("합집합 : " + a);
//      2-3. 차집합
        a.removeAll(b);
        System.out.println("차집합 : " + a);
  }
}

Set 함수 도움 없이 구현해보기

// Practice
// ArrayList를 사용한 집합 구현 실습 (집합 관련 연산 사용 X)

import java.util.ArrayList;

class MySet {
    // ArrayList
    ArrayList<Integer> list;
/* 집합을 위한 기능들을 추가해주기
 멤버변수로 ArryList Integer타입이 하나 잡혀있고
 list를 초기화하기 위한 생성자 2개를 만들어주기
*/ 
// 생성자1
    MySet() {
        this.list = new ArrayList<Integer>();
    } // 객체 만든 것

// 생성자 2
    // 데이터를 만들어서 객체를 만들 때 그 데이터를 넣어주는 생성자
    MySet(int[] arr) {
        this.list = new ArrayList<Integer>();

        for (int item : arr) { // 들어온 데이터를 갖고(arr) list에 하나씩 add됨
            this.list.add(item);
        }
    }

// 원소 추가 (중복 X)
    /* 리스트에 있는 원소들을 순회를 하면서, add하려는 데이터와 list에 있는 데이터를
    비교를 하면서 만약 같은게 있으면 데이터를 추가하지 않고 return해서 함수를 벗어난다.
    */ 
    public void add(int x) {
        for (int item : this.list) {
            if (item == x) {
                return;
            }
        }
        // 중복 값이 발견되지 않으면 데이터 추가
        this.list.add(x);
    }

// 교집합
    /*
    retainAll은 HashSet의 이름과 같은 이름으로 맞춤
    차이 : HashSet의 기본적인 교집합 연산은 a, b라는 집합이 있을때
    a.retainAll(b); 라고 할 때 a의 집합 값이 바뀐다.
    그러나 여기선 a의 내용은 그대로 두고 교집합 된 집합을 새로 반환하는
    함수를 만들어 보는 것
     */
    public MySet retainAll(MySet b) {
        MySet result = new MySet(); // 반환을 위한 MySet 자료형 만들기

        for(int itemA : this.list) {
            for(int itemB : b.list) {
                // 자기 자신의 리스트를 순회하고 새로 들어온 집합을 순회하면서 비교하는 부분을 작성
                if(itemA == itemB) {
                    result.add(itemA);
                }
            }
        }
        return result;
    }

// 합집합
    public MySet addAll(MySet b) {
        MySet result = new MySet(); // 반환을 위한 MySet 자료형 만들기

        /* 자기 자신의 리스트와 합집합 하려는 대상 리스트를
         result에 add 해주는 것
         add는 위에서 만들었던 중복은 추가하지 않고 add 시켜주는 것(중복X)
        */ 
        for(int itemA : this.list) {
            result.add(itemA);
            }
        for(int itemB : b.list) {
            result.add(itemB);
        }
        return result;
    }

// 차집합
    public MySet removeAll(MySet b) {
        MySet result = new MySet();

        /* 현재 집합의 리스트를 순회 하면서
         차집합 하려는 대상의 리스트를 순회를 하는데
         같은 원소가 있으면 빼주어야 하니깐 원소가 있는지 없는지를 구분하기 위해
         boolean containFlag 변수를 하나 잡아주었고,
         만약 순회를 하다가 같은 값을 찾았으면 남은 원소를 굳이 순회하지 않아도 되니깐
         아래에서 데이터 처리를 위해. 있다라는 containFlag를 true로 바꿔줌
         더 순회할 필요는 없으니 break문으로 안쪽 for문을 탈출시킴
        */ 
        for(int itemA : this.list) {
            boolean containFlag = false;

            for(int itemB : b.list) {
                if(itemA == itemB) {
                    containFlag = true;
                    break;
                }
            }
            /* containFlag가 false면 -> 두 리스트에 같은 값이 없다는 것
            a-b에서 살아남는 원소가 result에 더해져서 return 됨
            */ 
            if(!containFlag) {
                result.add(itemA);
            }
        }
        return  result;
    }
}

public class Practice {
    public static void main(String[] args) {

//      Test code
        // HashSet이 아닌 만들어준 MySet 클래스를 이용해서 객체를 만들어 준 것
        MySet a = new MySet();

        a.add(1);
        a.add(1);
        a.add(1);
        System.out.println(a.list); // 마찬가지로 중복 데이터는 제거되서 1만 출력됨
        a.add(2);
        a.add(3);
        System.out.println(a.list); // 2, 3 추가 1, 2, 3 출력

        a = new MySet(new int[]{1, 2, 3, 4, 5});
        MySet b = new MySet(new int[]{2, 4, 6, 8, 10});
        System.out.println("a: " + a.list);
        System.out.println("b: " + b.list);

        MySet result = a.retainAll(b);
        System.out.println("교집합: " + result.list);

        result = a.addAll(b);
        System.out.println("합집합: " + result.list);

        result = a.removeAll(b);
        System.out.println("차집합: " + result.list);
    }
}

 

'자료구조 l 알고리즘 > Ch. 01. 기초 수학' 카테고리의 다른 글

지수와 로그  (0) 2023.03.16
점화식과 재귀함수  (0) 2023.03.16
조합  (0) 2023.03.15
순열  (0) 2023.03.14
경우의 수  (0) 2023.03.14