공부함

Java 정렬 본문

Java

Java 정렬

찌땀 2023. 12. 25. 22:21

https://80000coding.oopy.io/21cb57a3-681b-404d-a4ac-8ab0e7289bc0

 

[JAVA] Sort 사용 (Arrays, Collections)

Java’s Sort

80000coding.oopy.io

Arrays.sort

		int[] arr = new int[] {1,5,3,2,4};
		Arrays.sort(arr);
		Integer[] arr2 = new Integer[] {3,4,6,1};
		Arrays.sort(arr2);

Arrays.sort로 배열을 정렬할 수 있다. 오름차순으로 정렬한다.

		Integer[] arr2 = new Integer[] {3,4,6,1};
		Arrays.sort(arr2,Collections.reverseOrder());

내림차순으로 정렬하고 싶으면 위와 같이 두번째 인자로 Collections.reverseOrder()를 전달해준다.

Collections.sort

		List<Integer> arr3 = new ArrayList<Integer>(List.of(1,2,3,4));
		Collections.sort(arr3);
		Collections.sort(arr3,Collections.reverseOrder());

Collections.sort()는 List에 사용한다. Arrays.sort와 마찬가지로 기본 오름차순이고 두번째 인자로 Collections.reverseOrder()를 전달해서 내림차순 정렬할 수 있다.

Comparable과 Comparator를 활용한 정렬

class Player{
	private int age;
	private int power;
	
	public Player(int age, int power) {
		this.age = age;
		this.power = power;
	}
}

Player 객체를 정렬한다고 생각해보자. 무엇을 기준으로 정렬할지 애매하다. age, power 또는 둘다..?

이처럼 정렬 기준이 정해져 있지 않은 객체를 정렬하거나, 오름차순, 내림차순 말고 다른 방식으로 정렬하려면 Comparable, Comparator를 사용한다. Comparable과 Comparator는 인터페이스다. 사용 방법은 2가지가 있다.

  • 정렬하려는 객체가 Comparable또는 Comparator를 구현하게 한다
  • Arrays.sort()나 Collections.sort()의 두번째 인자로 Comparator의 구현체를 전달한다

하나씩 알아보자.

Comparable, Comparator 구현

Comparable

Comparable을 구현할 경우 CompareTo(Type o)를 구현해야 한다.

class Player implements Comparable<Player> {
    private int age;
    private int power;

    public Player(int age, int power) {
        this.age = age;
        this.power = power;
    }

    @Override
    public int compareTo(Player o) {
        return this.age-o.age;
    }
}

위와 같이 Comparable을 구현하고, compareTo를 오버라이딩한다. compareTo는 자기 자신과 대상 객체를 비교한다.

정렬할 때 compareTo의 반환값이 음수면 두 원소의 자리를 바꾸고, 양수면 바꾸지 않는다.

즉 위 예시의 경우 Player의 age에 따라 오름차순 정렬하게 된다. 

    @Override
    public int compareTo(Player o) {
        return o.age-this.age;
    }

위와 같이 작성하면 내림차순 정렬한다. 

Comparator

Comparator를 구현할 경우 compare를 오버라이딩한다. compare는 두 매개변수 객체를 비교한다.

class Player implements Comparator<Player> {
    private int age;
    private int power;

    public Player(int age, int power) {
        this.age = age;
        this.power = power;
    }

    @Override
    public int compare(Player o1, Player o2) {
        return o1.age-o2.age;
    }
}

 

위와 같이 구현하고 compare를 오버라이딩하면 된다. Comparable의 compareTo와 다른점은 매개변수가 2개고 그 2개를 비교한다는 것이다. 오름차순, 내림차순 정렬 기준은 Comparable과 같다.

Comparator의 경우 Comparable과 비교되는 단점이 있다. 

Comparable을 구현한 객체를 비교하는 상황을 보자.

        Player p1 = new Player(2,2);
        Player p2 = new Player(3,3);
        p1.compareTo(p2);

이렇게 비교하려는 두 객체만 있으면 비교할 수 있다.

        Player comparator = new Player(1,1);
        Player p1 = new Player(2,2);
        Player p2 = new Player(3,3);
        comparator.compare(p1,p2);

반면 Comparator를 구현할 경우, 비교를 위한 객체를 생성해야 한다. compare 메서드는 인자로 들어온 두 객체를 비교하는 방식이기 때문이다. 이러한 방식은 통일성도 떨어지고, 비교를 위해 생성한 객체의 필드는 사용하지 않는데도 메모리를 차지한다는 단점이 있다.

익명클래스

이 단점을 해결하기 위해 익명클래스를 활용할 수 있다. 익명클래스를 활용해 클래스 상속, 인터페이스 구현을 간편하게 해서 사용할 수 있다. 

class Player{
    public int age;
    public int power;

    public Player(int age, int power) {
        this.age = age;
        this.power = power;
    }
}

public class Main {
    public static void main(String[] args) {
        Comparator<Player> comparator = new Comparator<Player>() {
            @Override
            public int compare(Player o1, Player o2) {
                return o1.age-o2.age;
            }
        };
        Player p1 = new Player(1,1);
        Player p2 = new Player(2,2);
        System.out.println(comparator.compare(p1,p2));
    }
}

comparator가 Comparator<Player>를 구현한 익명 클래스이다. 인터페이스의 추상 메소드를 구현부에서 구현하고 있다.

이 방식을 사용할 경우 Player 객체에서는 Comprator를 구현하지 않아도 된다. 그리고 비교만을 위한 익명 클래스를 사용하므로 통일성이 있다.

정리

원시타입이나 Integer같은 Wrapper타입은 배열은 Arrays.sort(), 컬렉션은 Collections.sort()로 정렬할 수 있다. 

다른 객체를 Comparable 또는 Comparator를 사용해서 정렬을 하는 방법은 2가지가 있다.

Comparable 또는 Comparator 구현 

정렬하려는 객체가 두 인터페이스 중 하나를 구현하게 한다.

배열인 경우 Arrays.sort(배열), 리스트인 경우 Collections.sort(리스트)와 같이 정렬한다.

sort의 두번째 인자로 Comparator 구현체 전달 

        Comparator<Player> comparator = new Comparator<Player>() {
            @Override
            public int compare(Player o1, Player o2) {
                return o1.age - o2.age;
            }
        };

        Player p1 = new Player(1, 1);
        Player p2 = new Player(2, 2);

        List<Player> list = new ArrayList<>(List.of(p2, p1));

        Collections.sort(list, comparator);

정렬하려는 객체가 Comparable이나 Comparator를 구현할 필요 없다.

익명 클래스로 Comparator를 구현하게 하고 Arrays.sort나 Collections.sort의 두번째 인자로 전달한다.

Collections.sort(list,Collections.reverseOrder()) 역시 이 방법을 사용한 것이다. 

오름차순, 내림차순 기준 

compareTo나 compare의 반환값이 음수면 두 원소의 위치를 바꾸고, 양수면 바꾸지 않는다.

        Comparator<Player> comparator = new Comparator<Player>() {
            @Override
            public int compare(Player o1, Player o2) {
                return o1.age - o2.age;
            }
        };

즉 이게 오름차순

        Comparator<Player> comparator = new Comparator<Player>() {
            @Override
            public int compare(Player o1, Player o2) {
                return o2.age-o1.age;
            }
        };

이게 내림차순이다. 

'Java' 카테고리의 다른 글

Java에서의 예외처리  (0) 2023.12.15
StringBuilder, StringJoiner, String.format  (1) 2023.10.29