1. Set 컬렉션의 특징 및 주요 메서드
1) 특징
- 수학의 집합과 유사한 개념.
- 저장 순서가 유지되지 않고, 중복도 허용하지 않음. ex) 양의 정수집합, 소수의 집합 등
- 하나의 null 만 저장할 수 있음.
- 인덱스로 객체를 검색해 가져오는 메서드가 없으므로 반복자(Iterator)를 제공.
2) 구현 클래스
- HashSet
- LinkedHashSet
- TreeSet
3) 주요 메서드 (※저장 순서가 유지되지 않기 때문에 인덱스를 검색해서 가져오는 메서드는 없음.)
기능 | 메서드 | 설명 |
객체 추가 | boolean add(E e) | 주어진 객체 추가 |
객체 검색 | boolean contains(Object o) | 주어진 객체가 저장되어 있는지 여부에 따라 true / false 를 리턴 |
boolean isEmpty() | 컬렉션 전체가 비어 있는 지 조사해서 true, false 로 리턴 | |
Iterator<E> iterator() | 저장된 객체를 한 번씩 가져오는 반복자 리턴 | |
int size() | 저장되어 있는 전체 객체 수를 리턴 | |
객체 삭제 | void clear() | 저장된 모든 객체를 삭제 |
boolean remove(Object o) | 주어진 객체를 삭제 | |
객체 배열 | Object[] toArray() | Set에 저장된 객체를 배열로 반환 |
Object[] toArray(Object[] a) |
- Iterator 반복자 사용법
Object[] objArr = { "1", "2", "3", "4", "5" }
Set set = new HashSet();
//배열을 set 에 추가
for(int i=0; i<objArr.length, i++) {
set.add(ObjArr[i]); //HashSet에 objArr의 요소들을 저장.
Iterator it = set.iterator();
while(it.hasNext()) { //읽어올 요소가 있는지 확인 후,
System.out.println(it.next()); //요소 하나씩 꺼내오기
- Set 컬렉션 객체 추가, 찾기, 삭제
Set<String>list = ....; //Set이 저장하는 객체 타입이 String 타입이라는 의미
set.add("홍길동"); //객체 추가
set.add("김자바"); //객체 추가
set.remove("홍길동"); //객체 삭제
2. HashSet
1) 내부 구조 표현 방법
Set<E> set = new HashSet<E>();
2) 순서 유지를 하고 싶으면 LinkedHashSet 클래스를 사용
3) 순서를 유지하지 않고 중복도 허용하지 않음.
- 객체가 다르더라도 동등하다고 판단되면 중복 저장 하지 않음.
4) 동일한 객체인지 판단하는 방법
- HashSet 사용
Set set = new HashSet();
//set의 크기가 6보다 작은 동안 1~45 사이의 난수를 저장
for(int i=0; set.size()<6, i++) {
int num = (int)(Math.random()*45)+1;
set.add(num);
}
System.out.println(set); //정렬되지 않은 숫자들이 랜덤으로 출력됨
List list = new LinkedList(set); //LinkedList(Collection c) set을 리스트로 옮긴 후,
Collections.sort(list); //Collections.sort(List list) 숫자를 정렬
System.out.println(list); //오름차순으로 정렬된 숫자들이 출력됨
- HashSet은 객체를 저장하기 전에 기존에 같은 객체가 있는지 확인. 같은 객체가 없으면 저장하고, 있으면 저장하지 않음
- boolean add(Object o)는 저장할 객체의 equals()와 hashCode()를 호출. equals()와 hashCode()가 오버라이딩 되어 있어야 함. (아래 예시 참고)
HashSet set = new HashSet();
set.add("abc");
set.add("abc"); //중복이라 저장 안됨.
set.add("new Person("David,10"); //중복인데도 불구하고 저장 되어 출력됨.
set.add("new Person("David,10"); //새로 생성한 Person 객체에서 equals(), hashCode()가 오버라이딩 안되어서.
System.out.println(set); //출력: [abc, David:10, David:10]
//equals(), hashCode()를 오버라이딩 해야 HashSet이 바르게 동작.
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
Public String toString() {
return name +":"+ age;
}
- equals(), hashCode() 오버라이딩 후
HashSet set = new HashSet();
set.add("abc");
set.add("abc"); //중복이라 저장 안됨.
set.add("new Person("David,10"); //equals(), hashCode()가 오버라이딩 되어 있어서 중복으로 처리.
set.add("new Person("David,10");
System.out.println(set); //출력: [abc, David:10]
//equals(), hashCode()를 오버라이딩 해야 HashSet이 바르게 동작.
class Person {
String name;
int age;
@Override
public int hashCode() {
//int hash(Object... values); //... 가변인자라서 어떤 매개변수를 넣어도 됨.
return Objects.hash(name, age);
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Persron)) return false;
Person p = (Person)obj;
//나 자신(this)의 이름과 나이를 p와 비교
return this.name.equals(p.name) && this.age == p.age;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
Public String toString() {
return name +":"+ age;
}
3. TreeSet
1) 객체 생성 구조
TreeSet<E> treeSet = new TreeSet<E>();
2) 트리 형태의 부모 노드와 자식 노드로 구성된 '이진 탐색 트리 (binary search tree)'를 이용하여 계층적 구조(tree 구조)를 가지면서 객체를 저장함. 범위 검색과 정렬에 유리함.
- 이진 트리 (binary tree) : 부모 노드에 최대 2개의 자식 노드를 연결할 수 있는 것.
- 이진 탐색 트리 (binary search tree) : 이진 트리의 하위개념. 부모보다 작은 값은 왼쪽, 큰 값은 오른쪽에 저장됨.
- 단점 : 데이터가 많아질 수록(트리가 커질수록) 추가, 삭제에 시간이 더 걸림. (비교 횟수 증가)
※ 참고 : 트리 순회(tree traversal)
- 이진 트리의 모든 노드를 한 번씩 읽는 것.
- 전위, 중위, 후위 순외법이 있으며, 중위 순외하면 오름차순으로 정렬됨.
3) TreeSet에 객체를 저장하면 부모값과 비교해 자동으로 정렬됨.
4) 노드는 노드 값과 왼쪽과 오른쪽 자식을 참조하기 위한 두 개의 변수로 구성
5) 주요 메서드
- 검색 메서드 : first(), last(), lower(), higher(), floor(), ceiling(), pollFirst(), pollLast()
- 정렬 메서드 : descendingIterator(), descendingSet()
- 범위 검색 메서드 : headSet(), tailSet(), subSet()
6) 메서드 구현하기
- 검색 메서드 : first(), last(), lower(), higher(), floor(), ceiling() 활용
public class TreeSetExample1 {
public static void main(String[] args) {
TreeSet<Integer> scores = new TreeSet<Integer>();
scores.add(87);
scores.add(98);
scores.add(75);
scores.add(95);
scores.add(80);
Integer score = null;
score = scores.first(); //가장 왼쪽에 있는 객체를 얻어서 리턴
System.out.println("가장 낮은 점수 : " + score);
score = scores.last(); //가장 오른쪽에 있는 객체를 얻어서 리턴
System.out.println("가장 높은 점수 : " + score);
score = scores.lower(95); //95 보다 더 낮은 객체를 리턴
System.out.println("95점 아래 점수 : " + score);
score = scores.higher(95); //95 보다 더 높은 객체를 리턴
System.out.println("95점 위의 점수 : " + score);
//95가 있으면 95 리턴, 95가 없으면 95 바로 아래의 객체 리턴
score = scores.floor(95);
System.out.println("95점이거나 바로 아래 점수 : " + score);
//85가 있으면 85 리턴, 85가 없으면 85 바로 위의 객체 리턴
score = scores.ceiling(85);
System.out.println("85점 위의 점수 : " + score);
}
}
출력 화면
가장 낮은 점수 : 75
가장 높은 점수 : 98
95점 아래 점수 : 87
95점 위의 점수 : 98
95점이거나 바로 아래 점수 : 95
85점 위의 점수 : 87
- 검색 메서드 : pollFirst() 활용
public class TreeSetExample1 {
public static void main(String[] args) {
TreeSet<Integer> scores = new TreeSet<Integer>();
scores.add(87);
scores.add(98);
scores.add(75);
scores.add(95);
scores.add(80);
Integer score = null;
while(!scores.isEmpty()) {
//제일 작은 값인 왼쪽 자식 노드부터 하나씩 빼서 treeset에서 제거한 후 저장.
score = scores.pollFirst();
System.out.println(score+ " 를 빼면 남는 객체 수 : "+scores.size());
}
출력 화면
//제일 작은 값인 왼쪽 자식 노드부터 하나씩 빼서 treeset에서 제거한 후 저장하기 때문에,
//최종 남는 객체는 0이 됨.
75 를 빼면 남는 객체 수 : 4
80 를 빼면 남는 객체 수 : 3
87 를 빼면 남는 객체 수 : 2
95 를 빼면 남는 객체 수 : 1
98 를 빼면 남는 객체 수 : 0
- 검색 메서드 : pollLast() 활용
public class TreeSetExample1 {
public static void main(String[] args) {
TreeSet<Integer> scores = new TreeSet<Integer>();
scores.add(87);
scores.add(98);
scores.add(75);
scores.add(95);
scores.add(80);
Integer score = null;
while(!scores.isEmpty()) {
//제일 큰 값인 오른쪽 자식 노드부터 하나씩 빼서 treeset에서 제거한 후 저장.
score = scores.pollLast();
System.out.println(score+ " 를 빼면 남는 객체 수 : "+scores.size());
}
출력 화면
//제일 큰 값인 오른쪽 노드부터 하나씩 빼서 treeset에서 제거한 후 저장하기 때문에,
//최종 남는 객체는 0이 됨.
98 를 빼면 남는 객체 수 : 4
95 를 빼면 남는 객체 수 : 3
87 를 빼면 남는 객체 수 : 2
80 를 빼면 남는 객체 수 : 1
75 를 빼면 남는 객체 수 : 0
- 정렬 메서드 : descendingSet() 활용
public class TreeSetExample1 {
public static void main(String[] args) {
TreeSet<Integer> scores = new TreeSet<Integer>();
scores.add(87);
scores.add(98);
scores.add(75);
scores.add(95);
scores.add(80);
//내림차순으로 정렬
NavigableSet<Integer> descendingSet = scores.descendingSet();
for(Integer score : descendingSet) {
System.out.print(score + " ");
}
System.out.println();
System.out.println();
//descendingSet.descendingSet 의미 : 내림차순에 한번 더 내림차순을 하게되면 올림차순이 됨.
NavigableSet<Integer> ascendingSet = descendingSet.descendingSet();
for(Integer score : ascendingSet) {
System.out.print(score + " ");
}
System.out.println();
}
}
출력 화면
98 95 87 80 75 //올림차순
75 80 87 95 98 //내림차순
- 범위 검색 메서드 : subSet() 활용
public class TreeSetExample1 {
public static void main(String[] args) {
TreeSet<String> treeSet = new TreeSet<String>();
treeSet.add("apple");
treeSet.add("forever");
treeSet.add("description");
treeSet.add("ever");
treeSet.add("zoo");
treeSet.add("base");
treeSet.add("guess");
treeSet.add("cherry");
System.out.println("[c~f 사이의 단어 검색]");
//시작하는 값, 유무 여부, 끝나는 값, 유무 여부 확인해서 정렬해주는 subSet()메서드
NavigableSet<String> rangeSet = treeSet.subSet("c", true, "f", true);
for(String word : rangeSet) {
System.out.println(word);
}
}
}
출력 화면
[c~f 사이의 단어 검색]
cherry
description
ever
참고 : [한빛미디어] 이것이 자바다 (신용권의 Java 프로그래밍 정복) Chapter 15.컬렉션 프레임워크
참고 : [도우출판] JAVA의 정석(3ND EDITION)-자바의 정석 최신 Java 8.0 포함 Chapter 11.컬렉션 프레임워크
'JAVA' 카테고리의 다른 글
인터페이스 (Interface) (0) | 2022.09.02 |
---|---|
Map 컬렉션 (HashMap, TreeMap) (0) | 2022.08.28 |
List 컬렉션 (0) | 2022.08.28 |
컬렉션 프레임워크 (0) | 2022.08.28 |
람다식 (Lambda Expression) (0) | 2022.08.28 |
댓글