본문 바로가기
Tech/Java

[Java] 컬렉션 프레임웍(Collections Framework) 연습문제

by 소라소라잉 2019. 8. 23.

* 이 포스팅의 연습문제는 남궁성 선생님의 자바의 정석에 수록된 문제이며 정답 및 해설은 본인의 의견입니다. 

* 연습문제 PDF파일은 아래 남궁성 선생님의 GitHub에서 다운 받으실 수 있습니다. 

https://github.com/castello/javajungsuk3

 

castello/javajungsuk3

soure codes and ppt files of javajungsuk 3rd edition - castello/javajungsuk3

github.com

 

<문제1>

[11-1] 다음은 정수집합 1,2,3,4와 3,4,5,6의 교집합, 차집합, 합집합을 구하는 코드이다. 

코드를 완성하여 실행결과와 같은 결과를 출력하시오.
[Hint] ArrayList클래스의 addAll(), removeAll(), retainAll()을 사용하라.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.util.*;
 
class Exercise11_1 {
    public static void main(String[] args) {
        ArrayList list1 = new ArrayList();
        ArrayList list2 = new ArrayList();
        ArrayList kyo = new ArrayList(); // 교집합
        ArrayList cha = new ArrayList(); // 차집합
        ArrayList hap = new ArrayList(); // 합집합
        list1.add(1);
        list1.add(2);
        list1.add(3);
        list1.add(4);
        list2.add(3);
        list2.add(4);
        list2.add(5);
        list2.add(6);
        /*
         * (1) 알맞은 코드를 넣어 완성하시오.
         */
        System.out.println("list1=" + list1);
        System.out.println("list2=" + list2);
        System.out.println("kyo=" + kyo);
        System.out.println("cha=" + cha);
        System.out.println("hap=" + hap);
    }
}
cs

[실행결과]

list1=[1, 2, 3, 4]
list2=[3, 4, 5, 6]
kyo=[3, 4]
cha=[1, 2]
hap=[1, 2, 3, 4, 5, 6]

 

<나의 풀이>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import java.util.ArrayList;
import java.util.HashSet;
 
public class Exercise11_1 {
    public static void main(String[] args) {
        ArrayList list1 = new ArrayList();
        ArrayList list2 = new ArrayList();
        ArrayList kyo = new ArrayList(); // 교집합
        ArrayList cha = new ArrayList(); // 차집합
        ArrayList hap = new ArrayList(); // 합집합
        list1.add(1);
        list1.add(2);
        list1.add(3);
        list1.add(4);
        list2.add(3);
        list2.add(4);
        list2.add(5);
        list2.add(6);
 
        // 교집합 방법1)
        for (int i = 0; i < list1.size(); i++) {
            if (list2.contains(list1.get(i))) {
                kyo.add(list1.get(i));
            }
        }
 
        // 교집합 방법2)
        ArrayList kyo2 = new ArrayList(list1);
        kyo2.retainAll(list2);
 
        // 차집합 방법1)
        for (int i = 0; i < list1.size(); i++) {
            if (!(list2.contains(list1.get(i))))
                cha.add(list1.get(i));
        }
 
        // 차집합 방법2)
        ArrayList cha2 = new ArrayList(list1);
        cha2.removeAll(list2);
 
        // 합집합 방법1)
        HashSet setHap = new HashSet(hap);
        setHap.addAll(list1);
        setHap.addAll(list2);
        hap = new ArrayList(setHap);
 
        // 합집합 방법2)
        ArrayList hap2 = new ArrayList(); 
        for (int i = 0; i < list1.size(); i++) {
            if (!(list2.contains(list1.get(i))))
                hap2.add(list1.get(i));
        }
        hap2.addAll(list2);
 
        System.out.println("list1=" + list1);
        System.out.println("list2=" + list2);
        System.out.println("kyo방법1=" + kyo);
        System.out.println("kyo방법2=" + kyo);
        System.out.println("cha방법1=" + cha);
        System.out.println("cha방법2=" + cha2);
        System.out.println("hap방법1=" + hap);
        System.out.println("hap방법2=" + hap2);
    }
}
cs

28라인과 38라인을 처음에는
ArrayList kyo2 = new ArrayList();

