[코드트리 조별과제] 6주차(정렬)

·

20 min read

[코드트리 조별과제] 6주차(정렬)

[6주차 소감]

  • 아쉽다. 그래도 완주했다!

  • 점점 배우는 개념이 많아질수록 한 문제당 소요되는 시간이 많았지만 역시 문제 풀리는 희열은 시간에 비례한다.

  • 남은 문제는 내돈내산해서 마무리 지을 예정!

[문제풀이]

[정렬] - 객체

  • class

두 학생의 국어, 영어, 수학 점수가 각각 (90, 80, 90), (80, 70, 60) 이라 했을 때 코드를 어떻게 작성해볼 수 있을까요?

  • 변수를 6개 만드는 방법
int kor1 = 90, eng1 = 80, math1 = 90;
int kor2 = 80, eng2 = 70, math2 = 60;

하지만 이런 경우 국어, 영어, 수학의 점수가 한 학생에 대한 정보를 나타내는 거라 보기 어렵다.

그래서 학생이라는 새로운 형태를 하나 정의하고, 그 안에 형태를 이루기 위한 요소로 국어, 영어, 수학 점수를 정의할 수 있다.

이를 가능하게 하는 것이 바로 클래스(class) 이다.

class Student {  // student class
    int kor, eng, math; // 국어, 영어, 수학 멤버 변수 

    public Student(int kor, int eng, int math){  // 생성자(constructor)
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }
};

Student 함수는 Student 클래스의 생성자(constructor) 이다.

생성자는 클래스와 같은 이름을 가지는 함수이고 클래스의 구성요소 중 하나이다.

new 로 객체 생성을 할 때 생성자가 호출되며 이때 멤버 변수를 초기화 하는 역할을 한다.

아래의 코드처럼 Student student1 = new Student(90, 80, 90); 인자로 값을 넘겨주면 해당되는 값을 갖는 하나의 학생 **객체(instance)**가 생성된다.

이 객체는 kor, eng, math 라는 이름의 멤버 변수를 갖으며, 이 값들을 조회하기 위해서는 객체이름.멤버변수이름 형태로 사용이 가능하다.

Student student1 = new Student(90, 80, 90);  // 객체 생성, 생성자 호출

System.out.println(student1.kor);  // 90
System.out.println(student1.eng);  // 80
System.out.println(student1.math); // 90
class Student {
    int k, e, m;

    public Student(int kor, int eng, int math){
        this.k = kor;
        this.e = eng;
        this.m = math;
    }
};

public class Main {
    public static void main(String[] args) {
        Student student1 = new Student(90, 80, 90);

        System.out.println(student1.k);  // 90
        System.out.println(student1.e);  // 80
        System.out.println(student1.m); // 90
    }
}
  • 007
import java.util.Scanner;

class Secret {
    String code, spot;
    int time;

    public Secret(String code, String spot, int time){
        this.code = code;
        this.spot = spot;
        this.time = time;
    }
};

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        String code = sc.next();
        String spot = sc.next();
        int time = sc.nextInt();

        Secret agent = new Secret(code, spot, time);

        System.out.println("secret code : " + agent.code);
        System.out.println("meeting point : " + agent.spot);
        System.out.println("time : " + agent.time);
    }
}
  • 객체 생성 및 값 변경
class Student {
    int kor, eng, math;

    // 기본생성자 없이 매개변수가 3개인 생성자
    public Student(int kor, int eng, int math){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }
};

public class Main {
    public static void main(String[] args) {
    // (에러)여기에서는 인자가 없는 생성자를 호출하며 객체생성 
        Student student1 = new Student(); 
    }
}
>>  error: constructor Student in class Student cannot be applied to given types;

C++, Python과 같은 언어에서는 각 인자의 초기값을 설정하는 것으로 해결이 가능하지만 Java에서는 함수 인자의 초기값을 설정하기가 어렵기에, 생성자(Constructor) 를 2개 만드는 것으로 해결이 가능하다. 기본 생성자를 만들어주거나 매개변수가 없는 생성자를 만들어주자.

