본문 바로가기
아카이브/자바의 정석

11장 컬렉션프레임워크 20201106

by nineteen 2020. 11. 6.
반응형

HashSet

 

Set인터페이스를 구현한 가장 대표적인 컬렉션

중복허용 x

새로운 요소 추가 시, add, addAll메소드 사용 ( 이미 저장되어있다면 false반환 )

저장순서 유지 x ( 저장순서 유지하려면 LinkedHashSet 사용 )

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.HashSet;
import java.util.Set;
 
public class HashSetEx1 {
    public static void main(String[] args) {
        // 변수구성
        //    다양한 요소가 들어가 있는 Object배열 생성
        //     HashSet생성
        // Object배열의 요소를 HashSet에 추가
        // 출력
        
        // 변수구성
        Object[] objArr = {"1",new Integer(1),"2","2","3","3","4","4","4"};
        Set set = new HashSet();
        
        // HashSet에 요소추가
        for(int i=0; i<objArr.length; i++) {
            set.add(objArr[i]);
        }
        
        // 출력
        System.out.println(set);
    }
}
 
cs

출력

[1, 1, 2, 3, 4]

 

-->

중복이 제거되어서 출력된다. 

1이 두번 출력되었지만, 하나는 String이고, 다른 하나는 Integer로 서로다른 객체이기 때문에 중복으로 간주하지 않음

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
 
public class HashSetLotto {
    public static void main(String[] args) {
        // 변수구성
        //    HashSet생성
        // HashSet에 로또번호를 의미하는 1~45까지의 난수6개를 요소로 저장
        // LinkedList를 이용해 HashSet에 저장되어 있는 요소를 순차적으로 정렬 후 출력
        
        // 변수구성
        Set set = new HashSet();
        
        for(int i=0; i<6; i++) {
            set.add((int)(Math.random()*45)+1);
        }
        System.out.println(set);
        
        // LinkedList 생성, HashSet을 LinkedList로 변환
        List list = new LinkedList(set);
        
        // Collections클래스의 메소드를 이용해 순차적으로 정렬
        Collections.sort(list);        // sort(List list)
        System.out.println(list);
    }
}
cs

출력

[34, 18, 7, 24, 10, 11]
[7, 10, 11, 18, 24, 34]

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
 
public class Bingo {
    public static void main(String[] args) {
        // 변수구성
        //    HashSet생성 (
        //    2차원 배열 생성 ( 빙고판 )
        // HashSet에 1~50까지의 난수를 25개 저장
        // Iterator를 활용해 HashSet에서 요소를 꺼내 2차원 배열에 저장
        
        // 변수구성
        Set set = new HashSet();
        int[][] arr = new int[5][5];
        
        // HashSet에 1~50까지의 난수를 25개 저장
        for(int i=0; set.size()<25; i++) {
            set.add((int)(Math.random()*50)+1+"");    // ""를 더한 이유 -> 문자열로 저장하기위해
        }
        
        // Iterator획득
        Iterator it = set.iterator();
        
        // HashSet에 저장된 요소를 2차원 배열에 저장
        for(int i=0; i<arr.length; i++) {
            for(int j=0; j<arr[i].length; j++) {
                arr[i][j] = Integer.parseInt((String)it.next());
                System.out.print((arr[i][j] < 10 ? "  " : " "+ arr[i][j]);
            }
            System.out.println();
        }
    }
}
cs

출력

 22 44 24 46 26
 27 28 30 32 10
 12 34 13 36 37
 39 17  2  3  6
  8  9 42 20 21

 

 

 

HashSet은 저장된 순서를 보장하지 않고 자체적인 저장방식에 따라 순서가 결졍되기 때문에 같은 숫자가 비슷한 위치에 출력된다.

그래서 이러한 경우에는 HashSet보다 LinkedHashSet이 더 나은 선택이다

 

 

1
Set set = new LinkedHashSet();
cs

출력

 46  5 39 45 36
 28  7 25  2  3
 49 44 31 24 42
 12 15 13 37 10
 20  8 26 43 21

 

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import java.util.HashSet;
import java.util.Set;
 
// Person클래스 정의
//    변수구성
//        name
//        age
//    생성자(String name, int age)
//    equals()메소드 오버라이딩
//        매개변수로 받은 객체와 Person객체의 name과 age가 같은지?
//    hashCode()메소드 오버라이딩
//        name+age한 값의 hashCode반환
//    toString()메소드 오버라이딩
 
class Person {
    // 변수구성
    String name;
    int age;
    
    // 생성자
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Person) {
            Person ps = (Person)obj;                        // 다운캐스팅
            return name.equals(ps.name) && age==ps.age;        // String의 equals() - 문자열같으면 true
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        return (name+age).hashCode();
    }
    
    @Override
    public String toString() {
        return name+":"+age;
    }
    
}
 