kyo2 = list1; 

위와 같은 식으로 구현했었다.

이렇게 하게 되면

1) ArrayList클래스의 인스턴스 kyo2가 메모리의 빈 공간에 생성된다.  (ArrayList kyo2 = new ArrayList();) 

2) 대입 연산자에 의해 list1의 주소값이 참조변수 kyo2에 저장된다.  (kyo2 = list1;)

결국 두 참조변수가 참조하는 ArrayList가 동일해 지기 때문에 둘중 하나만 변경해도 다른쪽도 같이 변경된다.(두 참조변수가 참조하는 인스턴스는 동일함.)

 

수정한 코드는 

ArrayList kyo2 = new ArrayList(list1);
kyo2.retainAll(list2);

이런식으로 하게 되면

ArrayList클래스의 인스턴스가 메모리의 빈 공간에 생성되고 그 내용은 list1의 값으로 초기화 하게 된다.(list1이 갖고있는 주소를 참조하여 그 인스턴스로 kyo2를 초기화)

 

그리고 나중엔 코드의 재사용성을 늘 고려하며 HashSet set = new HashSet(); 보다는

Set set = new HashSet(); 으로 해보는 것도 괜찮겠다. 

 

 

<문제2>

[11-2] 다음 코드의 실행결과를 적으시오.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Exercise11_2 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(3);
        list.add(6);
        list.add(2);
        list.add(2);
        list.add(2);
        list.add(7);
        HashSet set = new HashSet(list);
        TreeSet tset = new TreeSet(set);
        Stack stack = new Stack();
        stack.addAll(tset);
        while (!stack.empty())
            System.out.println(stack.pop());
    }
}
cs

<나의 풀이>

List인터페이스를 구현한 ArrayList클래스는 List인터페이스의 '중복허용,순서유지'의 특성을 갖는다.

따라서 ArrayList list는 입력받은 그대로 3-6-2-2-2-7이 저장되게 된다. 

이를 set인터페이스를 구현한 HashSet클래스로 변환해주면(컬렉션 클래스들은 서로 변환이 가능한 생성자를 가지고 있기 때문에 변환이 쉽다) set인터페이스의 특징(중복X,순서X)에 맞게 중복된 값이 삭제되고(3-6-2-7)

이를 다시 TreeSet으로 변환해주면 값을 입력받을때 자동으로 정렬해주는 TreeSet의 기능에 의해 2-3-6-7의 순서로 저장된다. 

TreeSet의 값을 stack에 저장하고 스택은 LIFO(Last In First Out)의 방법으로 요소들을 꺼내게(pop)된다.

따라서 결과는 7-6-3-2 

 

 

<문제3>

[11-5] 다음에 제시된 Student클래스가 Comparable인터페이스를 구현하도록 변경해서 이름(name)이 기본 정렬기준이 되도록 하시오.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Student {
    String name;
    int ban;
    int no;
    int kor, eng, math;
 
    Student(String name, int ban, int no, int kor, int eng, int math) {
        this.name = name;
        this.ban = ban;
        this.no = no;
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }
 
    int getTotal() {
        return kor + eng + math;
    }
 
    float getAverage() {
        return (int) ((getTotal() / 3f) * 10 + 0.5/ 10f;
    }
 
    public String toString() {
        return name + "," + ban + "," + no + "," + kor + "," + eng + "," + math + "," 
        + getTotal() + "," + getAverage();
    }
}
 
class Exercise11_5 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(new Student("홍길동"11100100100));
        list.add(new Student("남궁성"12907080));
        list.add(new Student("김자바"13808090));
        list.add(new Student("이자바"14709070));
        list.add(new Student("안자바"156010080));
        Collections.sort(list);
        Iterator it = list.iterator();
        while (it.hasNext())
            System.out.println(it.next());
    }
}
cs

[실행결과]

김자바,1,3,80,80,90,250,83.3
남궁성,1,2,90,70,80,240,80.0
안자바,1,5,60,100,80,240,80.0
이자바,1,4,70,90,70,230,76.7
홍길동,1,1,100,100,100,300,100.0

 

<나의 풀이>