이렇게 되면 객체 생성시 국어, 영어, 수학 점수가 넘어오는 경우에는 그대로 값을 넣어주게 되고, 그렇지 않은 경우에는 인자가 없는 경우에 해당하는 생성자를 호출하여 객체를 생성해주게 된다.

class Student {
    int kor, eng, math;
    // 매개변수가 없는 생성자
    // 인자가 없는 경우 이 생성자가 호출되고 각 멤버 변수가 0으로 초기화된다.
    public Student(){
        this.kor = 0;
        this.eng = 0;
        this.math = 0;
    }

    // 매개변수가 3개 있는 생성자
    // 넘어온 인자 값으로 멤버 변수를 초기화 한다.
    public Student(int kor, int eng, int math){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }
};

public class Main {
    public static void main(String[] args) {
        Student student1 = new Student(90, 80, 90); // 넘어간 값을 사용
        System.out.println(student1.kor);  // 90
        System.out.println(student1.eng);  // 80
        System.out.println(student1.math); // 90

        Student student2 = new Student();  // 값이 넘어가지 않는 생성자를 이용
        System.out.println(student2.kor);  // 0
        System.out.println(student2.eng);  // 0
        System.out.println(student2.math); // 0
    }
}
  • 멤버 변수 수정하기

변수에 들어있는 값을 수정할 때처럼, 객체이름.매개변수이름=바꿀 값 형태로 값을 변경해주면 된다.

class Student {
    int kor, eng, math;

    public Student(){
        this.kor = 0;
        this.eng = 0;
        this.math = 0;
    }

    public Student(int kor, int eng, int math){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }
};

public class Main {
    public static void main(String[] args) {
        Student student2 = new Student();  // 값이 넘어가지 않는 생성자를 이용
        System.out.println(student2.kor);  // 0
        System.out.println(student2.eng);  // 0
        System.out.println(student2.math); // 0

          // 이미 초기화 된 멤버 변수 수정하기
        student2.kor = 90;  
        student2.eng = 80;
        student2.math = 90;

        System.out.println(student2.kor);  // 90
        System.out.println(student2.eng);  // 80
        System.out.println(student2.math); // 90
    }
}
  • Next Level
import java.util.Scanner;

class UserInfo {
    String id;
    int level;

    public UserInfo() {
        this.id = "codetree";
        this.level = 10;
    }

    public UserInfo(String id, int level) {
        this.id = id;
        this.level = level;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        String userId = sc.next();
        int userLevel = sc.nextInt();

        UserInfo user1 = new UserInfo();
        UserInfo user2 = new UserInfo(userId, userLevel);

        System.out.println("user " + user1.id + " lv " + user1.level);
        System.out.println("user " + user2.id + " lv " + user2.level);

    }
}
  • 객체를 원소로 하는 리스트

국어, 영어, 수학 점수를 포함한 학생 5명의 정보를 쉽게 표현해보자.

class를 이용한 객체 선언과 동시에, 이 각각의 객체를 원소로 갖는 리스트를 이용.

class Student {
    int kor, eng, math;

    public Student(int kor, int eng, int math){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }
};

public class Main {
    public static void main(String[] args) {
        Student[] students = new Student[]{  // 객체를 원소로 갖는 리스트
            new Student(90, 80, 90), // 첫 번째 학생
            new Student(20, 80, 80), // 두 번째 학생
            new Student(90, 30, 60), // 세 번째 학생
            new Student(60, 10, 50), // 네 번째 학생
            new Student(80, 20, 10)  // 다섯 번째 학생
        };

        Student student3 = students[2]; // 세 번째 학생 정보
        System.out.println(student3.kor);  // 90
        System.out.println(student3.eng);  // 30
        System.out.println(student3.math); // 60
    }
}

반복문을 활용해서 5명 학생 정보를 정의하기.

class 정의시 각 점수의 기본값을 설정해주고, 다음과 같이 리스트에 각 객체를 넣어 정의해 줄 수 있다.

Student[] students = new Student[5];
        for(int i = 0; i < 5; i++)         // 5명의 학생 추가
            students[i] = new Student();   // 모든 객체의 멤버 변수가 0으로 초기화

