본문 바로가기
개념

[JAVA의 정석] Chapter11_연습문제

by cook_code 2024. 12. 15.
 

[11-1] 다음은 정수집합 1, 2, 3, 4와 3, 4, 5, 6의 교집합, 차집합, 합집합을 구하는 코드이다. 코드를 완성하여 실행결과와 같은 결과를 출력하시오.

[Hint] ArrayList클래스의 addAll( ), removeAll( ), retainALL( )을 사용하라.

 

list1=[1, 2, 3, 4]

list2=[3, 4, 5, 6]

kyo=[3, 4]

cha=[1, 2]

hap=[1, 2, 3, 4, 5, 6]

 

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);

		kyo.addAll(list1);
		kyo.retainAll(list2);
		cha.addAll(list1);
		cha.removeAll(list2);
		hap.addAll(cha);
		hap.addAll(list2);

		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);

	}

}
 

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

 

import java.util.*;

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());
	}

}
 

[11-3] 다음 중 ArrayList에서 제일 비용이 많이 드는 직업은? 단, 작업도중에 ArrayList의 크기 변경이 발생하지 않는다고 가정한다.

 

a. 첫 번째 요소 삭제

b. 마지막 요소 삭제

c. 마지막에 새로운 요소 추가

d. 중간에 새로운 요소 추가

 

a

 

풀이

a. 첫 번째 요소 삭제
비용: 첫 번째 요소를 삭제한 후, 나머지 모든 요소를 왼쪽으로 한 칸씩 이동해야 합니다. 이 과정은 O(n) 시간 복잡도를 가집니다.
작업: 모든 요소를 이동시키는 비용 발생.

b. 마지막 요소 삭제
비용: 마지막 요소를 삭제하는 것은 단순히 배열의 크기를 줄이는 것이므로 O(1) 시간 복잡도를 가집니다.
작업: 추가적인 이동이 필요하지 않습니다.

c. 마지막에 새로운 요소 추가
비용: 배열의 크기 변경이 발생하지 않는다고 가정할 때, 마지막에 새로운 요소를 추가하는 것은 O(1) 시간 복잡도를 가집니다.
작업: 새로운 요소를 마지막 위치에 추가하는 것만 하면 됩니다.

d. 중간에 새로운 요소 추가
비용: 중간에 새로운 요소를 추가하면, 추가할 위치 이후의 모든 요소를 오른쪽으로 한 칸씩 이동시켜야 합니다. 이 과정은 O(n) 시간 복잡도를 가집니다.
작업: 요소를 이동시키는 비용 발생.
 

[11-4] LinkedList 클래스는 이름과 달리 실제로는 이중 원형 연결리스트(doubly circular linked list)로 구현되어 있다. LinkedList인스턴스를 생성하고 11개의 요소를 추가했을 때, 이 11개의 요소 중 접근시간(access time)이 가장 오래 걸리는 요소는 몇 번째 요소인가?

 

LinkedList에서 특정 요소에 접근하려면 첫 번째 또는 마지막 요소부터 시작하여 차례로 링크를 따라가야 한다. 따라서, 요소에 접근하는 시간은 요소가 리스트의 어느 쪽에 위치하는지에 따라 다르다.
11개의 요소가 있는 LinkedList를 고려할 때, 리스트의 중간 요소에 접근하는 데 가장 많은 시간이 걸린다.

요소 개수: 11
중앙 요소의 인덱스: (11 - 1) / 2 = 5 (0부터 시작하는 인덱스 기준)

따라서, 접근 시간이 가장 오래 걸리는 요소는 6번째 요소 (1부터 시작하는 인덱스 기준)이다.
 

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

 

김자바,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

 

import java.util.*;

class Student implements Comparable<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;
	}

	@Override
	public String toString() {
		return name + "," + ban + "," + no + "," + kor + "," + eng + "," + math
				+ "," + getTotal() + "," + getAverage();
	}

	@Override
	public int compareTo(Student o) {
		return name.compareTo(o.name);
	}
}