Comparable과 Comparator를 먼저 간단히 정리해보면 둘다 '비교기준'이라고 표현할 수 있겠다.

- Comparable : 기본 정렬기준을 구현하는데 사용.

- Comparator : 기본 정렬기준 외에 다른 기준으로 정렬하고자 할 때 사용. 

간단히 말하자면 기본정렬(오름차순)이 필요할땐 Comparable, 그 외에 내림차순 등으로 정렬하고 싶으면 Comparator인터페이스의 내부 메서드를 오버라이딩 해주어 사용하면 된다. 

 

같은 타입의 인스턴스끼리 서로 비교할 수 있는 클래스들은(wrapper클래스,String,Data 등) 기본적으로 오름차순으로 정렬될 수 있도록 내부적으로 Comparable인터페이스를 구현하고 있다. 이 말은 Comparable인터페이스를 구현한 클래스는 정렬이 가능하다는 것을 의미한다.(Comparable말 그대로 '비교할 수 있는')

 

Integer같은 wrapper클래스는 기본적으로 Comparable이 구현되어있지만 위 문제의 Student같은 사용자정의타입의 클래스의 객체들을 정렬가능하도록 만드려면 Comparable을 우리가 직접 구현해 주어야 한다. 

1
2
3
4
5
6
7
8
9
10
    public int compareTo(Object o) {
        
        if (o instanceof Student) {
            Student tmp = (Student) o;
            return this.name.compareTo(tmp.name);
        }
 
        return -1;
 
    }
cs

 

Student 클래스에 Comparable인터페이스를 상속받고(class Student implements Comparable) 

위와 같이 compareTo(Object o)를 오버라이딩 해주었다. 

일단 인자값으로 들어오는 Object가 Student의 인스턴스인지 확인하고,( if(o instanceof Student)) true면 Object를 Studnet형으로 변환한다.( Student tmp = (Student) o; )  

그리고 비교대상인 tmp의 name과 name인스턴스 변수와의 비교값을 return하는데

여기서 사용된 comparTo()는 name의 타입이 String이기 때문에 String클래스에 정의되어있는 compareTo(오름차순)를 이용하는 것이다. 

 

<문제4>

[11-6] 다음의 코드는 성적평균의 범위별로 학생 수를 세기 위한 것이다. TreeSet이 학생들의 평균을 기준으로 정렬하도록 compare(Object o1, Object o2)와 평균점수의 범위를 주면 해당 범위에 속한 학생의 수를 반환하는 getGroupCount()를 완성하라.
[Hint] TreeSet의 subSet(Object from, Object to)를 사용하라.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import java.util.*;
 
class Student implements Comparable {
    String name;
    int ban;
    int no;
    int kor;
    int eng;
    int math;
 
    Student(String name, int ban, int no, int kor, int eng, int math) {
        this.name = name;
        this.ban = ban;
        this.no = no;
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }
 
    int getTotal() {
        return kor + eng + math;
    }
 
    float getAverage() {
        return (int) ((getTotal() / 3f) * 10 + 0.5/ 10f;
    }
 
    public String toString() {
        return name + "," + ban + "," + no + "," + kor + "," + eng + "," + math + "," 
        + getTotal() + "," + getAverage();
    }
 
    public int compareTo(Object o) {
        if (o instanceof Student) {
            Student tmp = (Student) o;
            return name.compareTo(tmp.name);
        } else {
            return -1;
        }
    }
// class Student
 
class Exercise11_6 {
    static int getGroupCount(TreeSet tset, int from, int to) {
        /*
         * (1) 알맞은 코드를 넣어 완성하시오.
         */
    }
 
    public static void main(String[] args) {
        TreeSet set = new TreeSet(new Comparator() {
            public int compare(Object o1, Object o2) {
                /*
                 * (2) 알맞은 코드를 넣어 완성하시오.
                 */
            }
        });
        set.add(new Student("홍길동"11100100100));
        set.add(new Student("남궁성"12907080));
        set.add(new Student("김자바"13808090));
        set.add(new Student("이자바"14709070));
        set.add(new Student("안자바"156010080));
        Iterator it = set.iterator();
        while (it.hasNext())
            System.out.println(it.next());
        System.out.println("[60~69] :" + getGroupCount(set, 6070));
        System.out.println("[70~79] :" + getGroupCount(set, 7080));
        System.out.println("[80~89] :" + getGroupCount(set, 8090));
        System.out.println("[90~100] :" + getGroupCount(set, 90101));
    }
}
cs

[실행결과]

이자바,1,4,70,90,70,230,76.7
남궁성,1,2,90,70,80,240,80.0
김자바,1,3,80,80,90,250,83.3
홍길동,1,1,100,100,100,300,100.0
[60~69]:0
[70~79]:1
[80~89]:2
[90~100]:1

 

<나의 풀이>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        TreeSet set = new TreeSet(new Comparator() {
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Student && o2 instanceof Student) {
                    Student s1 = (Student) o1;
                    Student s2 = (Student) o2;
                    Float s1Avr = s1.getAverage();
                    Float s2Avr = s2.getAverage();
                    if (s1Avr instanceof Comparable && s2Avr instanceof Comparable) {
                        Comparable c1 = (Comparable) s1Avr;
                        Comparable c2 = (Comparable) s2Avr;
                        return c1.compareTo(c2);
                    }
                }
                return -1;
            }
        });