5명의 학생 정보를 사용자의 입력을 받아 생성하기.

import java.util.Scanner;

class Student {
    int kor, eng, math;

    public Student() {
        this.kor = 0;
        this.eng = 0;
        this.math = 0;
    }

    public Student(int kor, int eng, int math){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }
};

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        Student[] students = new Student[5];
        for(int i = 0; i < 5; i++) {
            int kor = sc.nextInt();  // 사용자의 입력을 받은 후
            int eng = sc.nextInt();
            int math = sc.nextInt();
            students[i] = new Student(kor, eng, math); // 입력된 정보를 인자로 넘긴다.
        }

        Student student3 = students[2];    // 세 번째 학생 정보
        System.out.print("student3: ");
        System.out.print(student3.kor + " ");
        System.out.print(student3.eng + " ");
        System.out.print(student3.math + " ");
    }
}

>> 90 80 90
   20 80 80
   90 30 60
   60 10 50
   80 20 10

student3: 90 30 60
  • 코드네임
import java.util.Scanner;

class AgentInfo {
    String codeName;
    int score;

    public AgentInfo(String codeName, int score) {
        this.codeName = codeName;
        this.score = score;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        AgentInfo [] agents = new AgentInfo[5];

        for (int i = 0; i < 5; i++) {
            String inputName = sc.next();  // 사용자의 입력을 받은 후
            int inputScore = sc.nextInt();
            agents[i] = new AgentInfo(inputName, inputScore); // 객체 생성
        }

        int minIdx = 0;
        for (int i = 1; i < 5; i++) {
           if (agents[minIdx].score > agents[i].score) {  // 최솟값을 가진 인덱스
                minIdx = i;
           } 
        }

        System.out.print(agents[minIdx].codeName + " " + agents[minIdx].score);
    }
}
  • 폭탄 해체
import java.util.Scanner;

class Bomb {
    String code;
    String color;
    int time;

    public Bomb(String code, String color, int time) {
        this.code = code;
        this.color = color;
        this.time = time;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String inputCode = sc.next();
        String inputColor = sc.next();
        int inputTime = sc.nextInt();

        Bomb boom = new Bomb(inputCode, inputColor, inputTime);
        System.out.println("code : " + boom.code);
        System.out.println("color : " + boom.color);
        System.out.println("second : " + boom.time);

    }
}
  • 상품 코드
import java.util.Scanner;

class Goods{
    String product;
    int code;

     public Goods(String product, int code) {
        this.product = product;
        this.code = code;
    }
}

public class Main {
    public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);

        String productName = sc.next();
        int productCode = sc.nextInt();

        Goods go1 = new Goods("codetree", 50);
        Goods go2 = new Goods(productName, productCode);

        System.out.printf("product %d is %s\\n", go1.code, go1.product);
        System.out.printf("product %d is %s\\n", go2.code, go2.product);
    }
}
  • 사는 지역
import java.util.Scanner;

class Person {
    String name;
    String streetNum; 
    String area;

    public Person(String name, String streetNum, String area) {
        this.name = name;
        this.streetNum = streetNum;
        this.area = area;
    }
}

public class Main {
    public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);
       int n = sc.nextInt();
       Person [] people = new Person[n];

       for (int i = 0; i < n; i++) {
        String userName = sc.next();
        String userNum = sc.next();
        String userArea = sc.next();

        people[i] = new Person(userName, userNum, userArea);
       }

        int idx = 0;
        for (int i = 1; i < n; i++) {
            if (people[idx].name.compareTo(people[i].name) < 0) {  // 문자열 비교
                idx = i;
            }
        }
        System.out.println("name " + people[idx].name);
        System.out.println("addr " + people[idx].streetNum);
        System.out.println("city " + people[idx].area);  
    }
}

[해설]

String s1 = "abc";
String s2 = "def";
System.out.println(s1.compareTo(s2));  // -3 s2가 뒤에 
System.out.println(s2.compareTo(s1));  // 3 s1이 더 앞에
System.out.println(s1.compareTo(s1));  // 0 같아서
  • 비오는 날
