본문 바로가기

Java/문법

17 - 3장 Set<E> 컬렉션 인터페이스 (2)

4. LinkedHashSet<E> 구현 클래스 

 

- HashSet<E>의 자식 클래스

- HashSet<E>의 모든 기능에 데이터 간의 연결 정보만을 추가로 갖고 있는 컬렉션 (입력된 순서를 기억)

- 출력 순서가 항상 입력 순서와 동일한 특징

- List<E>처럼 중간에 데이터를 추가하거나 특정 순서에 저장된 값을 가져오는 것은 불가능

 

-LinkedHashSet<E> 클래스의 주요 메서드 활용 방법

package CollectionFramework;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

public class LInkedHashSetMethod {
	public static void main(String[] args) {
		Set<String>linkedSet1 = new LinkedHashSet<>();
		//1. add(E element)
		linkedSet1.add("가");
		linkedSet1.add("나");
		linkedSet1.add("가");
		System.out.println(linkedSet1.toString());
		
		//2.addAll(다른 set 객체)
		Set<String>linkedSet2 = new LinkedHashSet<>();
		linkedSet2.add("나");
		linkedSet2.add("다");
		linkedSet2.addAll(linkedSet1);
		System.out.println(linkedSet2.toString());
		
		//3.remove(Object o)
		linkedSet2.remove("나");
		System.out.println(linkedSet2.toString());
		
		//4. clear()
		linkedSet2.clear();
		System.out.println(linkedSet2.toString());
		
		//5.isEmpty()
		System.out.println(linkedSet2.toString());
		
		//6.contains(Object o)
		Set<String>linkedSet3 = new LinkedHashSet<>();
		linkedSet3.add("가");
		linkedSet3.add("나");
		linkedSet3.add("다");
		System.out.println(linkedSet3.contains("나"));
		System.out.println(linkedSet3.contains("라"));
		
		//7. size()
		System.out.println(linkedSet3.size());
		
		//8.iterator()
		Iterator<String> iterator = linkedSet3.iterator();
		while(iterator.hasNext()) {
			System.out.println(iterator.next());
		}
		
		//9.toArray()
		Object[] objArray = linkedSet3.toArray();
		System.out.println(Arrays.toString(objArray));
		
		//10.1 toArray(T[] t)
		String[] strArray1 = linkedSet3.toArray(new String[0]);
		System.out.println(Arrays.toString(strArray1));
		
		//10-2 toArray(T[] t)
		String[] strArray2 = linkedSet3.toArray(new String[5]);
		System.out.println(Arrays.toString(strArray2));
	}
}

5. TreeSet<E> 구현 클래스 

 

- 공통적인 Set<E>의 기능에 크기에 따른 정렬 및 검색 기능 추가

- 데이터를 입력 순서와 상관없이 크기순으로 출력

- HashSet<E>에서는 단지 두 객체가 같은지, 다른지를 비교했다면, TreeSet<E>에서는 두 객체의 크기를 비교 

- Navigable Set<E>와 SortedSet<E>를 부모 인터페이스로 두고 있음

- TreeSet<E>로 선언해야 SortedSet<E>와 NavigableSet<E>에서 추가된 정렬 및 검색 메서드 호출

 

 -> Set<E> 객체 타입을 선언할때 

Set<String> treeSet = new TreeSet<String>();
treeSet.Set<E>메서드만 사용가능

 -> TreeSet<E>로 객체 타입을 선언할 떄

TreeSet<String> treeSet = new TreeSet<String>();
treeSet. Set<E> 메서드와 정렬/검색 기능 메서드도 사용 가능

 

- TreeSet<E>의 주요 메서드 

구분 메서드명 기능
데이터 검색 first() Set 원소 중 가장 작은 원소값 리턴
last() Set 원소 중 가장 큰 원소값 리턴
lower(E element) 매개변수로 입력된 원소보다 작은, 가장 큰 수
higher(E element) 매개변수로 입력된 원소보다 큰, 가장 작은 수 
flooar(E element) 매개변수로 입력된 원소보다 같거나 작은 가장 큰수
ceiling(E element) 매개변수로 입력된 원소보다 같거나 가장 큰 수 
데이터 꺼내기 pollFirst() Set 원소들 중 가장 작은 원솟값을 꺼내 리턴
pollLast() Set 원소들 중 가장 큰 원솟값을 꺼내 리턴
데이터 부분 집합 생성 headSet(E to Element) toElement 미만인 모든 원소로 구성된Set을 리턴 (toElement 미포함)
headSet(E toElement, boolean inclusive) toElement 미만/이하인 모든 원소로 구성된 Set을 리턴(inclusive=true이면 toElement 포함, inclusive =false 이면 toElement 미포함)
tailSet(E fromElement) toElement 이상인 모든 원소로 구성된 set을 리턴(fromElement 미포함)
tailSet(E fromElement, boolean inclusive) fromElement 초과/이상인 모든 원소로 구성된 Set을 리턴(inclusive=true이면 fromElement 포함, inclusive =false 이면 fromElement 미포함)
subSet( E fromElement, E toElement) fromElement 이상 toElement 미만인 원소들로 이뤄진 Set을 리턴(fromElement 포함, toElement 미포함)
subSet(E fromElement, boolean frominclusive, E toElement, boolean toinclusive) fromElement 초과 이상 toElement 미만/이하인 원소들로 이뤄진 Set을 리턴(fromclusive=true이면 fromElement 포함, toinclusive =false 이면 fromElement 미포함)
데이터 정렬 descendingSet() 현재 정렬 기준을 반대로 변환

 