cs

Float클래스 내부의 compareTo를 이용한 방법이다. 딱 봐도 지저분해 보이고 Float클래스 내부의 compareTo도 결국 return값으로 값 비교를 할거라는 아이디어로 코드를 간단히 해봤다. 

1
2
3
4
5
6
7
8
9
10
11
12
        TreeSet set = new TreeSet(new Comparator() {
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Student && o2 instanceof Student) {
                    Student s1 = (Student) o1;
                    Student s2 = (Student) o2;
 
                    return s1.getAverage()<s2.getAverage() ? -1 : 
                        (s1.getAverage()==s2.getAverage() ? 01);
                }
                return -1;
            }
        });
cs

return값으로 삼항연산자를 이용하여 s1의 average와 s2의 average를 비교했다. compareTo의 반환값은 Int이지만 실제로는 비교하는 두 객체가 같으면 0, 비교하는 값보다 작으면 음수, 크면 양수를 반환하도록 구현해야 한다. average는 float형 이기 때문에 int형으로 캐스팅 하게 되면 정확도가 떨어질 수 있다. 따라서 조건문을 이용함. 

1
2
3
4
5
6
7
8
    static int getGroupCount(TreeSet tset, int from, int to) {
 
        Student st = new Student(""00, from, from, from);
        Student st2 = new Student(""00, to, to, to);
 
        return tset.subSet(st, st2).size();
 
    }
cs

이건 도저히 어떻게 해야할까 감이 안잡혀서 해설을 보고 말았다.ㅜㅜ

처음 생각의 흐름은, tset의 Student요소들을 첫 index부터 마지막 index까지 average 인스턴스 변수를 from과 to로 비교하여 true면 getGroupCount내부에 정의한 count변수를 올려 마지막에 return하게끔 하려 했었다.

그러나 set은 index가 없고 (내가 모르는 것 일수 있겠으나)모든 요소들을 index형식으로 검색할 수 있는 방법이 없다!

 

Studnet st와 st2는 각 과목 점수를 모두 from과 to로 초기화 했다. st의 average는 결국 from이 될 것이고 st2는 to가 될 것이다.

subSet이라는 treeset의 메서드를 이용하면 범위검색(from~to~)이 가능한데, subSet을 호출하는건 tset이고 매개변수 tset에 들어가는 set의 정렬기준은 우리가 위에서 오버라이딩 했던 Compare의 기준에 따라(메서드 내부의 o1 instanceOf Student) set(=tset)의 'average'가 된다.

 

따라서 st1와 st2의 평균값 사이에 있는 요소들을 set형태로 return하고 그 size(갯수)를 최종적으로 return한다. 

 

 

<문제5>