import java.util.*;

class Weather {
    String date;
    String day;
    String info;

    public Weather(String date, String day, String info) {
        this.date = date;
        this.day = day;
        this.info = info;
    }
}

public class Main {
    public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);
       int n = sc.nextInt();

       Weather [] data = new Weather[n];

       for (int i = 0; i < n; i++) {
        String date = sc.next();
        String day = sc.next();
        String info = sc.next();

        data[i] = new Weather(date, day, info);
       }

       Weather [] rainData = new Weather[n];

       int cnt = 0;
       for (int i = 0; i < n; i++) {
        if (data[i].info.equals("Rain")) {
            rainData[cnt++] = data[i];
        }
       }

      int idx = 0;
       for (int i = 1; i < cnt; i++) {
        if (rainData[idx].date.compareTo(rainData[i].date)>0) {
            idx = i;
        }
       }

       System.out.printf("%s %s %s", rainData[idx].date, rainData[idx].day, rainData[idx].info);
    }
}

[해설]

나는 날짜 형식이 "YYYY-MM-DD" String 형식이었고 compareTo 메소드를 사용으로 비교함.


public class Main {
    public static Forecast ans = new Forecast("9999-99-99", "", "");

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 변수 선언 및 입력
        int n = sc.nextInt();

        for(int i = 1; i <= n; i++) {
            String date = sc.next();
            String day = sc.next();
            String weather = sc.next();

            // Forecast 객체를 만들어 줍니다.
            Forecast f = new Forecast(date, day, weather);
            if(weather.equals("Rain")) {  // 비오는 날씨를 먼저 체크 한 후에
                // 비가 오는 경우 가장 최근인지 확인하고,
                // 가장 최근일 경우 정답을 업데이트합니다.
                if(ans.date.compareTo(f.date) > 0)
                    ans = f;  // 업데이트
            }
        }

        // 결과를 출력합니다.
        System.out.print(ans.date + " " + ans.day + " " + ans.weather);
    }
}
  • 객체 정렬

국어 점수를 기준으로 오름차순 정렬하는 코드를 작성해보자.

Java에서는 custom comparator를 만들어야 한다.. 이 함수는 반환 타입이 꼭 int 이어야 하며, 해당하는 class를 type으로 하는 1개의 인자를 갖고 있어야만 한다.

현재 객체(this)에 들어있는 값과 함수로 넘어온 객체 값을 비교했을 때, 오름차순 정렬을 위해서는 다음 조건 3개를 만족시키면 된다..

  1. 현재 객체가 정렬 기준 더 뒤에 나와야 한다면 0보다 큰 값을 반환해야 합니다.

  2. 현재 객체가 정렬 기준 더 앞에 나와야 한다면 0보다 작은 값을 반환해야 합니다.

  3. 현재 객체가 정렬 기준 우선순위가 함수로 넘어온 객체와 동일하다면, 값 0을 반환해야 합니다.

그 예시는 다음과 같다..

class Student implements Comparable<Student> { // 가장 일반적인 방법
    int kor, eng, math;

    public Student(int kor, int eng, int math){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }

    @Override
    public int compareTo(Student student) { // 국어 점수 기준 오름차순 정렬
        if(this.kor > student.kor)
            return 1;
        else if(this.kor < student.kor)
            return -1;
        else
            return 0;
    }
};

위 코드는 국어 점수를 기준으로 오름차순 정렬을 진행하기 위한 코드.

따라서 **현재 객체(this)**의 국어 점수가 더 뒤에 나와야 하는 경우인 this.kor > student.kor에 대해서는 0보다 큰 값인 1을 반환해주고, 반대의 경우에는 -1을 반환해주고, 두 값이 동일한 경우에는 0을 반환해주면 된다..

이 함수는 아래와 같이 더 간단하게 작성이 가능하다.

@Override
public int compareTo(Student student) { // 국어 점수 기준 오름차순 정렬
    return this.kor - student.kor;
}

이제 Arrays.sort를 이용하면 국어 점수 기준 오름차순 정렬이 진행됨을 확인할 수 있다.

import java.util.Arrays;