class Exercise11_5 {
	public static void main(String[] args) {
		ArrayList<Student> list = new ArrayList<>();
		list.add(new Student("홍길동", 1, 1, 100, 100, 100));
		list.add(new Student("남궁성", 1, 2, 90, 70, 80));
		list.add(new Student("김자바", 1, 3, 80, 80, 90));
		list.add(new Student("이자바", 1, 4, 70, 90, 70));
		list.add(new Student("안자바", 1, 5, 60, 100, 80));
		Collections.sort(list);
		Iterator<Student> it = list.iterator();
		while (it.hasNext())
			System.out.println(it.next());
	}
}
 

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

[Hint] TreeSet의 subSet(Object from, Object to)를 사용하라.

 

이자바,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

 

import java.util.*;

class Student implements Comparable<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();
	}

	public int compareTo(Student o) {
		return name.compareTo(o.name);
	}
}

class Exercise11_6 {

	static int getGroupCount(TreeSet<Student> tset, int from, int to) {
		Student fromStu = new Student("", 0, 0, from, from, from);
		Student toStu = new Student("", 0, 0, to, to, to);
		return tset.subSet(fromStu, toStu).size();
	}

	public static void main(String[] args) {
		TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
			public int compare(Student s1, Student s2) {
				return Float.compare(s1.getAverage(), s2.getAverage());
			}
		});

		set.add(new Student("홍길동", 1, 1, 100, 100, 100));
		set.add(new Student("남궁성", 1, 2, 90, 70, 80));
		set.add(new Student("김자바", 1, 3, 80, 80, 90));
		set.add(new Student("이자바", 1, 4, 70, 90, 70));
		set.add(new Student("안자바", 1, 5, 60, 100, 80));

		Iterator<Student> it = set.iterator();

		while (it.hasNext())
			System.out.println(it.next());

		System.out.println("[60~69]:" + getGroupCount(set, 60, 70));
		System.out.println("[70~79]:" + getGroupCount(set, 70, 80));
		System.out.println("[80~89]:" + getGroupCount(set, 80, 90));
		System.out.println("[90~100]:" + getGroupCount(set, 90, 101));
	}
}
 

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

 

김자바,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

 

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 BanNoAscending implements Comparator<Student> {
    public int compare(Student s1, Student s2) {
        // 반을 먼저 비교
        if (s1.ban != s2.ban) {
            return s1.ban - s2.ban;
        }
        // 반이 같으면 번호를 비교
        return s1.no - s2.no;
    }
}

class Exercise11_7 {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student("이자바", 2, 1, 70, 90, 70));
        list.add(new Student("안자바", 1, 2, 80, 80, 90));
        list.add(new Student("홍길동", 2, 2, 60, 100, 80));
        list.add(new Student("남궁성", 1, 3, 100, 100, 100));
        list.add(new Student("김자바", 1, 1, 90, 70, 80));

        Collections.sort(list, new BanNoAscending());

        Iterator<Student> it = list.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}
 

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

 

import java.util.*;

class Student implements Comparable<Student> {
	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(Student o) {
		return o.total - this.total; // 총점을 기준으로 내림차순 정렬
	}

	public String toString() {
		return name + "," + ban + "," + no + "," + kor + "," + eng + "," + math
				+ "," + getTotal() + "," + getAverage() + "," + schoolRank; // 새로 추가
	}
}

class Exercise11_8 {
	public static void calculateSchoolRank(List<Student> list) {
		Collections.sort(list); // 먼저 list를 총점기준 내림차순으로 정렬한다.

		int prevRank = -1; // 이전 전교등수
		int prevTotal = -1; // 이전 총점
		int sameRankCount = 0; // 동점자 수

		for (int i = 0; i < list.size(); i++) {
			Student s = list.get(i);

			if (s.total == prevTotal) {
				s.schoolRank = prevRank;
				sameRankCount++;
			} else {
				s.schoolRank = i + 1;
				prevRank = s.schoolRank;
				prevTotal = s.total;
				sameRankCount = 1;
			}
		}

		// 동점자들에 대해 올바르게 등수 반영
		for (int i = 0; i < list.size(); i++) {
			Student s = list.get(i);
			if (s.total == prevTotal) {
				s.schoolRank = prevRank - sameRankCount + 1;
			}
		}
	}

