TreeSet 클래스 활용, Comparable, Comparator

gustjtmd·2022년 1월 11일
0

Java

목록 보기
23/40

TreeSet클래스의 이해와 활용

이어서 Set<E> 인터페이스를 구현하는 TreeSet<E> 클래스를 확인해보자
TreeSet<E>는 트리라는 자료구조 기반으로 인스턴스를 저장한다. 이는 정렬된 상태가
유지되면서 인스턴스를 저장됨을 의미한다.

TreeSet<Integer> tree = new TreeSet<>();
        tree.add(3); tree.add(1); tree.add(2);
        tree.add(4); tree.add(5); 
        System.out.println("인스턴스의 수 : " +tree.size());

        //for-each문에 의한 반복
        for(Integer n : tree)
            System.out.print(n.toString()+ '\t');
        System.out.println();

        //Itreator 반복자에 의한 반복
        for(Iterator<Integer> itr = tree.iterator(); itr.hasNext();)
            System.out.print(itr.next().toString()+'\t');
        System.out.println();
출력값
인스턴스의 수 : 5
1	2	3	4	5	5	
1	2	3	4	5	5	
TreeSet<E> 인스턴스가 정렬 상태를 유지하면서 인스턴스를 저장하기 때문에 반복자는
다음의 특징을 갖는다.
"인스턴스들의 참조 순서는 오름차순을 기주능로 한다.

그렇다면 다음 클래스의 인스턴스는 무엇이 작은것이며 무엇이 큰것일까?

class Person{
	private String name;
	private int age;
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
}
------------------------------------------------------------
위 클래스의 경우 기준을 어떻게 정하느냐에 따라서 오름차순으로의 나열 결과는 달라지게 된다.
예를 들어서 크고 작음에 대한 기준을 나이로 둘 수 있고 이름의 가나다 순이 기준이 될 수 있다.
이걸 결정하는건 프로그래머가 결정하는것. 그래서 다음 인터페이스의 구현을 통해서 
크고 작음에 대한 기준을 정해주어야 한다.
public interface Comparable<T>
"이 인터페이스에 위치한 유일한 추상 메소드, int compareTo(T o)

인스턴스의 비교 기준을 정의하는 Comparable<"T"> 인터페이스 구현 기준.

int caompreTo(T o)
인자로 전달된 o가 작다면 양의 정수 반환
인자로 전달된 o가 크다면 음의 정수 반환
인자로 전달된 o가 같다면 0을 반환.
정렬기준 : 나이순
  
  class Person implements Comparable<Person>{
    private String name;
    private int age;
    public Person2(String n, int a){
        name = n;
        age = a;
    }
    @Override
    public String toString(){return name + " : " + age;}

    @Override
    public int compareTo(Person p){
        return this.age - p.age;
    }
}
public class ComparablePerson {
    public static void main(String[] args) {
        TreeSet<Person> tree = new TreeSet<>();
        tree.add(new Person2("YOON", 37));
        tree.add(new Person2("HONG", 53));
        tree.add(new Person2("PARK", 22));

        for(Person2 p : tree)
            System.out.println(p);
    }
}
결과 : 
PARK : 22
YOON : 37
HONG : 53

Comparator<"T"> 인터페이스 기반으로 treeSet의 정렬기준 제시하기.

우리는 Person 클래스를 정의하였다. 이때 나이가 적은 사람이 앞쪽에 위치하도록 compareTo
메소드도 구현해보았다 그런데 나이가 많은 사람이 앞쪽에 위치하도록 기준을 바꿔야 한다면?
물론 메소드의 구현 내용을 수정하면 되지만 일시적인 기준 변경이라면 메소드를 수정하는 일은
적절하지 않다. 이러한 상황을 고려하여 다음 인터페이스가 제공되고 있다.
public interfacce Comparator<T>
  -> int compare(T o1, To2)의 구현을 통해 정렬 기준을 설정할수 있다.
  public TreeSet(Comparator<? super E> comparator
그러면 이렇게 생성된 TreeSet<E> 인스턴스는 생성자로 전달된 인스턴스의 
compare 메소드 호출 결과를 기준으로 정렬을 진행한다. 
compare 메소드의 정의기준.

int compare(T o1, T o2)
o1이 o2보다 크면 양의 정수 반환
o1이 o2보다 작으면 음의 정수 반환
o1이 o2와 같다면 0 반환
class Person5 implements Comparable<Person5>{
    String name;
    int age;
    public Person5(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString(){return name + " : "+ age;}

    @Override
    public int compareTo(Person5 p){
        return this.age-p.age;
    }
}
class PersonComparator implements Comparator<Person5>{
    public int compare(Person5 p1, Person5 p2) {
        return p2.age - p1.age;
	//나이가 많으신 분을 앞에 세우는 연산
    }
}
public class ComparatorPerson {
    public static void main(String[] args) {
        TreeSet<Person5> tree = new TreeSet<>(new PersonComparator());
        tree.add(new Person5("YOON", 37));
        tree.add(new Person5("HONG", 53));
        tree.add(new Person5("PARK", 22));

        for(Person5 p : tree)
            System.out.println(p);
    }
}
출력값
HONG : 53
YOON : 37
PARK : 22
String 클래스의 경우 사전 편찬 순으로 되도록 이미 Comparale<String>
인터페이스를 구현하고 있다. 그런데 이 기준을 문자열의 길이 순으로 수정하고 싶다면?
class StringComparator implements Comparator<String> {
    public int compare(String s1, String s2){
        return s1.length() - s2.length();
    }
}
public class ComparatorString {
    public static void main(String[] args) {
        TreeSet<String> tree = new TreeSet<>(new StringComparator());
        tree.add("Box");
        tree.add("Rabbit");
        tree.add("Robot");

        for(String s : tree)
            System.out.printf(s.toString()+'\t');
    }
}
--------------------------------------------------------
Box	Robot	Rabbit	
위의 예제에서 보이듯이 자바에서 제공하는 기본 클래스를 대상으로 정렬 기준을 바꿔야 하는 상황에서는 Comparator의 구현이 좋은 해결책이 된다!

중복된 인스턴스를 삭제하려면?(추가 정보)

List<E>를 구현하는 컬렉션 클래스는 인스턴스 중복삽입을 허용한다. 그런데 저장된 인스턴스들
중에서 중복 삽입된 인스턴스들을 하나만 남기고 모두 지워야 한다고 가정해보자. 
어떻게 이 일을 처리할수 있겠는가? 이러한 작업을 위한 코드를 별도로 만들수는 있지만
번거롭기 때문에 다음 방법을 기억해두자.

List<String> lst = Arrays.asList("Box", "Toy", "Box", "Toy");
        ArrayList<String> list = new ArrayList<>(lst);

        for(String s : list)
            System.out.print(s.toString()+ '\t');
        System.out.println();

        //중복된 인스턴스를 걸러 내기 위한 작업
        HashSet<String> set = new HashSet<>(list);

        //원래대로 ArrayList<String> 인스턴스로 저장물을 옮긴다.
        list = new ArrayList<>(set);

        for(String s : list)
            System.out.print(s.toString() + "\t");
        System.out.println();
----------------------------------------------------------------
Box	Toy	Box	Toy	
Box	Toy	
profile
반갑습니다

0개의 댓글