class Student implements Comparable<Student> {
    int kor, eng, math;

    public Student(int kor, int eng, int math){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }

    @Override
    public int compareTo(Student student) { // 국어 점수 기준 오름차순 정렬
        return this.kor - student.kor;
    }
};

public class Main {
    public static void main(String[] args) {
        Student[] students = new Student[] {
            new Student(90, 80, 90), // 첫 번째 학생
            new Student(20, 80, 80), // 두 번째 학생
            new Student(90, 30, 60), // 세 번째 학생
            new Student(60, 10, 50), // 네 번째 학생
            new Student(80, 20, 10)  // 다섯 번째 학생
        };

        Arrays.sort(students); // 국어 점수 기준 오름차순 정렬

        for(int i = 0; i < 5; i++)
            System.out.println(students[i].kor + " " + students[i].eng + " " + students[i].math);
    }
}

>> 20 80 80
   60 10 50
   80 20 10
   90 80 90
   90 30 60

국어 점수를 기준으로 내림차순 정렬을 해볼 수는 없을까요? 이 경우에는 compareTo 함수에서 student.kor - this.kor를 반환하는 식으로 수정하면 된다.

import java.util.Arrays;

class Student implements Comparable<Student> {
    int kor, eng, math;

    public Student(int kor, int eng, int math){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }

    @Override
    public int compareTo(Student student) { // 국어 점수 기준 내림차순 정렬
        return student.kor - this.kor;
    }
};

public class Main {
    public static void main(String[] args) {
        Student[] students = new Student[] {
            new Student(90, 80, 90), // 첫 번째 학생
            new Student(20, 80, 80), // 두 번째 학생
            new Student(90, 30, 60), // 세 번째 학생
            new Student(60, 10, 50), // 네 번째 학생
            new Student(80, 20, 10)  // 다섯 번째 학생
        };

        Arrays.sort(students); // 국어 점수 기준 내림차순 정렬

        for(int i = 0; i < 5; i++)
            System.out.println(students[i].kor + " " + students[i].eng + " " + students[i].math);
    }
}

>> 90 80 90
   90 30 60
   80 20 10
   60 10 50
   20 80 80
@Override
public int compareTo(Student student) { // 국어 점수 기준 오름차순 정렬
    return this.kor - student.kor;
}

Java 8 부터 아래와 같은 방식도 가능.

Arrays.sort(students, (a, b) -> a.kor - b.kor); // 국어 점수 기준 오름차순 정렬
  • Java에서 만약 2번에 걸쳐 각각 다른 기준으로 정렬하고 싶은 경우

compare 함수는 compareTo함수와는 다르게 인자를 2개를 받아 기준을 설정해줘야 하며, 순서대로 a, b라 했을 때 a가 compareTo에서의 this라고 생각해주시면 된다.

// custom comparator를 활용한 정렬
Arrays.sort(students, new Comparator<Student>() {
    @Override
    public int compare(Student a, Student b) { // 키를 기준 오름차순 정렬합니다.
        return a.height - b.height;
    }
});

키를 기준으로 오름차순 정렬하는 전체 코드.

import java.util.Scanner;
import java.util.Arrays;
import java.util.Comparator;

// 학생들의 정보를 나타내는 클래스 선언
class Student {
    String name;
    int height, weight;

    public Student(String name, int height, int weight){
        this.name = name;
        this.height = height;
        this.weight = weight;
    }
};

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 변수 선언 및 입력:
        int n = sc.nextInt();
        Student[] students = new Student[n];
        for(int i = 0; i < n; i++) {
            String name = sc.next();
            int height = sc.nextInt();
            int weight = sc.nextInt();

            // Student 객체를 생성해 리스트에 추가합니다.
            students[i] = new Student(name, height, weight);
        }

        // custom comparator를 활용한 정렬
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student a, Student b) { // 키를 기준 오름차순 정렬합니다.
                return a.height - b.height;
            }
        });

        // 결과를 출력합니다.
        for (int i = 0; i < n; i++){
            System.out.print(students[i].name + " ");
            System.out.print(students[i].height + " ");
            System.out.println(students[i].weight);
        }
    }
}

[추가 해설]

  1. Arrays.sort() 호출 시 내부 동작:

    • Arrays.sort(students)는 정렬 알고리즘을 사용하여 배열의 요소들을 반복적으로 비교합니다.

    • 이 과정에서 정렬 알고리즘은 배열의 요소들(여기서는 Student 객체들) 중 두 개를 선택하여 서로 비교합니다. 이를 위해 compareTo() 메서드를 호출합니다.

  2. compareTo() 메서드에서 thisstudent:

    • this: 현재 메서드를 호출한 객체를 의미합니다. 즉, compareTo()가 호출된 객체입니다.

    • student: compareTo(Student student) 메서드의 매개변수로 전달된 비교 대상 객체입니다.

  • 키를 기준으로 오름차순 정렬
import java.util.*;

class Human implements Comparable<Human>{
    String name;
    int height;
    int weight;

    public Human(String name, int height, int weight) {
        this.name = name;
        this.height = height;
        this.weight = weight;
    }

    @Override
    public int compareTo(Human human) {
        return this.height - human.height;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        Human [] people = new Human[n];

        for (int i = 0; i < n; i++) {
            String name = sc.next();
            int height = sc.nextInt();
            int weight = sc.nextInt();

            people[i] = new Human(name, height, weight);
        }

        Arrays.sort(people);

        for (int i = 0; i < n; i++) {
            System.out.printf("%s %d %d\\n", people[i].name, people[i].height, people[i].weight);
        }
    }
}
  • 여러 우선순위를 갖는 객체 정렬

국어 점수를 기준으로 오름차순 정렬하되, 만약 국어 점수가 같다면 영어 점수를 기준으로 오름차순으로 정렬하는 코드를 작성해 보자.

@Override
public int compareTo(Student student) {
    if(this.kor == student.kor)     // 국어 점수가 일치한다면
        return this.eng - student.eng;  // 영어 점수를 기준으로 오름차순 정렬합니다.
    return this.kor - student.kor;     // 국어 점수가 다르다면, 오름차순 정렬합니다.
}

만약 국어 점수를 오름차순으로 정렬하되, 국어 점수가 동일한 경우에는 영어 점수를 내림 차순으로 정렬하고 싶은 경우라면, 영어 점수만 내림차순이 되도록 compareTo 함수를 다음과 같이 작성해주면 된다.

@Override
public int compareTo(Student student) {
    if(this.kor == student.kor)     // 국어 점수가 일치한다면
        return student.eng - this.eng;  // 영어 점수를 기준으로 내림차순 정렬합니다.
    return this.kor - student.kor;     // 국어 점수가 다르다면, 오름차순 정렬합니다.
}
  • 국영수 순이지
import java.util.*;

class Student implements Comparable<Student> {
    String name;
    int kor;
    int eng;
    int math;

    public Student(String name, int kor, int eng, int math) {
        this.name = name;
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }

    @Override
    public int compareTo(Student student) {
        if (this.kor == student.kor){
            if (this.eng == student.eng) {
                return student.math - this.math;
            }
            return student.eng - this.eng;
        }    
        return student.kor - this.kor;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        Student [] st = new Student[n];

        for (int i = 0; i < n; i ++) {
            String name = sc.next();
            int kor = sc.nextInt();
            int eng = sc.nextInt();
            int math = sc.nextInt();

            st[i] = new Student(name, kor, eng, math);
        }

        Arrays.sort(st);

        for (int i = 0; i < n; i++) {
            System.out.printf("%s %d %d %d\\n", st[i].name, st[i].kor, st[i].eng, st[i].math);
        }
    }
}

[해설]

@Override
    public int compareTo(Student student) {
        // 국어 점수가 높으면 정렬 했을 때 앞에 와야 합니다.
        if(this.korean != student.korean)
            return student.korean - this.korean;
        // 영어 점수가 높으면 정렬 했을 때 앞에 와야 합니다.
        if(this.english != student.english)
            return student.english - this.english;
        // 수학 점수가 높으면 정렬 했을 때 앞에 와야 합니다.
        return student.math - this.math;
    }
  • 정렬 기준이 복잡한 객체 정렬

compareTo 함수의 오름차순 기준에 점수의 총 합을 적어주면 된다.

import java.util.Arrays;

class Student implements Comparable<Student> {
    int kor, eng, math;

    public Student(int kor, int eng, int math){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }

    @Override
    public int compareTo(Student student) {  // 총 점수 기준 오름차순 정렬
        return (this.kor + this.eng + this.math) - (student.kor + student.eng + student.math);
    }
};

public class Main {
    public static void main(String[] args) {
        Student[] students = new Student[] {
            new Student(90, 80, 90), // 첫 번째 학생
            new Student(20, 80, 80), // 두 번째 학생
            new Student(90, 30, 60), // 세 번째 학생
            new Student(60, 10, 50), // 네 번째 학생
            new Student(80, 20, 10)  // 다섯 번째 학생
        };

        Arrays.sort(students); // 총 점수 기준 오름차순 정렬

        for(int i = 0; i < 5; i++)
            System.out.println(students[i].kor + " " + students[i].eng + " " + students[i].math);
    }
}

>> 80 20 10
   60 10 50
   20 80 80
   90 30 60
   90 80 90
  • 총점 비교
import java.util.*;

class Student implements Comparable<Student> {
    String name;
    int sub1;
    int sub2;
    int sub3;

    public Student(String name, int sub1, int sub2, int sub3) {
        this.name = name;
        this.sub1 = sub1;
        this.sub2 = sub2;
        this.sub3 = sub3;
    }

    @Override
    public int compareTo(Student student) {
        return (this.sub1 + this.sub2 + this.sub3) - (student.sub1 + student.sub2 + student.sub3);
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        Student [] st = new Student[n];

        for (int i = 0; i < n; i++) {
            String name = sc.next();
            int sub1 = sc.nextInt();
            int sub2 = sc.nextInt();
            int sub3 = sc.nextInt();

            st[i] = new Student(name, sub1, sub2, sub3);
        }

        Arrays.sort(st);

        for (int i = 0; i < n; i++) {
            System.out.printf("%s %d %d %d\\n", st[i].name, st[i].sub1, st[i].sub2, st[i].sub3);
        }
    }
}
  • 객체 정렬시 index 멤버 변수의 필요성

국어 점수에 따라 정렬이 되면서 각 학생의 번호도 같이 움직여야 정렬 이후에 각 등수에 해당하는 학생의 번호를 출력할 수 있기 때문에, 객체에 학생 번호에 해당하는 멤버 변수를 꼭 추가해줘야 한다.

import java.util.Arrays;

class Student implements Comparable<Student> {
    int kor, eng, math, number;

    public Student(int kor, int eng, int math, int number){
        this.kor = kor;
        this.eng = eng;
        this.math = math;
        this.number = number;  // 학생 번호
    }

    @Override
    public int compareTo(Student student) { // 국어 점수 기준 내림차순
        return student.kor - this.kor;
    }
};

public class Main {
    public static void main(String[] args) {
        Student[] students = new Student[] {
            new Student(90, 80, 90, 1), // 첫 번째 학생
            new Student(20, 80, 80, 2), // 두 번째 학생
            new Student(90, 30, 60, 3), // 세 번째 학생
            new Student(60, 10, 50, 4), // 네 번째 학생
            new Student(80, 20, 10, 5)  // 다섯 번째 학생
        };

        Arrays.sort(students); // 국어 점수 기준 내림차순 정렬

        // 정렬 이후 등수별 학생 번호 출력
        for(int i = 0; i < 5; i++)
            System.out.println((i + 1) + "등: " + students[i].number + "번");
    }
}

>> 1등: 12등: 33등: 54등: 45등: 2

Side Note

정렬 이후 각 번호가 어디로 갔는지를 출력하는 코드는 어떻게 작성해 볼 수 있을까?

예를 들어 위의 예에서 처럼 등수 별 각 학생의 번호가 1 3 5 4 2 라면

1번 -> 12번 -> 53번 -> 24번 -> 45번 -> 3