[11-7] 다음에 제시된 BanNoAscending클래스를 완성하여 ArrayList에 담긴 Student인스턴스들이 반(ban)과 번호(no) 로 오름차순 정렬되게 하시오.(반이 같은 경우 번호를 비교해서 정렬한다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import java.util.*;
 
class Student {
    String name;
    int ban;
    int no;
    int kor;
    int eng;
    int math;
 
    Student(String name, int ban, int no, int kor, int eng, int math) {
        this.name = name;
        this.ban = ban;
        this.no = no;
        this.kor = kor;
        this.eng = eng;
        this.math = math;
    }
 
    int getTotal() {
        return kor + eng + math;
    }
 
    float getAverage() {
        return (int) ((getTotal() / 3f) * 10 + 0.5/ 10f;
    }
 
    public String toString() {
        return name + "," + ban + "," + no + "," + kor + "," + eng + "," 
        + math + "," + getTotal() + "," + getAverage();
    }
}// class Student
 
class BanNoAscending implements Comparator {
    public int compare(Object o1, Object o2) {
        /* 알맞은 코드를 넣어 완성하시오 (1) . */
 
    }
}
 
class Exercise11_7 {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(new Student("이자바"21709070));
        list.add(new Student("안자바"226010080));
        list.add(new Student("홍길동"13100100100));
        list.add(new Student("남궁성"11907080));
        list.add(new Student("김자바"12808090));
        Collections.sort(list, new BanNoAscending());
        Iterator it = list.iterator();
        while (it.hasNext())
            System.out.println(it.next());
    }
}
cs

[실행결과] 

남궁성,1,1,90,70,80,240,80.0 

김자바,1,2,80,80,90,250,83.3 

홍길동,1,3,100,100,100,300,100.0 

이자바,2,1,70,90,70,230,76.7 

안자바,2,2,60,100,80,240,80.0

 

<나의 풀이>

1
2
3
4
5
6
7
8
9
10
11
class BanNoAscending implements Comparator {
    public int compare(Object o1, Object o2) {
        if (o1 instanceof Student && o2 instanceof Student) {
            Student s1 = (Student) o1;
            Student s2 = (Student) o2;
 
            return s1.ban < s2.ban ? -1 : (s1.ban == s2.ban ? (s1.no < s2.no ? -1 : 1) : 1);
        }
        return -1;
    }
}
cs

삼항연산자가 세번이나 중첩됐고 ban이나 no가 int형이기 때문에 굳이 -1,1로 해줄 필요가 없었다. 

compare의 return 값의 숫자를 보는것이 아니라 양/음수인지 0인지만 판단하여 정렬하기 때문에 두개를 비교하려면 그냥 빼주기만 하면 되기 때문이다. 

뺄셈 결과가 -이면 앞이 작은수, +이면 앞이 큰수, 0이면 같은 수다.

따라서 아래와 같이 간략화 할 수 있다. 

1
2
3
4
5
6
7
8
9
    public int compare(Object o1, Object o2) {
        if (o1 instanceof Student && o2 instanceof Student) {
            Student s1 = (Student) o1;
            Student s2 = (Student) o2;
            int result = s1.ban - s2.ban;
            return result;
        }
        return -1;
    }
cs

 

<문제6>

[11-8] 문제11-7의 Student클래스에 총점(total)과 전교등수(schoolRank)를 저장하기 위한 인스턴스변수를 추가하였다. Student클래스의 기본정렬을 이름(name)이 아닌 총점(total)을 기준으로 한 내림차순으로 변경한 다음, 총점을 기준으로 각 학생의 전교등수를 계산하고 전교등수를 기준으로 오름차순 정렬하여 출력하시오.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import java.util.*;
 
class Student implements Comparable {
    String name;
    int ban;
    int no;
    int kor;
    int eng;
    int math;
    int total; // 총점
    int schoolRank; // 전교등수
 
    Student(String name, int ban, int no, int kor, int eng, int math) {
        this.name = name;
        this.ban = ban;
        this.no = no;
        this.kor = kor;
        this.eng = eng;
        this.math = math;
        total = kor + eng + math;
    }
 
    int getTotal() {
        return total;
    }
 
    float getAverage() {
        return (int) ((getTotal() / 3f) * 10 + 0.5/ 10f;
    }
 
    public int compareTo(Object o) {
        /*
         * (1) 알맞은 코드를 넣어 완성하시오.
         */
    }
 
    public String toString() {
        return name + "," + ban + "," + no + "," + kor + "," + eng + "," + math + "," + getTotal()
 + "," + getAverage() + "," + schoolRank; // 새로추가
    }
}
 
class Exercise11_8 {
    public static void calculateSchoolRank(List list) {
        Collections.sort(list); // 먼저 list를 총점기준 내림차순으로 정렬한다.
        int prevRank = -1// 이전 전교등수
        int prevTotal = -1// 이전 총점
        int length = list.size();
        /*
         * (2) 아래의 로직에 맞게 코드를 작성하시오. 
* 1. 반복문을 이용해서 list에 저장된 Student객체를 하나씩 읽는다. 
* 1.1 총점(total)이 이전총점(prevTotal)과 같으면 이전 등수(prevRank)를 
* 등수(schoolRank)로 한다. 
* 1.2 총점이
서로 다르면, 등수(schoolRank)의 값을 알맞게 계산해서 저장한다. 
* 이전에 동점자 였다면, 그 다음 등수는 동점자의 수를 고려해야한다. (실행결과 참고) 
* 1.3 현재 총점과 등수를 이전총점(prevTotal)과 이전등수(prevRank)에 저장한다.
         */
    }
 
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(new Student("이자바"21709070));
        list.add(new Student("안자바"226010080));
        list.add(new Student("홍길동"13100100100));
        list.add(new Student("남궁성"11907080));
        list.add(new Student("김자바"12808090));
        calculateSchoolRank(list);
        Iterator it = list.iterator();
        while (it.hasNext())
            System.out.println(it.next());
    }
}
 cs

[실행결과] 

홍길동,1,3,100,100,100,300,100.0,1
김자바,1,2,80,80,90,250,83.3,2
안자바,2,2,60,100,80,240,80.0,3
남궁성,1,1,90,70,80,240,80.0,3
이자바,2,1,70,90,70,230,76.7,5

 

<나의 풀이>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void calculateSchoolRank(List list) {
        Collections.sort(list); // 먼저 list를 총점기준 내림차순으로 정렬한다.
 
        int prevRank = -1// 이전 전교등수
        int prevTotal = -1// 이전 총점
        int length = list.size();
 
        for (int i = 0; i < length; i++) {
 // 반복문을 이용해서 list에 저장된 Student객체를 하나씩 읽는다.
            Student2 current = (Student2) list.get(i);
 // 총점(total)이 이전총점(prevTotal)과 같으면 이전 등수(PrevRank)를 등수(schoolRank)로 한다.
            if (current.total == prevTotal) {
                current.schoolRank = prevRank;
            } else {
 // 총점이 이전총점과 같지 않으면 등수를 넣는다(i+1)
                current.schoolRank = i + 1;
            }
 // 현재 schoolRank와 total을 prev변수들에 넣는다.
            prevRank = current.schoolRank;
            prevTotal = current.total;
 
        }
cs

 

<문제7>

[11-9] 문제11-8의 Student클래스에 반등수(classRank)를 저장하기 위한 인스턴스변수를 추가하였다. 반등수를 계산하고 반과 반등수로 오름차순 정렬하여 결과를 출력하시오. (1)~(2)에 알맞은 코드를 넣어 완성하시오.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import java.util.*;
 
class Student implements Comparable {
    String name;
    int ban;
    int no;
    int kor;
    int eng;
    int math;
    int total;
    int schoolRank; // 전교등수
    int classRank; // 반등수
 
    Student(String name, int ban, int no, int kor, int eng, int math) {
        this.name = name;
        this.ban = ban;
        this.no = no;
        this.kor = kor;
        this.eng = eng;
        this.math = math;
        total = kor + eng + math;
    }
 
    int getTotal() {
        return total;
    }
 
    float getAverage() {
        return (int) ((getTotal() / 3f) * 10 + 0.5/ 10f;
    }
 
    public int compareTo(Object o) {
        if (o instanceof Student) {
            Student tmp = (Student) o;
            return tmp.total - this.total;
        } else {
            return -1;
        }
    }
 
    public String toString() {
        return name + "," + ban + "," + no + "," + kor + "," + eng + "," + math + "," + getTotal() + "," + getAverage()
                + "," + schoolRank + "," + classRank // 새로추가
        ;
    }
// class Student
 
class ClassTotalComparator implements Comparator {
    public int compare(Object o1, Object o2) {
        /*
         * (1) 알맞은 코드를 넣어 완성하시오.
         */
    }
}
 
class Exercise11_9 {
    public static void calculateClassRank(List list) {
// 먼저 반별 총점기준 내림차순으로 정렬한다.
        Collections.sort(list, new ClassTotalComparator());
        int prevBan = -1;
        int prevRank = -1;
        int prevTotal = -1;
        int length = list.size();
        /*
         * (2) 아래의 로직에 맞게 코드를 작성하시오. 1. 반복문을 이용해서 list에 저장된 Student객체를 하나씩 읽는다. 1.1 반이
         * 달라지면,(ban과 prevBan이 다르면) 이전 등수(prevRank)와 이전 총점(prevTotal)을 초기화한다. 1.2
         * 총점(total)이 이전총점(prevTotal)과 같으면 이전 등수(prevRank)를 등수(classRank)로 한다. 1.3 총점이
         * 서로 다르면, 등수(classRank)의 값을 알맞게 계산해서 저장한다. 이전에 동점자였다면, 그 다음 등수는 동점자의 수를 고려해야
         * 한다. (실행결과 참고) 1.4 현재 반과 총점과 등수를 이전 반(prevBan), 이전 총점(prevTotal), 이전
         * 등수(prevRank)에 저장한다.
         */
    } // public static void calculateClassRank(List list) {
 
    public static void calculateSchoolRank(List list) {
        /* 내용 생략 */
    }
 
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(new Student("이자바"21709070));
        list.add(new Student("안자바"226010080));
        list.add(new Student("홍길동"13100100100));
        list.add(new Student("남궁성"11907080));
        list.add(new Student("김자바"12808090));
        calculateSchoolRank(list);
        calculateClassRank(list);
        Iterator it = list.iterator();
        while (it.hasNext())
            System.out.println(it.next());
    }
}
cs

[실행 결과]

홍길동,1,3,100,100,100,300,100.0,1,1
김자바,1,2,80,80,90,250,83.3,2,2
남궁성,1,1,90,70,80,240,80.0,3,3
안자바,2,2,60,100,80,240,80.0,3,1
이자바,2,1,70,90,70,230,76.7,5,2

 

<나의 풀이>

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class ClassTotalComparator implements Comparator {
    public int compare(Object o1, Object o2) {
        if (o1 instanceof Student33 && o2 instanceof Student33) {
            Student33 s1 = (Student33) o1;
            Student33 s2 = (Student33) o2;
            int tmp = s2.total - s1.total;
            if (tmp == 0)
                // 점수가 같을 경우 이름 오름차순 정렬. 
                return s1.name.compareTo(s2.name);
            return tmp;
        }
        return -1;
    }
}
 
class Exercise11_9 {
    public static void calculateClassRank(List list) {
        // 먼저 반별 총점기준 내림차순으로 정렬한다.
        Collections.sort(list, new ClassTotalComparator());
        int prevBan = -1;
        int prevRank = -1;
        int prevTotal = -1;
        int length = list.size();
 
        for (int i = 0; i < length; i++) {
            Student33 tmp = (Student33) list.get(i);
            // 반이 이전반과 같지 않으면 새로 count시작해야하니 초기화. 
            if (tmp.ban != prevBan) {
                prevRank = 0;
                prevTotal = 0;
            }
            // 이전 점수와 현재 점수가 같으면 이전점수와 같은 rank를 주고
            // 그 다음 등수를 고려하여 이전 점수를 1 올려준다. 
            if (tmp.total == prevTotal) {
                tmp.classRank = prevRank;
                prevRank++;
            } else {
                // 이전 점수와 현재 점수가 같지 않으면 이전점수 +1을 rank로 주고 
                // prevRank를 현재점수로 초기화한다. 
                tmp.classRank = prevRank + 1;
                prevRank = tmp.classRank;
            }
            // 다음 계산이 가능하도록 현재 ban,total을 각각 이전ban, total에 초기화. 
            prevBan = tmp.ban;
            prevTotal = tmp.total;
 
        }
    } // public static void calculateClassRank(List list) 
cs

 

댓글