- TreeSet<E>의 객체 생성 및 데이터 추가와 출력

TreeSet<Integer> treeSet = new TreeSet<Integer>();
for(int i=50; i>0; i-=2) 
	treeSet.add(i);
System.out.println(treeSet.toString()); //[2,4,6,..,50]

 

1) 데이터 검색

 

 -first() : 가장 큰 값

 -last() : 가장 작은 값

 -lower() , higher() : 각 입력값보다 작거나 큰 첫번째 값

 -floor(), ceiling() : 입력값과 동일한 것까지 고려 

//1.first()
System.out.println(treeSet.first()); //2
//2.last()
System.out.println(treeSet.last()); //50
//3.lower(E element)
System.out.println(treeSet.lower(26)); //24
//4.higher(E element)
System.out.println(treeSet.higher(26)); //28
//5.floor(E element)
System.out.println(treeSet.floor(25)); //24
System.out.println(treeSet.floor(26)); //26
//6.ceiling(E element)
System.out.println(treeSet.ceiling(25)); //26
System.out.println(treeSet.ceiling(26)); //26

 

2) 데이터 꺼내기

 

 -TreeSet<E>의 첫번째 값을 pollFirst()로 꺼내는 동작을 25번 반복

 -pollFirst()는 실제 데이터를 꺼내 리턴하므로 size()로 데이터의 크기를 확인해 보면 모든 데이터가 꺼내졌으므로 0이 됨(pollLast()도 동일)

//7.pollFirst()
int treeSetSize = treeSet.size();
System.out.println(treeSetSize); //25
for(int i=0; i< treeSetSize; i++) 
	System.out.println(treeSet.pollFirst()+" "); //2 4 6 ...50
System.out.println(treeSet.size()); //0

//8.pollLast()
for(int i=50; i>0; i-=2)
	treeSet.add(i);
treeSetSize = treeSet.size(); 
System.out.println(treeSetSize); //25
for(int i=0; i <treeSetSize; i++)
	System.out.println(treeSet.pollLast() +" "); //50 48 46 ...2
System.out.println(treeSet.size()); //0

 

3) 데이터 부분 집합 생성 -hashSet(), tailSet()

 

- 입력값의 포함 여부는 두 번째 불리언값으로 제어

for(int i = 50; i > 0; i-=2)
	treeSet.add(i);
//9.SortedSet<E> headSet(E toElement)
SortedSet<Integer>sSet = treeSet.headSet(20); //20미만 데이터 리턴
System.out.println(sSet.toString()); //[2,4,6,..,18]

//10.NavigableSet<E> headSet(E toElement, booelean inclusive)
NavigableSet<Integer> nSet = treeSet.headSet(20,false); //입력값 포함x 20미만 데이터 리턴
System.out.println(nSet.toString()); //[2,4,6,..,18]
nSet = treeSet.headSet(20,true); //입력값 포함 20이하 데이터 리턴
System.out.println(sSet.toString()); //[2,4,6,..,18,20]

//11.SortedSet<E> tailSet(E toElement)
sSet = treeSet.tailSet(20); //20이상 데이터 리턴
System.out.println(sSet.toString());//[20,22,24,...,50]

//12.NavigableSet<E> tailSet(E toElement, boolean inclusive)
nSet = treeSet.tailSet(20,false); //입력값 포함 x, 20 이상 데이터 리턴
System.out.println(nSet.toString()); //[22,24,26,..,50]
nSet = treeSet.tailSet(20,true); //입력값 포함 , 20 이상 데이터 리턴
System.out.println(nSet.toString()); //[20,22,24,26,..,50]

 

4) 데이터 부분 집합 생성 -subSet()

 

- subSet(10,20): 첫 번째 매갭면수 이상이면서 두 번째 매개변수 미만인 데이터로 구성된 Set<E> 객체 리턴

//13.SortedSet<E> subSet(E fromElement, E toElement)
sSet = treeSet.subSet(10,20); //10이상이면서 20미만인 데이터 Set리턴
System.out.println(sSet.toString()); //[10,12,14,16,18]

//14.NavigableSet<E> subSet(E fromElement, booelan frominclusive, E toElement, boolean toinclusive)
nSet = treeSet.subSet(10,true,20,false); 10 포함, 20 포함 x
System.out.println(nSet.toString()); //[10,12,14,16,18]
nSet = treeSet.subSet(10,false,20,true); 10 포함x, 20 포함
System.out.println(nSet.toString()); //[12,14,16,18,20]

 