public class HashSetEx3 {
    public static void main(String[] args) {
        Set set = new HashSet();
        Person ps1 = new Person("David"10);
        Person ps2 = new Person("David"10);
        
        System.out.println(ps1.equals(ps2));
        
        System.out.println(ps1.hashCode());
        System.out.println(ps2.hashCode());
        
        set.add("abc");
        set.add("abc");
        set.add(ps1);        
        set.add(ps2);        // ps1과 ps2는 같기때문에 중복으로 취급, 하나만 저장됨
        
        System.out.println(set);
    }
}
cs

출력

true
-1185030285
-1185030285
[abc, David:10]

 

 

 

 

 

 

TreeSet

 

이진검색트리라는 자료구조의 형태로 데이터를 저장하는 컬렉션 클래스

이진검색트리의 성능을 향상시킨 '레드-블랙 트리'로 구현

( 이진검색트리는 정렬,검색,범위검색에 높은성능을 보이는 자료구조 )

중복허용 x

저장순서 유지 x

 

이진트리노드를 코드로 표현

1
2
3
4
5
class TreeNode {
    TreeNode left;    // 왼쪽 자식노드
    Object element;    // 객체를 저장하기 위한 참조변수
    TreeNode right;    // 오른쪽 
}
cs

 

부모노드의 왼쪽 - 부모노드의 값보다 작은 값의 자식노드 저장

부모노드의 오른쪽 - 부모노드의 값보다 큰 값의 자식노드 저장

 

 

TreeSet에 저장되는 객체가 Comparable을 구현하던가, Comparator를 제공해서 두 객체를 비교할 방법을 제공해야 함

 

왼쪽 마지막값부터 오른쪽 값까지 '왼쪽노드 -> 부모노드 -> 오른쪽노드' 순으로 읽어오면 오름차순으로 정렬가능

 

정렬된 상태를 유지하기 때문에 단일 값 검색, 범위검색이 매우 빠름

 

 

트리는 데이터 순차적으로 저장x, 저장위치 찾아서 저장o

링크드 리스트보다 데이터의 추가/삭제시간이 더 걸림 ( 트리는 삭제 시, 일부를 재구성해야함 )

배열, 링크드리스트보다 검색과 정렬기능이 뛰어남

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.Set;
import java.util.TreeSet;
 
public class TreeSetLotto {
    public static void main(String[] args) {
        // 변수구성
        //    TreeSet
        // TreeSet에 1~45까지의 난수를 6개 저장
        // 출력
        
        // 변수구성
        Set set = new TreeSet();
        
        // 난수저장
        for(int i=0; i<6; i++) {
            set.add((int)(Math.random()*45)+1);
        }
        
        // 출력
        System.out.println(set);    
    }
}
 
cs

출력

[11, 22, 23, 29, 40, 45]

 

HashSet과는 다르게 정렬하는 코드가 빠져있음 -> TreeSet은 저장할 때 이미 정렬하기 때문

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.util.Set;
import java.util.TreeSet;
 
public class TreeSetEx1 {
    public static void main(String[] args) {
        // 변수구성
        //    TreeSet
        //    from, to ( subSet()메소드의 매개변수로 활용할 변수 )
        // 요소추가
        // subSet()메소드를 이용해 범위검색
        
        // 변수구성
        TreeSet set = new TreeSet();
        String from = "b";    
        String to = "d";
        
        // 요소추가
        set.add("abc");    set.add("alien");    set.add("bat");    set.add("car");
        set.add("Car");    set.add("disc");    set.add("dance");    set.add("dZZZZ");
        set.add("dzzzz");    set.add("elephant");    set.add("elevator");
        set.add("fan");    set.add("flower");
        
        System.out.println(set);
        System.out.println("range search : from " + from + " to " + to);
        System.out.println("result1 : " + set.subSet(from, to));        // b ~ d까지 범위의 해당하는 요소검색 (d는 제외)
        System.out.println("result2 : " + set.subSet(from, to+"zzz"));    // b ~ dzzz까지 범위에 해당하는 요소검색 (d까지 포함)    
    }
}
 
cs

출력

[Car, abc, alien, bat, car, dZZZZ, dance, disc, dzzzz, elephant, elevator, fan, flower]
range search : from b to d
result1 : [bat, car]
result2 : [bat, car, dZZZZ, dance, disc]

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.TreeSet;
 
public class TreeSetEx2 {
    public static void main(String[] args) {
        // 변수구성
        //    TreeSet
        //    1차원 배열
        // 1차원 배열의 요소를 TreeSet에 저장
        // 50보다 작은 요소, 큰 요소 출력
        
        // 변수구성
        TreeSet set = new TreeSet();
        int[] arr = {80,95,50,35,45,65,10,100};
        
        // 1차원 배열 -> TreeSet으로 저장
        for(int i=0; i<arr.length; i++) {
            set.add(new Integer(arr[i]));
        }
        System.out.println(set);
        System.out.println("50보다 작은 요소 : " + set.headSet(new Integer(50)));
        System.out.println("50보다 큰 요소 : " + set.tailSet(new Integer(50)));    
    }
}
 
cs

출력

[10, 35, 45, 50, 65, 80, 95, 100]
50보다 작은 요소 : [10, 35, 45]
50보다 큰 요소 : [50, 65, 80, 95, 100]