정보란 무엇인가?
정보는 데이터를 의미있게 가공한것을 말한다. 라고 들었다. 틀려도 난몰라

어느정도 프로그래밍을 하다보면 어떤 데이터를 처리하게 되는데 이때 자주 사용되는것이 해시나 정렬이다.
특히 정렬은 동내북처럼 쓰인다..

과장되게 말한다면 동일한 형식의 다량의 데이터가 들어오면 일단 정렬부터 한다.
최대값과 최소값을 찾아라! 라고 하면 정렬해서 첫값과 끝값을 보여준다.

위와 같은 형태로 정렬은 쓰인다.(뭔가 아닌거 같지만 넘어가자)

그렇다면 정렬을 하려면 어떻게 해야할까?
일단 순서를 매길수 있어야한다. 다시말해서 비교가 가능해야 한다는것이다.

그렇다면 비교가 가능한 것들은 어떤것이 있을까?
일단 byte,short,int,long,float,double,char 의 기본형 변수는 정렬이 가능하다.
또 String 도 정렬이 가능하다.

왜 가능할까. 일단 기본형 변수는 원래 값이니까 비교가 된다. 따지지 말자
String 은 어떻게 비교를 할수 있는것인가? String도 값이니까 비교할수 있다고?
if("a">"b") 라는 조건문을 만들어 보라. 안된다.



그렇다면 도대체 어떻게 비교를 하고 정렬을 하는가? 하는 문제가 생긴다.

위에서 말했듯 뭔가 정렬을 하려면 비교가 가능해야되는데 어떻게 비교를 할것이냐 라는것은 아무도 모른다.
따라서 프로그래머가 만들어 주어야 하는데 이것을 Java의 규칙으로 표현하는것이 Comparable 인터페이스이다.

class Data implements Comparable<Data>{
	@Override
	public int compareTo(Data o) {
		// TODO Auto-generated method stub
		return 0;
	}
}
이것이 Comparable 인터페이스의 기본적인 구현 방법이다.
implements Comparable<클레스명> 이다.
제네릭에 들어가는 클레스명은 반드시 확장한 클레스와 같아야 하는건 아니지만 동일타입이외의 것이 들어가는 경우는 아직 보지 못했고 또 보게될일은 없을것 같다.

이렇게 Comparable 인터페이스를 확장하고 compareTo 메소드를 오버라이드 했는데 내용물을 어떻게 체울것인가? 하는 문제가 있다.

가장 기본적인 구현은 아래와 같다.
  • this 가 other 보다 작으면 음수
  • this 가 other 와 같다면 0
  • this 가 other 보다 크면 양수

이상이 가장 기본이 되는 룰이다.
첨가 하자면  A.compareTo(B) 에서 A 가 this 이고 B 가 other이다.
compareTo 를 만들때마다 했갈리는 부분이니 구현할때 주의하자.

compareTo 도 equals처럼 따라주어야 하는 규칙이 몇가지 있다.

  • 모든 x,y 에 대하여 ∑(x.compareTo(y) == -∑(y.compareTo(x)) 가 되어야한다. (예외 상황은 제외한다.)
  • x.compareTo(y)>0 이고 y.compareTo(z)>0 이면 x.compareTo(z) > 0 이어야한다. (이행성)
  • x.compareTo(y)==0 이라면 모든 z에 대해서 ∑(x.compareTo(z) == ∑(y.compareTo(z)) 이어야한다.
  • x.compareTo(y)==0 이면 x.equals(y)==true 이다.

∑ 가 무엇인지 잘 모르겠다면 고등학교 수학책을 다시 한번 찾아보기를 권한다.

위의 규칙들이 수학기호도 들어가고 뭔가 알쏭달쏭해 보인다고 걱정하지 말자.
일반적으로 저 위에있는 크다 작다만 잘 구현해도 아래에 있는 규칙들은 잘 지켜진다.

네번째 x.compareTo(y)==0 이라고 항상 x.equals(y)==true 이다. 라는 조항은 반드시 지켜질 필요는 없다.
하지만 지켜지지 않았다면 JavaDoc에 equals 메소드와 다른 방식으로 compareTo를 구현했다고 표시를 해두어야한다.

예를들어 Set 을 구현할때 TreeSet 와 HashSet 에서 equals 와 compareTo 의 동등 비교를 다르게 만들었다면 약간 다른 결과를 만들어 낸다. BigDecimal 이라는 클레스에서 1.0 이라는 값으로 만든 객체와 1.00 의 값으로 만든 객체가 있다면
1.0 과 1.00 은 일단 equals 로 비교하면 다르다 라는 결과를 냅니다.
뭐 그렇다는데 따지지 맙시다.
하지만 compareTo 로 비교를 하면 0을 돌려줘서 같다는 결과가 나옵니다.
따라서 이놈들을 TreeSet에 넣으면 한놈만 들어가지만 HashSet에 집어넣으면 두놈이 들어갑니다.
요런 차이점이 있으니 표시정도는 해주어야 합니다.

class Data implements Comparable<Data>{
	int time;
	int score;
	@Override
	public int compareTo(Data o) {
		// TODO Auto-generated method stub
		int result=time-o.time;
		if(result!=0)
			return result;
		result=o.score-score;
		return result;
	}
}

위의 Data 는 어떤 게임의 점수를 기록하는데 걸린 시간(time) 가 적으면 앞쪽으로. time이 같다면 score가 높은사람이 앞쪽으로 가는 랭킹을 만든다고 해봅시다.
위의 compareTo 처럼 구현을 하면 가장 쉽게 구현할수 있는데 약간의 문제점이 있습니다.
만약 time-o.time 의 값이 Integer.MAX_VALUE 보다 크게 된다면 오버플로우로 인한 오류를 발생하게 됩니다.
따라서 왠만하면 빼기를 통해서 값을 비교 하기 보다는 그냥 조건문을 가지고 처리하는편이 나을수도 있습니다.


if (score > o.score)
	return 1;
else if (score < o.score)
	return -1;
else
	return 0;

의 형식으로 말이죠. 누가보면 저런 비효율적인 코드는 너무 느려요! 라고 말할지도 모르겠으나. 
전 이렇게 말하고 싶습니다. "당신의 컴퓨터는 충분히 빠릅니다"

그리고 double 같은경우에는
Double 클레스의 compare 라는 static 메소드를 사용해 줍시다. 이게 가장 정확하고 빠를겁니다.
그리고 compareTo 가 구현된 클레스라면 그것을 바로 쓰도록 하고 말이죠

자 이렇게 구현을 다 했으면 쓰는 방법을 알아야겠죠?

배열의 경우에는 Arrays.sort 가 있고 콜랙션 즉 List의 경우에는 Collections.sort 가 있습니다.
둘다 Comparable 만 구현했다면 집어넣은 리스트나 배열을 완벽하게 정렬해서 돌려줄것입니다.

참고로 Arrays.sort 는 일반형 변수에서 QuickSort를 사용하고 클레스 객체에서는 Merge Sort를 사용합니다. Collections.sort는 Merge Sort 를 사용합니다.
Posted by 동적할당
: