[Java] 자바 #37, Set 계열 컬렉션(HashSet, TreeSet)
- 프로그래밍 언어/Java
- 2019. 3. 6. 22:21
Set 계열 컬렉션
- 순서가 없는 배열
- 첨자가 업슴
- 중복값을 가질 수 없다.
HashSet
- Set인터페이스 구현한 컬렉션
- 순서는 중요하지 않고 의미를 가지지 않는다.
- 같은 set 인터페이스 구현컬렉션 내에 중복값을 허용하지 않는다.
HashSet 예제 1
Set<String> set = new HashSet<String>();
요소 추가.
set.add("하나");
set.add("둘");
set.add("셋");
set.add("넷");
set.add("다섯");
System.out.println(set.add("하나")); // 무시 혹은 덮어쓰기...
System.out.println(set.size()); //set 사이즈
모든 요소 출력 -> Set은 순서가 중요하지 않은 집합(***)
System.out.println(set.toString()); //[넷, 둘, 하나, 셋, 다섯] -> 순서가 중요하지 않다고 했음.
Set계열 컬렉션을 사용하면 편한경우 1.
- 중복값을 없애는 코드가 필요한 경우
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 | class Example{ public static void main(String[] args){ // 로또번호 추출 // 1. ArrayList // 2. HashSet Random ran = new Random(); ArrayList<Integer> list = new ArrayList<Integer>(); // 중복 없애는 코드 for (int i = 0; i < 6; i++) { int num = ran.nextInt(45) + 1; //1부터 45까지 랜덤숫자 반환... boolean flag = false; for (int j = 0; j < i; j++) { if (num == list.get(j)) { //이전까지 나왔던 숫자들과 비교해서 중복숫자 나오면 빼줘야했음. flag = true; } } // for j if (flag) i--; else list.add(num); } System.out.println(list.toString()); // ex) [26, 9, 43, 17, 38, 30] Set<Integer> set2 = new HashSet<Integer>(); while (set2.size() < 6) { //셋에서는 이렇게 6자리의 숫자가 정해질때까지 추출하면 됨. int num2 = ran.nextInt(45) + 1; set2.add(num2); } System.out.println(set2); // ex) [33, 36, 21, 5, 38, 31] } } | cs |
HashSet 예제 2
- 복합값 집합(클래스 (객체) 집합)
ex)
Set<String> set = new HashSet<String>();
set.add("홍길동");
set.add("홍길동");
>>> 이 경우에는 "홍길동"이라는 문자열이 두개 겹치므로 당연히 뒤에 나오는 값은 set에 더해지지 않는다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Person{ private String name; private int age; public Person(String name, int age) { this.name=name; this.age=age; } @Override public String toString() { return String.format("%s(%s)",this.name,this.age); } } | cs |
다음과 같은 Person 클래스가 있다고 할때! 같은 name값을 가지고 같은 age 값을 가지는 객체는 같게 인식할까???
nob!!
Set<Person> set2 = new HashSet<Person>();
set2.add(new Person("홍길동",20));
set2.add(new Person("홍길동",20));
System.out.println(set2.toString()); >>> [홍길동(20), 홍길동(20)] 아니이런?
>> 서로 다른 객체이다보니(new 키워드로 각각 생성한) 같은 값을 가졌는지는 판단하지 않고 다른 객체로만 판단함.
>> Person 클래스에 hashCode() 메소드와 equals() 메소드를 오버라이딩 하여준다.
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 | class Person{ private String name; private int age; public Person(String name, int age) { this.name=name; this.age=age; } @Override public String toString() { return String.format("%s(%s)",this.name,this.age); } @Override public int hashCode() { return (this.name+this.age).hashCode(); } @Override public boolean equals(Object obj) { //p1.equals(p2) if(obj instanceof Person) { Person p = (Person)obj; return this.hashCode()==p.hashCode(); } return false; } } | cs |
Person 클래스에 다음과 같이 hashCode 메소드와 equals 메소드를 재정의 해준다.
이유 >>
1. 참조변수를 비교할때 주소값을 비교하게 되는데 이를 문자열 형태로 변환한다. 즉, "주소값"으로 변환하고 여기에 hashCode 메소드를 통해 해쉬코드값으로 변환시켜 준다.
2. 이 원리를 통해 주소값을 비교하도록 만들지 말고, 클래스 내의 멤버변수 값을 비교하도록 name과 age의 데이터를 문자열 결합(+)을 통해 "홍길동20" 으로 만든 후 "홍길동20".hashCode() 메소드를 통해 "홍길동20"의 해쉬코드값을 비교하게 만들도록 구조를 바꾸었다.
- 이러한 작업을 클래스내에 작성하여주고 다시한번 컴파일을 하면 같은 객체로써 뒤의 객체는 set에 담기지 않는다.
set2.add(new Person("홍길동",20));
set2.add(new Person("홍길동",20));
System.out.println(set2.toString()); [홍길동(20)]
HashSet 예제 3
Set<String> set = new HashSet<String>();
set.add("사과");
set.add("바나나");
set.add("복숭아");
set.add("사과"); // 얘는 당연히 안담기겠죠?? 아셔야합니다. 이젠ㅎㅎ
과일을 이름순서대로 정렬해주세요. -> Set은 순서개념이 없음. -> 정렬도 못함. -> 되게하려면 Set을 List로 변화시켜야함.(역도 됨)
Set을 List로 바꾸는 방법
List<String> list = new ArrayList<String>(set);
System.out.println("list : "+list.toString()); 정렬 전 list : [복숭아, 사과, 바나나]
정렬
Collections.sort(list); -> Collections 클래스의 라이브러리로 배열계열을 () 안에 넣으면 원형 배열(list 컬렉션 포함)이 정렬됨.
System.out.println("list : "+list.toString()); 정렬 후 list : [바나나, 복숭아, 사과]
TreeSet
- Set : 중복값 X, 순서 X(정렬 X)
- 자료구조 특성 때문 -> 자동정렬(데이터를 관리하는 형태 자체가 이미 정렬이 완성된 형태로 관리가 된다.)
- 트리 구조(이진 검색 트리 구조)
- 검색, 범위검색 용이(******) : TreeSet을 선택하는 이유(목적, 용도)
TreeSet 예제1
TreeSet<Integer> set = new TreeSet<Integer>();
set.add(10);
set.add(20);
set.add(30);
set.add(40);
set.add(50);
System.out.println(set); [10, 20, 30, 40, 50] 해쉬셋은 엉망으로 들어있는데 TreeSet은 정렬이 되서 들어있다.
TreeSet 예제2
Random ran = new Random();
TreeSet<Integer> set = new TreeSet<Integer>();
while (set.size() < 30) {
set.add(ran.nextInt(30) + 1);
}
System.out.println( set ); [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]
>>> 순서대로 1부터 30까지 담긴 set
System.out.println( set.subSet(5, 10) ); [5, 6, 7, 8, 9]
>>> subSet(a,b) 에서 b는 포함하지 않는(미만이란뜻) set을 반환
System.out.println( set.headSet(10) ); [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> 헤드셋(a) 는 맨 첫값부터 a미만까지의 값까지의 set을 반환
System.out.println( set.tailSet(10) ); [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]지
>>> tailSet(a)는 첫값부터 a미만번째(9)까지의 set을 버리고 나머지 set을 반환.
이런 것도 당연히 가능
TreeSet<String> items = new TreeSet<String>();
items.add("필통");
items.add("스마트폰");
items.add("텀블러");
items.add("티슈");
items.add("우산");
items.add("마우스"); //아이템을 담고(물론 중복없고 한글순서대로 저장되겠죠??)
items.add("키보드");
items.add("커피");
items.add("가위");
items.add("테이프");
items.add("연습장");
//한글의 순서를 숫자라 치고 하는것도 가능!
System.out.println(items.subSet("마", "차")); [마우스, 스마트폰, 연습장, 우산]
System.out.println(items.headSet("자")); [가위, 마우스, 스마트폰, 연습장, 우산]
System.out.println(items.tailSet("자")); [커피, 키보드, 텀블러, 테이프, 티슈, 필통]
TreeSet 예제3
- 객체(참조형) 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 30 31 32 33 | class User { private String name; private int point; public User(String name, int point) { this.name = name; this.point = point; } @Override public String toString() { return String.format("%s(%d)", this.name, this.point); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPoint() { return point; } public void setPoint(int point) { this.point = point; } } | cs |
이러한 User 클래스가 있을 때
TreeSet 생성자 안에 compare 메소드를 오버라이딩한 Comparator<> 익명객체를 삽입하는 방법
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class Example{ public static void main(String[] args) { TreeSet<User> set = new TreeSet<User>(new Comparator<User>() { @Override public int compare(User a, User b) { //포인트 순으로 정렬할 경우 return a.getPoint()-b.getPoint(); // 이름순으로 정렬할 경우 //return a.getName().compareTo(b.getName()); } }); set.add(new User("홍길동", 100)); set.add(new User("아무개", 10)); set.add(new User("하하하", 55)); set.add(new User("호호호", 90)); set.add(new User("테스트", 42)); System.out.println(set); } } | cs |
출력 결과 : [아무개(10), 테스트(42), 하하하(55), 호호호(90), 홍길동(100)] (포인트순 오름차순 - 저거 더하기빼기 b.getPoint - a.getPoint 일캐 해주면 내림차순됩니다. )
- TreeSet 생성자의 ( ) 안에 TreeSet의 데이터형으로 제네릭형 Comparator 익명객체를 생성하여 넣어준다. 그리고 그안의 compare 메소드를 오버라이딩 해주면 이런식으로 TreeSet에 있는 참조형 객체데이터에 대한 정렬도 가능하다.
Comparable 인터페이스를 구현하여 정렬하는 방법
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 | class Unit implements Comparable<Unit>{ private String name; private int point; public Unit(String name, int point) { this.name = name; this.point = point; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPoint() { return point; } public void setPoint(int point) { this.point = point; } @Override public int compareTo(Unit o) { return this.point - o.point; } @Override public String toString() { return "["+this.name+this.point+"]"; } } | cs |
Comparable 인터페이스를 구현하는 Unit 클래스가 있다고 할때, 이 Unit 클래스는 compareTo 메소드를 오버라이딩 해줍니다. 그렇게 되면 TreeSet에 값이 삽입될때 오버라이딩된 compareTo 메소드를 이용하여 정렬을 진행하게 됩니다.
TreeSet<Unit> uset = new TreeSet<Unit>();
uset.add(new Unit("A",100));
uset.add(new Unit("B",120));
uset.add(new Unit("C",130));
uset.add(new Unit("D",140));
uset.add(new Unit("E",110));
System.out.println("uset"+uset);
출력 결과 : uset[[A100], [E110], [B120], [C130], [D140]]
'프로그래밍 언어 > Java' 카테고리의 다른 글
[Java] 자바 #39, File입출력(1) (0) | 2019.03.07 |
---|---|
[Java] 자바 #38, TreeMap, Properties 개념 (0) | 2019.03.06 |
[Java] 자바 #36, Iterator 반복자 (0) | 2019.03.05 |
[Java] 자바 #35, 배열 관련 라이브러리 및 Array클래스의 활용 (0) | 2019.03.04 |
[Java] 자바 #34, List 인터페이스 계열 컬렉션(ArrayList, LinkedList, Vector) & ArrayList vs LinkedList 예제 (0) | 2019.03.04 |