어느 학생이 어떤 등수를 받았는지를 나타내는 배열을 새로 하나 만들어 이용해 보자.

등수 별 학생 번호를 순회하면서, 각 학생 번호의 index에 해당 rank를 넣어주는 식으로 작성한다.

int[] num_to_rank = new int[6]; // 5명이므로
int[] nums = new int[]{1, 3, 5, 4, 2};

for(int i = 0; i < 5; i++)
    num_to_rank[nums[i]] = (i + 1);

for(int i = 1; i <= 5; i++)
    System.out.print(num_to_rank[i] + " "); // 1 5 2 4 3
  • 줄 세우기
import java.util.*;

class Student implements Comparable<Student> {
    int height;
    int weight;
    int num;

    public Student(int height, int weight, int num) {
        this.height = height;
        this.weight = weight;
        this.num = num;
    }

    @Override
    public int compareTo(Student student) {
        if (this.height != student.height){
            return student.height - this.height;
        }
        if (this.weight != student.weight) {
            return student.weight - this.weight;
        }
        return this.num - student.num;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        Student [] st = new Student[n];

        for (int i = 0; i < n; i++) {
            int height = sc.nextInt();
            int weight = sc.nextInt();
            int num = i+1;

            st[i] = new Student(height, weight, num);
        }

        Arrays.sort(st);

        for (int i = 0; i < n; i++) {
            System.out.printf("%d %d %d\\n", st[i].height, st[i].weight, st[i].num);
        }
    }
}
  • 개인 정보
import java.util.*;

class User implements Comparable<User>{
    String name;
    int height;
    double weight;

    public User(String name, int height, double weight) {
        this.name = name;
        this.height = height;
        this.weight = weight;
    }

    @Override
    public int compareTo(User user) {
        return this.name.compareTo(user.name);
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        User [] us = new User[5];

        for (int i = 0; i < 5; i++) {
            String name = sc.next();
            int height = sc.nextInt();
            double weight = sc.nextDouble();

            us[i] = new User(name, height, weight);
        }

        // 이름 오름차순 정렬
        Arrays.sort(us);
        System.out.println("name");
        for (int i = 0; i < 5; i++){
            System.out.printf("%s %d %.1f\\n", us[i].name, us[i].height, us[i].weight);
        }
        System.out.println();
        // 키 내림차순 정렬 
        Arrays.sort(us, (a, b) -> b.height - a.height); 

        System.out.println("height");
        for (int i = 0; i < 5; i++){
            System.out.printf("%s %d %.1f\\n", us[i].name, us[i].height, us[i].weight);
        }
    }
}

[해설]

해설에서는 Comparator<Student> 인터페이스를 구현한 익명 클래스가 사용되었다.

이 클래스는 compare 메소드를 오버라이드하여 Student 객체의 height 필드를 기준으로 내림차순 정렬하도록 정의하고 있다.

Arrays.sort(students, new Comparator<Student>() {  
            @Override
            public int compare(Student a, Student b) { // 이름 기준 오름차순 정렬합니다.
                return a.name.compareTo(b.name);
            }
        });

      Arrays.sort(students, new Comparator<Student>() {  
          @Override
          public int compare(Student a, Student b) { // 키 기준 내림차순 정렬합니다.
              return b.height - a.height;
          }
      });

키, 몸무게를 기준으로 정렬

import java.util.*;

class User implements Comparable<User> {
    String name;
    int height;
    int weight;

    public User(String name, int height, int weight) {
        this.name = name;
        this.height = height;
        this.weight = weight;
    }

    @Override
    public int compareTo(User user) {
        if (this.height != user.height) {
            return this.height - user.height;
        }
        return user.weight - this.weight;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        User [] us = new User[n];

        for (int i = 0; i < n; i++) {
            String name = sc.next();
            int height = sc.nextInt();
            int weight = sc.nextInt();

            us[i] = new User(name, height, weight);
        }

        Arrays.sort(us);

        for (int i = 0; i < n; i++) {
            System.out.printf("%s %d %d\n", us[i].name, us[i].height, us[i].weight);
        }
    }
}