	public static void main(String[] args) {
		ArrayList<Student> list = new ArrayList<>();
		list.add(new Student("이자바", 2, 1, 70, 90, 70));
		list.add(new Student("안자바", 2, 2, 60, 100, 80));
		list.add(new Student("홍길동", 1, 3, 100, 100, 100));
		list.add(new Student("남궁성", 1, 1, 90, 70, 80));
		list.add(new Student("김자바", 1, 2, 80, 80, 90));

		calculateSchoolRank(list);

		Collections.sort(list, new Comparator<Student>() {
			public int compare(Student s1, Student s2) {
				return s1.schoolRank - s2.schoolRank; // 전교등수를 기준으로 오름차순 정렬
			}
		});

		Iterator<Student> it = list.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
 

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

 

import java.util.*;

class Student implements Comparable<Student> {
	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(Student o) {
		return o.total - this.total; // 총점을 기준으로 내림차순 정렬
	}

	public String toString() {
		return name + "," + ban + "," + no + "," + kor + "," + eng + "," + math
				+ "," + getTotal() + "," + getAverage() + "," + schoolRank + "," + classRank;
	}
}

class ClassTotalComparator implements Comparator<Student> {
	public int compare(Student s1, Student s2) {
		if (s1.ban != s2.ban) {
			return s1.ban - s2.ban; // 반을 기준으로 오름차순 정렬
		}
		return s2.total - s1.total; // 반이 같으면 총점을 기준으로 내림차순 정렬
	}
}

class Exercise11_9 {
	public static void calculateClassRank(List<Student> list) {
		Collections.sort(list, new ClassTotalComparator());

		int prevBan = -1;
		int prevRank = 0;
		int prevTotal = -1;
		int sameRankCount = 0;

		for (int i = 0; i < list.size(); i++) {
			Student s = list.get(i);

			if (s.ban != prevBan) {
				prevRank = 0;
				prevTotal = -1;
				sameRankCount = 0;
				prevBan = s.ban;
			}

			if (s.total == prevTotal) {
				s.classRank = prevRank;
				sameRankCount++;
			} else {
				s.classRank = prevRank + sameRankCount + 1;
				prevRank = s.classRank;
				prevTotal = s.total;
				sameRankCount = 0;
			}
		}
	}

	public static void calculateSchoolRank(List<Student> list) {
		Collections.sort(list);

		int prevRank = -1;
		int prevTotal = -1;
		int sameRankCount = 0;

		for (int i = 0; i < list.size(); i++) {
			Student s = list.get(i);

			if (s.total == prevTotal) {
				s.schoolRank = prevRank;
				sameRankCount++;
			} else {
				s.schoolRank = i + 1;
				prevRank = s.schoolRank;
				prevTotal = s.total;
				sameRankCount = 0;
			}
		}
	}

	public static void main(String[] args) {
		ArrayList<Student> list = new ArrayList<>();
		list.add(new Student("이자바", 2, 1, 70, 90, 70));
		list.add(new Student("안자바", 2, 2, 60, 100, 80));
		list.add(new Student("홍길동", 1, 3, 100, 100, 100));
		list.add(new Student("남궁성", 1, 1, 90, 70, 80));
		list.add(new Student("김자바", 1, 2, 80, 80, 90));

		calculateSchoolRank(list);
		calculateClassRank(list);

		Collections.sort(list, new Comparator<Student>() {
			public int compare(Student s1, Student s2) {
				if (s1.ban != s2.ban) {
					return s1.ban - s2.ban;
				}
				return s1.classRank - s2.classRank;
			}
		});

		Iterator<Student> it = list.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
 

[11-10] 다음 예제의 빙고판은 1~30 사이의 숫자들로 만든 것인데, 숫자들의 위치가 잘 섞이지 않는다는 문제가 있다. 이러한 문제가 발생하는 이유와 이 문제를 개선하기 위한 방법을 설명하고, 이를 개선한 새로운 코드를 작성하시오.

import java.util.*;



class Exercise11_10 {

	public static void main(String[] args) {

		Set set = new HashSet();

		int[][] board = new int[5][5];



		for (int i = 0; set.size() < 25; i++) {

			set.add((int) (Math.random() * 30) + 1 + "");

		}



		Iterator it = set.iterator();



		for (int i = 0; i < board.length; i++) {

			for (int j = 0; j < board[i].length; j++) {

				board[i][j] = Integer.parseInt((String) it.next());

				System.out.print((board[i][j] < 10 ? " " : "") + board[i][j]);

			}

			System.out.println();

		}

	}

}
 

 

 

문제 :

현재 코드에서 숫자가 잘 섞이지 않는 문제의 원인은 HashSet을 사용한 뒤, 이를 바로 Iterator로 순회하여 빙고판에 숫자를 배치하기 때문이다. HashSet은 내부적으로 해시 테이블을 사용하여 요소를 저장하므로, 요소의 순서가 랜덤하게 섞이지 않는다. 또한, HashSet은 중복을 허용하지 않으므로 랜덤하게 생성된 숫자가 중복되어 삽입되지 않는 경우가 발생할 수 있다.

 

해결 :

  • ArrayList 사용: 랜덤하게 생성된 숫자를 ArrayList에 저장하고, 이를 Collections.shuffle 메서드를 사용하여 섞는다.
  • 숫자 범위 조정: 1부터 30까지의 숫자를 생성하여 중복 없이 삽입한다.
import java.util.*;

class Exercise11_10 {
	public static void main(String[] args) {
		List<Integer> list = new ArrayList<>();
		int[][] board = new int[5][5];

		// 1부터 30까지의 숫자를 리스트에 추가
		for (int i = 1; i <= 30; i++) {
			list.add(i);
		}

		// 리스트를 섞어 숫자의 위치를 랜덤하게 만든다.
		Collections.shuffle(list);

		// 섞인 리스트에서 첫 25개의 숫자를 빙고판에 배치
		Iterator<Integer> it = list.iterator();
		for (int i = 0; i < board.length; i++) {
			for (int j = 0; j < board[i].length; j++) {
				board[i][j] = it.next();
				System.out.print((board[i][j] < 10 ? " " : "") + board[i][j] + " ");
			}
			System.out.println();
		}
	}
}
 

[11-11] 다음은 SutdaCard클래스를 HashSet에 저장하고 출력하는 예제이다. HashSet에 중복된 카드가 저장되지 않도록 SutdaCard의 hashCode( )를 알맞게 오버라이딩하시오.

[Hint] String클래스의 hashCode( )를 사용하라

 

[3K, 1K]

 

import java.util.*;



class SutdaCard {

	int num;

	boolean isKwang;



	SutdaCard() {

		this(1, true);

	}



	SutdaCard(int num, boolean isKwang) {

		this.num = num;

		this.isKwang = isKwang;

	}



	public boolean equals(Object obj) {

		if (obj instanceof SutdaCard) {

			SutdaCard c = (SutdaCard) obj;

			return num == c.num && isKwang == c.isKwang;

		} else {

			return false;

		}

	}



	public String toString() {

		return num + (isKwang ? "K" : "");

	}

}



class Exercise11_11 {

	public static void main(String[] args) {

		SutdaCard c1 = new SutdaCard(3, true);

		SutdaCard c2 = new SutdaCard(3, true);

		SutdaCard c3 = new SutdaCard(1, true);



		HashSet set = new HashSet();

		set.add(c1);

		set.add(c2);

		set.add(c3);



		System.out.println(set);

	}

}
 

문제 :

SutdaCard 클래스를 HashSet에 저장하고 출력하는 예제입니다. HashSet은 중복 요소를 저장하지 않지만, 현재 코드에서는 중복된 SutdaCard 객체가 HashSet에 저장될 수 있습니다. 이를 해결하기 위해 hashCode() 메서드를 적절히 오버라이딩해야 합니다.

import java.util.*;

class Student_4 implements Comparable<Student_4> {
	String name;
	int ban;
	int no;
	int kor, eng, math;

	Student_4(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;
	}

	@Override
	public String toString() {
		return name + "," + ban + "," + no + "," + kor + "," + eng + "," + math
				+ "," + getTotal() + "," + getAverage();
	}

	@Override
	public int compareTo(Student_4 o) {
		return name.compareTo(o.name);
	}
}

class Exercise11_5 {
	public static void main(String[] args) {
		ArrayList<Student_4> list = new ArrayList<>();
		list.add(new Student_4("홍길동", 1, 1, 100, 100, 100));
		list.add(new Student_4("남궁성", 1, 2, 90, 70, 80));
		list.add(new Student_4("김자바", 1, 3, 80, 80, 90));
		list.add(new Student_4("이자바", 1, 4, 70, 90, 70));
		list.add(new Student_4("안자바", 1, 5, 60, 100, 80));
		Collections.sort(list);
		Iterator<Student_4> it = list.iterator();
		while (it.hasNext())
			System.out.println(it.next());
	}
}
 

[11-12] 다음은 섯다게임에서 카드의 순위를 결정하는 등급목록(족보)이다. HashMap에 등급과 점수를 저장하는 registerJokbo( )와 게임참가자의 점수를 계산해서 반환하는 getPoint( )를 완성하시오.

[참고] 섯다게임은 두 장의 카드의 숫자를 더한 값을 10으로 나눈 나머지가 높은 쪽이 이기는 게임이다. 그 외에도 특정 숫자로 구성된 카드로 이루어진 등급(족보)이 있어서 높은 등급의 카드가 이긴다.

 
사진 삭제

사진 설명을 입력하세요.

 

import java.util.*;

class Exercise11_12 {
	public static void main(String args[]) throws Exception {
		SutdaDeck deck = new SutdaDeck();

		deck.shuffle();
		Player p1 = new Player("타짜", deck.pick(), deck.pick());
		Player p2 = new Player("고수", deck.pick(), deck.pick());

		System.out.println(p1 + " " + deck.getPoint(p1));
		System.out.println(p2 + " " + deck.getPoint(p2));
	}
}

class SutdaDeck {
	final int CARD_NUM = 20;
	SutdaCard[] cards = new SutdaCard[CARD_NUM];

	int pos = 0; // 다음에 가져올 카드의 위치
	HashMap<String, Integer> jokbo = new HashMap<>(); // 족보를 저장할 HashMap

	SutdaDeck() {
		for (int i = 0; i < cards.length; i++) {
			int num = i % 10 + 1;
			boolean isKwang = i < 10 && (num == 1 || num == 3 || num == 8);
			cards[i] = new SutdaCard(num, isKwang);
		}
		registerJokbo(); // 족보를 등록한다.
	}

	void registerJokbo() {
		// jokbo(HashMap)에 족보를 저장한다.
		// 두 카드의 값을 문자열로 붙여서 key로, 점수를 value로 저장한다.
		jokbo.put("KK", 4000);
		jokbo.put("1010", 3100);
		jokbo.put("99", 3090);
		jokbo.put("88", 3080);
		jokbo.put("77", 3070);
		jokbo.put("66", 3060);
		jokbo.put("55", 3050);
		jokbo.put("44", 3040);
		jokbo.put("33", 3030);
		jokbo.put("22", 3020);
		jokbo.put("11", 3010);
	}

	int getPoint(Player p) {
		if (p == null)
			return 0;

		SutdaCard c1 = p.c1;
		SutdaCard c2 = p.c2;

		Integer result = 0;

		if (c1.isKwang && c2.isKwang) {
			result = jokbo.get("KK");
		} else {
			String key = c1.num + "" + c2.num;
			if (jokbo.containsKey(key)) {
				result = jokbo.get(key);
			} else {
				result = (c1.num + c2.num) % 10 + 1000;
			}
		}

		p.point = result;
		return result;
	}

	SutdaCard pick() throws Exception {
		SutdaCard c = null;

		if (0 <= pos && pos < CARD_NUM) {
			c = cards[pos];
			cards[pos++] = null;
		} else {
			throw new Exception("남아있는 카드가 없습니다.");
		}
		return c;
	}

	void shuffle() {
		for (int x = 0; x < CARD_NUM * 2; x++) {
			int i = (int) (Math.random() * CARD_NUM);
			int j = (int) (Math.random() * CARD_NUM);

			SutdaCard tmp = cards[i];
			cards[i] = cards[j];
			cards[j] = tmp;
		}
	}
}

class Player {
	String name;
	SutdaCard c1;
	SutdaCard c2;
	int point; // 카드의 등급에 따른 점수 - 새로 추가

	Player(String name, SutdaCard c1, SutdaCard c2) {
		this.name = name;
		this.c1 = c1;
		this.c2 = c2;
	}

	public String toString() {
		return "[" + name + "]" + c1.toString() + "," + c2.toString();
	}
}

class SutdaCard {
	int num;
	boolean isKwang;

	SutdaCard() {
		this(1, true);
	}

	SutdaCard(int num, boolean isKwang) {
		this.num = num;
		this.isKwang = isKwang;
	}

	public String toString() {
		return num + (isKwang ? "K" : "");
	}
}
 

[11-13] 다음 코드는 문제 11-12를 발전시킨 것으로 각 Player들의 점수를 계산하고, 점수가 제일 높은 사람을 출력하는 코드이다. TreeMap의 정렬기준을 점수가 제일 높은 사람부터 내림차순이 되도록 아래의 코드를 완성하시오. 단, 동점자 처리는 하지 않는다.

 

import java.util.*;

class Exercise11_13 {
    public static void main(String args[]) throws Exception {
        SutdaDeck deck = new SutdaDeck();

        deck.shuffle();

        Player[] pArr = { 
            new Player("타짜", deck.pick(), deck.pick()), 
            new Player("고수", deck.pick(), deck.pick()),
            new Player("물주", deck.pick(), deck.pick()), 
            new Player("중수", deck.pick(), deck.pick()),
            new Player("하수", deck.pick(), deck.pick()) 
        };

        TreeMap<Player, Integer> rank = new TreeMap<>(new Comparator<Player>() {
            public int compare(Player p1, Player p2) {
                return p2.point - p1.point; // 점수를 기준으로 내림차순 정렬
            }
        });

        for (int i = 0; i < pArr.length; i++) {
            Player p = pArr[i];
            rank.put(p, deck.getPoint(p));
            System.out.println(p + " " + deck.getPoint(p));
        }

        System.out.println();
        System.out.println("1위는 " + rank.firstKey() + "입니다.");
    }
}

class SutdaDeck {
    final int CARD_NUM = 20;
    SutdaCard[] cards = new SutdaCard[CARD_NUM];
    int pos = 0; // 다음에 가져올 카드의 위치
    HashMap<String, Integer> jokbo = new HashMap<>(); // 족보를 저장할 HashMap

    SutdaDeck() {
        for (int i = 0; i < cards.length; i++) {
            int num = i % 10 + 1;
            boolean isKwang = i < 10 && (num == 1 || num == 3 || num == 8);
            cards[i] = new SutdaCard(num, isKwang);
        }
        registerJokbo(); // 족보를 등록한다.
    }

    void registerJokbo() {
        // jokbo(HashMap)에 족보를 저장한다.
        // 두 카드의 값을 문자열로 붙여서 key로, 점수를 value로 저장한다.
        jokbo.put("KK", 4000);
        jokbo.put("1010", 3100);
        jokbo.put("12", 2060);
        jokbo.put("99", 3090);
        jokbo.put("21", 2060);
        jokbo.put("88", 3080);
        jokbo.put("14", 2050);
        jokbo.put("77", 3070);
        jokbo.put("41", 2050);
        jokbo.put("66", 3060);
        jokbo.put("19", 2040);
        jokbo.put("55", 3050);
        jokbo.put("91", 2040);
        jokbo.put("44", 3040);
        jokbo.put("110", 2030);
        jokbo.put("33", 3030);
        jokbo.put("101", 2030);
        jokbo.put("22", 3020);
        jokbo.put("104", 2020);
        jokbo.put("11", 3010);
        jokbo.put("410", 2020);
        jokbo.put("46", 2010);
        jokbo.put("64", 2010);
    }

    int getPoint(Player p) {
        if (p == null)
            return 0;

        SutdaCard c1 = p.c1;
        SutdaCard c2 = p.c2;

        Integer result = 0;

        if (c1.isKwang && c2.isKwang) {
            result = (Integer) jokbo.get("KK");
        } else {
            result = (Integer) jokbo.get("" + c1.num + c2.num);
            if (result == null) {
                result = (c1.num + c2.num) % 10 + 1000;
            }
        }

        p.point = result.intValue();

        return result.intValue();
    }

    SutdaCard pick() throws Exception {
        SutdaCard c = null;

        if (0 <= pos && pos < CARD_NUM) {
            c = cards[pos];
            cards[pos++] = null;
        } else {
            throw new Exception("남아있는 카드가 없습니다.");
        }
        return c;
    }

    void shuffle() {
        for (int x = 0; x < CARD_NUM * 2; x++) {
            int i = (int) (Math.random() * CARD_NUM);
            int j = (int) (Math.random() * CARD_NUM);

            SutdaCard tmp = cards[i];
            cards[i] = cards[j];
            cards[j] = tmp;
        }
    }
}

class Player {
    String name;
    SutdaCard c1;
    SutdaCard c2;
    int point;

    Player(String name, SutdaCard c1, SutdaCard c2) {
        this.name = name;
        this.c1 = c1;
        this.c2 = c2;
    }

    public String toString() {
        return "[" + name + "]" + c1.toString() + "," + c2.toString();
    }
}

class SutdaCard {
    int num;
    boolean isKwang;

    SutdaCard() {
        this(1, true);
    }

    SutdaCard(int num, boolean isKwang) {
        this.num = num;
        this.isKwang = isKwang;
    }

    public String toString() {
        return num + (isKwang ? "K" : "");
    }
}
 

풀이

1. registerJokbo() 메서드
HashMap에 족보를 저장. 두 카드의 값을 문자열로 붙여서 키로 사용하고, 점수를 값으로 저장.
예시: jokbo.put("1010", 3100);은 두 장의 10이 3100점이라는 것을 의미.

2. getPoint() 메서드
게임 참가자의 점수를 계산.
두 카드가 모두 광이면, jokbo에서 "KK" 키로 점수를 조회.
두 카드의 숫자(num)로 jokbo에서 등급을 조회.
해당하는 등급이 없으면, 공식 (c1.num + c2.num) % 10 + 1000으로 점수를 계산.
Player의 점수(point)에 계산한 값을 저장.

3. Comparator 구현
TreeMap에 Comparator를 전달하여 점수를 기준으로 내림차순 정렬.
Comparator의 compare 메서드를 오버라이딩하여 점수를 비교.
 

[11-14] 다음은 성적처리 프로그램의 일부이다. Scanner클래스를 이용해서 화면으로부터 데이터를 입력하고 보여주는 기능을 완성하시오.

 

import java.util.*;

class Exercise11_14 {
	static ArrayList<Student_8> record = new ArrayList<>(); // 성적 데이터를 저장할 공간
	static Scanner s = new Scanner(System.in);

	public static void main(String args[]) {
		while (true) {
			switch (displayMenu()) {
				case 1:
					inputRecord();
					break;
				case 2:
					displayRecord();
					break;
				case 3:
					System.out.println("프로그램을 종료합니다.");
					System.exit(0);
			}
		}
	}

	// menu를 보여주는 메서드
	static int displayMenu() {
		System.out.println("**************************************************");
		System.out.println("*                성적 관리 프로그램              *");
		System.out.println("**************************************************");
		System.out.println();
		System.out.println("1. 학생성적 입력하기");
		System.out.println();
		System.out.println("2. 학생성적 보기");
		System.out.println();
		System.out.println("3. 프로그램 종료");
		System.out.println();
		System.out.print("원하는 메뉴를 선택하세요.(1~3):");

		int menu = 0;
		while (true) {
			try {
				menu = Integer.parseInt(s.nextLine().trim());
				if (menu < 1 || menu > 3) {
					throw new Exception();
				}
				break;
			} catch (Exception e) {
				System.out.print("메뉴를 잘못 선택하셨습니다. 다시 입력해주세요. 원하는 메뉴를 선택하세요.(1~3):");
			}
		}

		return menu;
	}

	// 데이터를 입력받는 메서드
	static void inputRecord() {
		System.out.println("1.학생성적 입력하기");
		System.out.println("이름, 반, 번호, 국어성적, 영어성적, 수학성적 의 순서로 공백없이 입력하세요.");
		System.out.println("입력을 마치려면 q를 입력하세요. 메인화면으로 돌아갑니다.");

		while (true) {
			System.out.print(">>");
			String input = s.nextLine().trim();
			if (input.equalsIgnoreCase("q")) {
				return;
			}

			try {
				String[] data = input.split(",");
				if (data.length != 6) {
					throw new Exception();
				}
				String name = data[0];
				int ban = Integer.parseInt(data[1]);
				int no = Integer.parseInt(data[2]);
				int kor = Integer.parseInt(data[3]);
				int eng = Integer.parseInt(data[4]);
				int math = Integer.parseInt(data[5]);

				Student_8 student = new Student_8(name, ban, no, kor, eng, math);
				record.add(student);
				System.out.println("잘 입력되었습니다. 입력을 마치려면 q를 입력하세요.");
			} catch (Exception e) {
				System.out.println("입력오류입니다. 이름, 반, 번호, 국어성적, 영어성적, 수학성적 의 순서로 입력하세요.");
			}
		}
	}

	// 데이터 목록을 보여주는 메서드
	static void displayRecord() {
		int koreanTotal = 0;
		int englishTotal = 0;
		int mathTotal = 0;
		int total = 0;

		int length = record.size();

		if (length > 0) {
			System.out.println();
			System.out.println("이름 반 번호 국어 영어 수학 총점 평균 전교등수 반등수");
			System.out.println("====================================================");
			for (int i = 0; i < length; i++) {
				Student_8 student = record.get(i);
				System.out.println(student);
				koreanTotal += student.kor;
				mathTotal += student.math;
				englishTotal += student.eng;
				total += student.total;
			}

			System.out.println("====================================================");
			System.out.println("총점 :" + koreanTotal + " " + englishTotal + " " + mathTotal + " " + total);
			System.out.println();
		} else {
			System.out.println("====================================================");
			System.out.println("데이터가 없습니다.");
			System.out.println("====================================================");
		}
	}
}

class Student implements Comparable<Student_8> {
	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(Student_8 o) {
		return o.total - this.total;
	}

	public String toString() {
		return name + "," + ban + "," + no + "," + kor + "," + eng + "," + math + "," + getTotal() + "," + getAverage()
				+ "," + schoolRank + "," + classRank;
	}
}
 

풀이

1. displayMenu() 메서드
메뉴를 출력하고 사용자로부터 메뉴 선택을 입력받음.
입력이 유효한 값(1~3)인지 확인하고, 유효하지 않으면 다시 입력받음.

2. inputRecord() 메서드
학생 성적 데이터를 입력받아 Student 객체를 생성하고, record 리스트에 추가함.
입력 형식이 잘못되었을 경우 예외 처리를 통해 오류 메시지를 출력하고, 다시 입력받음.
입력이 "q" 또는 "Q"인 경우 메서드를 종료함.

3. displayRecord() 메서드
record 리스트에 저장된 학생 성적 데이터를 출력함.
각 과목의 총점과 전체 총점을 계산하여 출력함.
record 리스트가 비어있을 경우, "데이터가 없습니다." 메시지를 출력함.
 

 

반응형