5) 데이터 정렬

 

- desendingSet()은 현재의 정렬 기준(오름차순, 내림차순)을 바꾸는 메서드 

//15.NavigableSet<E> descendingSet()
System.out.println(treeSet); //[2,4,6,..,50]
NavigableSet<Integer> descendingSet = treeSet.descendingSet();
System.out.println(descendingSet); //[50,48,..,4,2]
descendingSet = descendingSet.descendingSet();
System.out.println(descendingSet);//[2,4,6,..,50]

 

6) TreeSet<E>에서 데이터 크기 비교 

 

- TreeSet<E>에서의 크기  순 정렬을 위해서는 각 데이터들의 크고 작음을 비교할 수 있어야함

- TreeSet<E>에서 Integer 객체의 크기 비교

TreeSet<Integer>treeSet1 = new TreeSet<Integer>();
Integer intValue1 = new Integer(20);
Integer intValue2 = new Integer(20);
treeSet1.add(intValue1);
treeSet2.add(intValue2);
System.out.println(treeSet1.toString()); //[10,20]

-TreeSet<E>에서 String 객체의 크기 비교 

 -> 문자열은 사전 순서로 비교 

TreeSet<String>treeSet2 = new TreeSet<String>();
String str1 = "가나";
String str2 = "다라";
treeSet2.add(str1);
treeSet2.add(str2);
System.out.println(treeSet2.toString()); //[가나, 다라]

- Integer 객체와 String 객체의 크기를 쉽게 비교할 수 있는 이유는 자바가 이미 이들 클래스에 크기 비교 기준을 작성해 놓았기 때문

 

-TreeSet<E>에서 MyClass 객체의 크기 비교

 -> treeSet<E.는 데이터를 입력할 때 크기 순으로 정렬해야 하는데, 이 데이터들의 크기를 비교할 수 없기 떄문에 예외 발생

 -> TreeSet<E>에 저장되는 모든 객체는 크기 비교의 기준이 제공돼야 함

class MyClass{
	int data1;
    int data2;
    public MyClass(int data1, int data2) {
    	this.data1 = data1;
        this.data2 = data2;
    }
}

TreeSet<MyClass>treeSet3 = new TreeSet<MyClass>();
MyClass myClass1 = new MyClass(2,5);
MyClass myClass2 = new MyClass(3,3);
treeSet3.add(myClass1); //예외 발생
treeSet3.add(myClass2); //예외 발생
System.out.println(treeSet3.toString()); //예외 발생

- 크기 기준 제공 방법 1) java.lang.Comparable<T> 인터페이스를 구현

 

 -> java.lang 패키지의 Comparable<T> 제네릭 인터페이스를  구현

 -> 이 인터페이스 내부에는 정숫값을 리턴하는 int compareTo(T t) 추상 메서드 존재 

 -> 자신의 객체가  매개변수 t보다 작을 때 음수, 같을 때 0, 클때  양수를 리턴

 

class MyComparableClass implements Comparable<MyComparableClass> {
	int data1;
    int data2;
    public MyComparableClass(int data1, int data2) {
    	this.data1 = data1;
        this.data2 = data2;
    }
    //override
    public int compareTo(MyComparableClass m) {
    	if(data1 < m.data1) {
        	return -1;
        }else if(data1 == m.data1) {
        	return 0;
        }else
        	return -1;
    }
}
TreeSet<MyComparableClass>treeSet4 = new TreeSet<MyCompareableClass>();
MyCompareableClass myComparableClass1 = new MyComparableClass(2,5);
MyCompareableClass myComparableClass2 = new MyComparableClass(3,3);
treeSet4.add(myComparableClass1);
treeSet4.add(myComparableClass2);
for(MyComparableClass mcc : treeSet4) {
	System.out.println(mcc.data1); // 2->3
}

 

-크기 기준 제공 방법 2) TreeSet 생성자 매개변수로 java.util.Comparator<T> 인터페이스 객체 제공

 

 -> TreeSet<E> 객체를 생성하면서 생성자 매개변수로 Compartor<T> 객체를 제공

 -> TreeSet<E> 객체 생성 과정에서 내부에 포함된 추상 메서드인 compare()를 구현함으로써 크기 비교의 기준을 갖게 됨

 -> 기존의 MyClass 클래스를 수정하지 않아도 됨

TreeSet<MyClass> treeSet5 = new TreeSet<MyClass> (new Comparator<MyClass>() {
	//override
    public int compare(MyClass o1, MyClass o2) {
    	if(o1.data1 < o2.data1)
        	return -1;
        else if (o1.data1 == o2.data1)
        	return 0;
        else
         	return 1;
        }
     });
MyClass myClass1 = new MyClass(2,5);
MyClass myClass1 = new MyClass(3,3);
treeSet5.add(myClass1);
treeSet5.add(myClass2);
for(MyClass mc: treeSet5) {
	System.out.println(mc.data1); //2->3
}