11. 배열의 복사 및 활용

Isaiah IM·2023년 4월 30일
0

java basic

목록 보기
12/38
post-thumbnail

1. 배열의 복사

배열은 한번 생성하면 크기를 변경할 수 없기 때문에 기존보다 더 큰 배열을 새로 생성하고, 값을 복사해야 한다.
이때, 배열의 값을 복사하는 방식은 크게 2가지 방식이 있다.

  • 얕은 복사(shallow copy)
  • 깊은 복사(deep copy)

1.1 얕은 복사(shallow copy)

얕은 복사란 배열의 주소를 복사하는 방식이다.

얕은복사는 배열의 주소를 그대로 복사하는 것으로, 같은 메모리를 공유하고 있기 때문에 원본 배열 혹은 복사본 배열의 데이터 둘 중 하나가 변경되면 나머지 배열의 데이터도 변경되는 특징이 있다.

public class Array {
	public static void main(String args[]) {
		int arr1[]= new int[10];
		int i;
		
		/*array initialize*/
		for(i=0; i<arr1.length; i++) {
			arr1[i]=i+30;
		}
		
		int arrCopy[];
		
		arrCopy=arr1;// 얕은 복사
		
		System.out.println(" before update data: ");
		for(i=0; i<arr1.length; i++) {
			System.out.printf("arr1[%d] is %d\t", i, arr1[i]);
			System.out.printf("arrCopy[%d] is %d\n", i, arrCopy[i]);
		}
		
		/*update data*/
		for(i=0; i<arrCopy.length; i++) {
			arrCopy[i]=i;
		}
		
		System.out.println("\n after update data: ");
		for(i=0; i<arr1.length; i++) {
			System.out.printf("arr1[%d] is %d\t", i, arr1[i]);
			System.out.printf("arrCopy[%d] is %d\n", i, arrCopy[i]);
		}
	}
}

output

 before update data: 
arr1[0] is 30	arrCopy[0] is 30
arr1[1] is 31	arrCopy[1] is 31
arr1[2] is 32	arrCopy[2] is 32
arr1[3] is 33	arrCopy[3] is 33
arr1[4] is 34	arrCopy[4] is 34
arr1[5] is 35	arrCopy[5] is 35
arr1[6] is 36	arrCopy[6] is 36
arr1[7] is 37	arrCopy[7] is 37
arr1[8] is 38	arrCopy[8] is 38
arr1[9] is 39	arrCopy[9] is 39

 after update data: 
arr1[0] is 0	arrCopy[0] is 0
arr1[1] is 1	arrCopy[1] is 1
arr1[2] is 2	arrCopy[2] is 2
arr1[3] is 3	arrCopy[3] is 3
arr1[4] is 4	arrCopy[4] is 4
arr1[5] is 5	arrCopy[5] is 5
arr1[6] is 6	arrCopy[6] is 6
arr1[7] is 7	arrCopy[7] is 7
arr1[8] is 8	arrCopy[8] is 8
arr1[9] is 9	arrCopy[9] is 9

1.2 깊은 복사(deep copy)

깊은 복사란 배열의 값을 복사하는 방식이다.

깊은 복사는 배열의 값을 복사하는 것으로, 메모리를 공유하지 않기 때문에 원본 배열의 데이터가 변경되도 복사한 배열의 데이터는 변경되지 않고 그대로 유지된다.

깊은 복사의 방법은 다음과 같이 복사를 할 수 있다.

  • 반복문을 활용한 복사
  • Object.clone()을 활용한 복사
  • Arrays.copyOf()을 활용한 복사
  • Arrays.copyOfRange()을 활용한 복사
  • System.arraycopy()를 활용한 복사

1.2.1 반복문을 활용한 복사

먼저 반복문을 활용한 복사에 대해 알아보자.

반복문을 활용한 복사는 배열의 모든 요소를 반복문으로 순회해 값을 새로운 배열로 이동하는 것을 의미한다.

복사의 과정은 다음과 같다.

  1. 먼저, 값을 옮길 새로운 배열을 선언한다. 이때, 새로운 배열의 크기는 기존의 배열의 크기 이상이어야 한다.
  2. 반복문을 활용해 기존 배열에 있던 값을 새로운 배열로 옮긴다.
  3. 기존 배열의 이름인 참조변수를 새로운 배열 이름으로 대입한다.

이를 그림으로 나타내면 다음과 같다.

1번 과정:

2번 과정:

3번 과정:

이를 코드로 나타내면 다음과 같다.

code

public class Array {
    public static void main(String[] args) {
    	int arr_old[]=new int[5];
        int i;
        
        for(i=0; i<arr_old.length; i++) {
        	arr_old[i]=i+1;
        }
        
        int arr_tmp[]=new int[10];// 1번 과정
        
        System.out.println("변경전:");
        for(i=0; i<arr_tmp.length; i++) {
        	System.out.printf("arr_new[%d]: %d\n", i, arr_tmp[i]);
        }
        
        for(i=0; i<arr_old.length; i++) {// 2번 과정
        	arr_tmp[i]=arr_old[i];
        }
        
        arr_old=arr_tmp;// 3번 과정
        
        System.out.println("\n\n변경후:");
        for(i=0; i<arr_old.length; i++) {
        	System.out.printf("arr_new[%d]: %d\n", i, arr_old[i]);
        }
    }
}

output

변경전:
arr_new[0]: 0
arr_new[1]: 0
arr_new[2]: 0
arr_new[3]: 0
arr_new[4]: 0
arr_new[5]: 0
arr_new[6]: 0
arr_new[7]: 0
arr_new[8]: 0
arr_new[9]: 0


변경후:
arr_new[0]: 1
arr_new[1]: 2
arr_new[2]: 3
arr_new[3]: 4
arr_new[4]: 5
arr_new[5]: 0
arr_new[6]: 0
arr_new[7]: 0
arr_new[8]: 0
arr_new[9]: 0

1.2.2 Object.clone()을 활용한 복사

배열역시 하나의 객체이다(객체에 대해서는 추후에 다루도록 하겠다). 이 객체에서는 객체를 복사할 수 있는 객체이름.clone(); 함수가 존재한다. 이는 가장 보편적으로 사용하는 복사방법이며 다음과 같이 복사할 수 있다.

import java.util.Arrays;

public class Array {
	public static void main(String args[]) {
		int[] arr = { 1, 2, 3, 4 };
        int[] arrCopy = new int[arr.length];
        
        arrCopy=arr.clone();
        
        System.out.println(Arrays.toString(arrCopy));
	}
}

output

[1, 2, 3, 4]

1.2.3 Arrays.copyOf()을 활용한 복사

Arrays.copyOf()은 배열을 복사할 수 있는 방법중 하나이며, 배열의 0번째 부터 시작해서 n번째까지 복사를 할 수 있는 기능이다.
복사 방법은 다음과 같다.

import java.util.Arrays;

public class Array {
	public static void main(String args[]) {
		int[] arr = { 1, 2, 3, 4 };
        int[] arrCopy = new int[arr.length];
        
        arrCopy=Arrays.copyOf(arr, 3);// arr[0]~arr[3]까지만 복사
        System.out.println("copy until arr[3]:");
        System.out.println(Arrays.toString(arrCopy));
        
        arrCopy=Arrays.copyOf(arr, arr.length);// 전체 복사
        System.out.println("full copy:");
        System.out.println(Arrays.toString(arrCopy));
	}
}

output

copy until arr[3]:
[1, 2, 3]
full copy:
[1, 2, 3, 4]

1.2.4 Arrays.copyOfRange()을 활용한 복사

Arrays.copyOfRange()는 복사할 배열의 시작점과 끝점을 설정할 수 있는 기능이다.

사용 방법은 다음과 같다.

import java.util.Arrays;

public class Array {
	public static void main(String args[]) {
		int[] arr = { 1, 2, 3, 4 };
        int[] arrCopy = new int[arr.length];
        
        arrCopy=Arrays.copyOfRange(arr, 1, 4);
        System.out.println("copy arr[1] ~ arr[3]:");
        System.out.println(Arrays.toString(arrCopy));
        
        arrCopy=Arrays.copyOfRange(arr, 0, arr.length);
        System.out.println("full copy:");
        System.out.println(Arrays.toString(arrCopy));
	}
}

output

copy arr[1] ~ arr[3]:
[2, 3, 4]
full copy:
[1, 2, 3, 4]

1.2.5 System.arraycopy()를 활용한 복사

System.arraycopy()의 경우 지정된 범위의 값을 특정 위치로 복사하는 것이 가능하다.
그렇기에 단순 배열의 복사 뿐 아니라 두 배열을 합치는 것 또한 가능하다.

이러한 System.arraycopy()메소드의 인자는 다음과 같다.

System.arraycopy(arr1, x, arr2, y, len);
arr1[x]에서 arr2[y]로 len개의 데이터를 복사한다.

System.arraycopy()를 이용해 두 배열을 합치는 코드는 다음과 같다.

public class Array {
    public static void main(String[] args) {
    	int arr1[]=new int[5];
    	int arr2[]=new int[5];
        int i;
        
        for(i=0; i<arr1.length; i++) {// 1~5 저장
        	arr1[i]=1+i;
        }
        System.out.println(" arr1 data:");
        for(i=0; i<arr1.length; i++) {
        	System.out.printf("arr1[%d]: %d\n", i, arr1[i]);
        }
        
        for(i=0; i<arr2.length; i++) {// 6~10 저장
        	arr2[i]=6+i;
        }
        System.out.println("\n\n arr2 data:");
        for(i=0; i<arr2.length; i++) {
        	System.out.printf("arr2[%d]: %d\n", i, arr2[i]);
        }
        
        int arr_cat[]=new int[10];
        
        System.out.println("\n arr cat1:");
        System.arraycopy(arr1, 0, arr_cat, 0, arr1.length);
        for(i=0; i<arr1.length; i++) {
        	System.out.printf("arr_cat[%d]: %d\n", i, arr_cat[i]);
        }
        
        System.out.println("\n arr cat2:");
        System.arraycopy(arr2, 0, arr_cat, arr1.length, arr2.length);
        for(i=arr1.length; i<arr_cat.length; i++) {
        	System.out.printf("arr_cat[%d]: %d\n", i, arr_cat[i]);
        }
        
        System.out.println("\n\n result:");
        for(i=0; i<arr_cat.length; i++) {
        	System.out.printf("arr_cat[%d]: %d\n", i, arr_cat[i]);
        }
    }
}

output

 arr1 data:
arr1[0]: 1
arr1[1]: 2
arr1[2]: 3
arr1[3]: 4
arr1[4]: 5


 arr2 data:
arr2[0]: 6
arr2[1]: 7
arr2[2]: 8
arr2[3]: 9
arr2[4]: 10

 arr cat1:
arr_cat[0]: 1
arr_cat[1]: 2
arr_cat[2]: 3
arr_cat[3]: 4
arr_cat[4]: 5

 arr cat2:
arr_cat[5]: 6
arr_cat[6]: 7
arr_cat[7]: 8
arr_cat[8]: 9
arr_cat[9]: 10


 result:
arr_cat[0]: 1
arr_cat[1]: 2
arr_cat[2]: 3
arr_cat[3]: 4
arr_cat[4]: 5
arr_cat[5]: 6
arr_cat[6]: 7
arr_cat[7]: 8
arr_cat[8]: 9
arr_cat[9]: 10

위 코드의 내용을 그림으로 나타내면 다음과 같다.

먼저, arr1의 데이터를 arr_cat배열에 넣는다. 그러면 arr1의 배열 크기는 5이므로 arr_cat[0] ~ arr_cat[4]까지 arr1의 데이터가 저장된다.(System.arraycopy(arr1, 0, arr_cat, 0, arr1.length);)
다음으로 arr2의 데이터를 arr_cat배열에 남은 공간에 넣는다. 그러면 arr_cat[5] ~ arr_cat[9]까지 arr2의 데이터가 저장된다.(System.arraycopy(arr2, 0, arr_cat, arr1.length, arr2.length);)


2. 배열의 활용

2.1 최대/최솟값, 평균 구하기

배열 내부의 값들의 최댓값, 최솟값, 평균을 구하는 코드는 다음과 같다.

public class Array {
    public static void main(String[] args) {
    	int num[] = {10, 50, 30, 20, 40};
    	int min, max;
    	float mean;
    	
    	int i;
    	
    	/*최소값 구하기*/
    	min=9999;// min에 큰 값 넣기
    	for(i=0; i<num.length; i++) {
    		if(num[i]<min) {
    			min=num[i];
    		}
    	}
    	
    	/*최댓값 구하기*/
    	max=-1;// max에 작은값 넣기
    	for(i=0; i<num.length; i++) {
    		if(num[i]>max) {
    			max=num[i];
    		}
    	}
    	
    	/*평균 구하기*/
    	mean=0;// mean 초기화
    	for(i=0; i<num.length; i++) {// 배열 값 합계 구하기
    		mean+=num[i];
    	}
    	
    	mean/=num.length;// mean=mean/요소 갯수 (평균)
    	
    	System.out.println("min: "+min);
    	System.out.println("max: "+max);
    	System.out.println("mean: "+mean);
    }
}

output:

min: 10
max: 50
mean: 30.0

코드의 동작 원리는 다음과 같다.
최대/최소, 평균값의 저장은 최댓값의 경우 max변수, 최소값의 경우 min변수, 평균값의 경우 mean 변수에 저장을 했다.

  • 최솟값 구하기

최솟값의 초기화는 매우 큰 값을 넣어서 초기화를 한다. 이때, 필자가 작성한 코드의 경우 9999로 초기화를 했다.
다음으로, 배열의 첫번째 요소와 최솟값인 9999와 비교를 해서 최솟값이 배열의 첫번째 요소보다 더 큰지 비교를 한다.
이때는 배열의 첫번째 요소가 더 작으므로 배열의 첫번째 요소가 최솟값이 된다.
즉, 최솟값을 처음 9999라는 큰 수로 초기화를 한 이유는 배열의 첫번째 요소가 최솟값이 되게 하기 위해서 이다.

이후로는 배열의 모든 요소까지 반복문으로 순회를 하면서 기존에 저장되 있던 최솟값과 현재 배열의 값을 비교해서 최솟값 정보를 업데이트 한다.

  • 최댓값 구하기

최댓값의 초기화는 매우 작은 값을 넣어서 초기화를 한다. 이때, 필자가 작성한 코드의 경우 -1로 초기화를 했다.
다음으로, 배열의 첫번째 요소와 최댓값인 -1과 비교를 해서 배열의 첫번째 요소가 최댓값이 보다 더 큰지 비교를 한다.
이때는 배열의 첫번째 요소가 더 크므로 배열의 첫번째 요소가 최댓값이 된다.
즉, 최댓값을 처음 -1이라는 작은수로 초기화를 한 이유는 배열의 첫번째 요소가 최댓값이 되게 하기 위해서 이다.

이후로는 배열의 모든 요소까지 반복문으로 순회를 하면서 기존에 저장되 있던 최댓값과 현재 배열의 값을 비교해서 최댓값 정보를 업데이트 한다.

2.2 정렬

배열을 정렬하는 경우 다음과 같이 두 가지 방식을 사용할 수 있다.

  • Arrays.sort()를 이용하는 경우
  • 직접 정렬알고리즘을 만들어 정렬하는 경우

2.2.1 Arrays.sort()를 이용하는 경우

java에서는 Arrays.sort()메소드를 통해 간단하게 배열을 정렬할 수 있다.
아래는 Arrays.sort() 메소드를 통해 오름차순으로 정렬하는 코드이다.

public class Array {
	public static void main(String args[]) {
		int[] arr = {10, 5, 2, 4, 3};
        
		System.out.println("before sort: ");
		System.out.println(Arrays.toString(arr));
		
        Arrays.sort(arr);
        System.out.println("after sort: ");
		System.out.println(Arrays.toString(arr));
	}
}

output

before sort: 
[10, 5, 2, 4, 3]
after sort: 
[2, 3, 4, 5, 10]

뿐만 아니라 Arrays.sort()는 특정 영역만을 정렬하는 것 역시 지원한다.
특정 영역만을 정렬하기 위해서는 다음과 같이 인자를 입력해야 한다.

Arrays.sort(배열, 정렬_시작점, 정렬_끝점+1);

만약 arr배열의 arr[2]~arr[5]까지 정렬하고 싶다면 인자는 다음과 같이 입력을 하면 된다.
Arrays.sort(arr, 2, 6);

이를 활용해 특정 부분만 정렬하는 코드는 다음과 같다.

public class Array {
	public static void main(String args[]) {
		int[] arr = {10, 5, 2, 4, 3};
        
		System.out.println("before sort: ");
		System.out.println(Arrays.toString(arr));
		
        Arrays.sort(arr, 1, 4);
        System.out.println("after sort arr[1]~arr[3]: ");
		System.out.println(Arrays.toString(arr));
	}
}

output

before sort: 
[10, 5, 2, 4, 3]
after sort arr[1]~arr[3]: 
[10, 2, 4, 5, 3]

이때, 일부분만 정렬한다는 것은 arr[1]에서 arr[3]에 있는 부분인 [5, 2, 4] 에 대해서만 정렬을 실시하게 된다.

2.2.2 직접 정렬 알고리즘을 설계하는 경우

다른 정렬 방법으로는 직접 정렬 알고리즘을 설계해서 정렬을 할 수 있다.
이때, 필자는 간단한 정렬 알고리즘인 버블정렬을 직접 설계를 하면서 직접 정렬을 하도록 하겠다.

버블정렬은 아래 그림과 같이 배열에서 인접한 두 숫자를 비교해 숫자를 하나씩 정렬을 반복하면서 전체 배열을 정렬하는 알고리즘이다.

버블정렬은 배열의 요소가 N개일때 N-1번 반복을 하면서 정렬을 한다. 또한, 오름차순 기준으로 배열에서 가장 큰 숫자부터 차례로 뒤에 정렬을 한다. 즉, 배열에 값이 [5, 4, 2, 1, 3] 순으로 있다고 가정할때, 첫번째 정렬시 [4, 2, 1, 3, 5]가, 두번째에는 [2, 1, 3, 4, 5]가 저장이 된다.
또한, 시간복잡도는 O(N^2)로 이는 만약 배열의 요소가 N개일때 최대 N^2번 연산을 한다는 의미이다. 즉, 데이터가 많아질수록 정렬에 사용되는 연산이 기하급수적으로 많아질 수 있음을 의미한다.

이러한 버블정렬은 다음과 같은 순서로 구현할 수 있다.
1. 정렬 연산이 N-1만큼 반복할 수 있도록 반복문을 만든다.
2. 배열의 첫번째 요소부터 접근해서 N-반복횟수-1 만큼 반복하는 반복문을 만든다. 이때, N-반복횟수-1인 이유는 한번 반복할때마다 큰 수가 배열의 끝에 차례로 정렬이 되기 때문이다.
3. 배열의 두 요소를 비교해서 정렬을 한다.

이를 각각 코드로 나타내면 다음과 같다.
1번과정

public class Array {
    public static void main(String[] args) {
    	int num[] = {10, 50, 30, 20, 40};
    	int i, j, tmp;
    	
    	for(i=0; i<num.length-1; i++) {// 1번
    		
    	}
    }
}

2번과정

public class Array {
    public static void main(String[] args) {
    	int num[] = {10, 50, 30, 20, 40};
    	int i, j, tmp;
    	
    	for(i=0; i<num.length-1; i++) {// 1번
    		for(j=0; j<num.length-i; j++) {// 2번
    			
    		}
    	}
    }
}

3번과정
3번 과정에서는 두 수의 위치를 바꾸기 위해swap이라는 방법을 사용한다. swap은 임시변수 하나를 선언해 두 변수의 위치를 바꾸는 방법으로, 아래와 같이 할 수 있다.
먼저 A값을 임시 변수에 저장을 한다. 이렇게 하면 A와 임시변수인 tmp에 A의 값인 1이 저장이 된다.

다음으로 B값을 A값에 대입한다. 이렇게 하면 B와 A에 B의 값인 2가 저장이 되고, tmp에는 이전의 A값인 1이 저장이 된다.

마지막으로 임시변수에 있던 이전에 저장해뒀던 A값을 B에 저장을 한다. 이렇게 하면 A와 B에 있던 값이 서로 바뀌게 된다.

이러한 방식으로 swap을 할 수 있다. 이를 적용해서 코드를 작성하면 다음과 같다.

public class Array {
    public static void main(String[] args) {
    	int num[] = {10, 50, 30, 20, 40};
    	int i, j, tmp;
    	
    	for(i=0; i<num.length-1; i++) {// 1번
    		for(j=0; j<num.length-1-i; j++) {// 2번
    			if(num[j]>num[j+1]) {// 3번
    				tmp=num[j];
    				num[j]=num[j+1];
    				num[j+1]=tmp;
    				
    			}
    		}
    	}
    	
    	System.out.println(Arrays.toString(num));
    }
}

output

[10, 20, 30, 40, 50]

3. 실습

  • Q1

최댓값(백준 2562)

9개의 서로 다른 자연수가 주어질 때, 이들 중 최댓값을 찾고 그 최댓값이 몇 번째 수인지를 구하는 프로그램을 작성하시오.

예를 들어, 서로 다른 9개의 자연수

3, 29, 38, 12, 57, 74, 40, 85, 61

이 주어지면, 이들 중 최댓값은 85이고, 이 값은 8번째 수이다.

입력:

첫째 줄부터 아홉 번째 줄까지 한 줄에 하나의 자연수가 주어진다. 주어지는 자연수는 100 보다 작다.

출력:

첫째 줄에 최댓값을 출력하고, 둘째 줄에 최댓값이 몇 번째 수인지를 출력한다.

예제입력

3
29
38
12
57
74
40
85
61

예제출력

85
8
  • Q2

과제 안 내신 분..?(백준 5597)

X대학 M교수님은 프로그래밍 수업을 맡고 있다. 교실엔 학생이 30명이 있는데, 학생 명부엔 각 학생별로 1번부터 30번까지 출석번호가 붙어 있다.

교수님이 내준 특별과제를 28명이 제출했는데, 그 중에서 제출 안 한 학생 2명의 출석번호를 구하는 프로그램을 작성하시오.

입력:

입력은 총 28줄로 각 제출자(학생)의 출석번호 n(1 ≤ n ≤ 30)가 한 줄에 하나씩 주어진다. 출석번호에 중복은 없다.

출력:

출력은 2줄이다. 1번째 줄엔 제출하지 않은 학생의 출석번호 중 가장 작은 것을 출력하고, 2번째 줄에선 그 다음 출석번호를 출력한다.

예제입력1

3
1
4
5
7
9
6
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

예제출력1

2
8

예제입력2

9
30
6
12
10
20
21
11
7
5
28
4
18
29
17
19
27
13
16
26
14
23
22
15
3
1
24
25

예제출력2

2
8
  • Q3

바구니 뒤집기(백준 10811)

도현이는 바구니를 총 N개 가지고 있고, 각각의 바구니에는 1번부터 N번까지 번호가 순서대로 적혀져 있다. 바구니는 일렬로 놓여져 있고, 가장 왼쪽 바구니를 1번째 바구니, 그 다음 바구니를 2번째 바구니, ..., 가장 오른쪽 바구니를 N번째 바구니라고 부른다.

도현이는 앞으로 M번 바구니의 순서를 역순으로 만들려고 한다. 도현이는 한 번 순서를 역순으로 바꿀 때, 순서를 역순으로 만들 범위를 정하고, 그 범위에 들어있는 바구니의 순서를 역순으로 만든다.

바구니의 순서를 어떻게 바꿀지 주어졌을 때, M번 바구니의 순서를 역순으로 만든 다음, 바구니에 적혀있는 번호를 가장 왼쪽 바구니부터 출력하는 프로그램을 작성하시오.

입력:

첫째 줄에 N (1 ≤ N ≤ 100)과 M (1 ≤ M ≤ 100)이 주어진다.

둘째 줄부터 M개의 줄에는 바구니의 순서를 역순으로 만드는 방법이 주어진다. 방법은 i j로 나타내고, 왼쪽으로부터 i번째 바구니부터 j번째 바구니의 순서를 역순으로 만든다는 뜻이다. (1 ≤ i ≤ j ≤ N)

도현이는 입력으로 주어진 순서대로 바구니의 순서를 바꾼다.

출력:

모든 순서를 바꾼 다음에, 가장 왼쪽에 있는 바구니부터 바구니에 적혀있는 순서를 공백으로 구분해 출력한다.

  • Q4

평균(백준 1546)

세준이는 기말고사를 망쳤다. 세준이는 점수를 조작해서 집에 가져가기로 했다. 일단 세준이는 자기 점수 중에 최댓값을 골랐다. 이 값을 M이라고 한다. 그리고 나서 모든 점수를 점수/M*100으로 고쳤다.

예를 들어, 세준이의 최고점이 70이고, 수학점수가 50이었으면 수학점수는 50/70*100이 되어 71.43점이 된다.

세준이의 성적을 위의 방법대로 새로 계산했을 때, 새로운 평균을 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 시험 본 과목의 개수 N이 주어진다. 이 값은 1000보다 작거나 같다. 둘째 줄에 세준이의 현재 성적이 주어진다. 이 값은 100보다 작거나 같은 음이 아닌 정수이고, 적어도 하나의 값은 0보다 크다.

출력:

첫째 줄에 새로운 평균을 출력한다. 실제 정답과 출력값의 절대오차 또는 상대오차가 10^2 이하이면 정답이다.

예제입력1

3
40 80 60

예제출력1

75.0

예제입력2

3
10 20 30

예제출력2

66.666667

예제입력3

4
1 100 100 100

예제출력3

75.25

  • A1

문제를 풀기 위해 필요한 요소는 다음과 같다.

  1. 문제에서는 총 9개의 자연수가 주어지므로 이를 저장하기 위한 크기가 9인 배열이 필요하다.
  2. 9개를 입력받는 기능이 필요하다.
  3. 최댓값과 최댓값의 배열 인덱스를 저장하는 변수가 필요하다.
  4. 최댓값을 찾는 기능이 필요하다.
  5. 찾은 최댓값과 최댓값의 인덱스를 저장하는 기능이 필요하다.

9개의 자연수를 저장하는 변수를 arr[]이라 하고, 최댓값을 저장하는 변수를 max, 최댓값 인덱스를 저장하는 변수를 maxIdx라고 하면 다음과 같은 틀이 나온다.

import java.util.*;

public class Q1 {
	public static void main(String[] args) {
		int arr[]=new int[9];
		int max, maxIdx;
		
		Scanner input = new Scanner(System.in);
		
		/*9개 자연수 입력기능*/
		// code...
		
		/*최댓값 찾는 기능*/
		// code..
		
		/*찾은 최댓값 및 최댓값 인덱스 저장 기능*/
		
	}
}

먼저, 자연수의 입력은 매 줄 마다 하나의 자연수가 입력이 되므로 Scanner.nextInt(); 메소드를 사용하면 된다.
총 9번 입력이 진행되므로 반복문을 이용해 입력을 받으면 다음과 같다.

import java.util.*;

public class Q1 {
	public static void main(String[] args) {
		int arr[]=new int[9];
		int max, maxIdx;
		int i;
		
		Scanner input = new Scanner(System.in);
		
		/*9개 자연수 입력기능*/
		for(i=0; i<arr.length; i++) {
			arr[i]=input.nextInt();
		}
		
		
		/*최댓값 찾는 기능*/
		// code..
		
		
		/*찾은 최댓값 및 최댓값 인덱스 저장 기능*/
		
	}
}

다음으로, 최댓값을 찾는 기능은 앞전에서 배운 것과 동일한 방식으로 배열을 순회해서 최댓값을 찾는 방식을 사용할 수 있다.
이를 코드로 구현하면 다음과 같다.

import java.util.*;

public class Q1 {
	public static void main(String[] args) {
		int arr[]=new int[9];
		int max, maxIdx=0;
		int i;
		
		Scanner input = new Scanner(System.in);
		
		/*9개 자연수 입력기능*/
		for(i=0; i<arr.length; i++) {
			arr[i]=input.nextInt();
		}
		
		
		/*최댓값 찾는 기능*/
		max=-1;
		for(i=0; i<arr.length; i++) {
			if(max<arr[i]) {// 최댓값
				max=arr[i];// 최댓값 저장
				maxIdx=i+1;// 최댓값 인덱스 저장
			}
		}
		
	}
}

마지막으로 결과를 출력하면 다음과 같다.

import java.util.*;

public class Q1 {
	public static void main(String[] args) {
		int arr[]=new int[9];
		int max, maxIdx=0;
		int i;
		
		Scanner input = new Scanner(System.in);
		
		/*9개 자연수 입력기능*/
		for(i=0; i<arr.length; i++) {
			arr[i]=input.nextInt();
		}
		
		
		/*최댓값 찾는 기능*/
		max=-1;
		for(i=0; i<arr.length; i++) {
			if(max<arr[i]) {// 최댓값
				max=arr[i];// 최댓값 저장
				maxIdx=i+1;// 최댓값 인덱스 저장
			}
		}
		
		/*결과 출력*/
		System.out.println(max);
		System.out.println(maxIdx);
	}
}

위 코드의 클래스 이름을 Q1에서 Main으로 변경해서 백준에 제출하면 정답임을 확인할 수 있다.

  • A2

이 문제는 흔히 빈도수 문제라고 부르는 문제로, 제한된 입력 범위에서의 입력 빈도수를 구하는 문제이다.
이러한 빈도수 문제는 다음과 같이 해결할 수 있다.

  1. 제한된 입력 숫자의 갯수(크기)만큼 배열을 선언한다.
  2. 입력된 숫자가 인덱스가 되도록 배열에 접근해서 해당 배열의 값을 증가시킨다.
    예를들어 숫자가 1, 2, 1, 3 이렇게 입력이 되면 arr[1]+=1;, arr[2]+=1;, arr[1]+=1;, arr[3]+=1; 이런식으로 하면 빈도수를 구할 수 있다.

물론, 이러한 빈도수 문제는 무조건 인덱스=입력숫자가 되지는 않는다. ex) 알파벳 빈도수등..
하지만 위에서 설명했던 방식을 이용하면 특정 데이터의 빈도를 배열을 이용해 쉽게 알 수 있다.

본론으로 들어가서 빈도수문제를 풀기 위해 크기가 30인 배열을 선언하고 빈도수를 측정해 빈도수가 0인(출석하지 않은 학생) 값을 출력하는 코드를 작성하면 된다.
이때, 출석번호는 1번이 시작이므로 출석번호-1=index가 되야 한다.

이를 코드로 구현하면 다음과 같다.

import java.util.*;

public class Q2 {
	public static void main(String[] args) {
		int student[]= new int[30];
		int i;
		
		Scanner input = new Scanner(System.in);
		
		for(i=0; i<28; i++) {// 총 28명이 출석함
			student[input.nextInt()-1]++;// 빈도수 증가
		}
		
		for(i=0; i<30; i++) {// 총 30명의 학생
			if(student[i]==0) {// 출석 안한 학생 번호
				System.out.println(i+1);// 출석 안한 학생 번호 출력
			}
		}
		
	}
}

위 코드의 클래스 이름을 Q2에서 Main으로 변경해서 백준에 제출하면 정답임을 확인할 수 있다.

  • A3

이 문제는 swap을 이용하는 문제로 동작은 다음과 같다.
만약 입력이 다음과 같다 가정하자.

5 4
1 2
3 4
1 4
2 2

이때, 첫번째 줄은 1부터 시작해서 총 5개의 값을 4번 swap 연산을 하겠다는 의미이다.
그 다음줄에서는 1번째 부터 2번째 까지 아래 그림과 같이 swap 한다.

그 다음줄에서는 아래 그림과 같이 3번째 부터 4번째 까지 swap 한다.

그 다음으로는 1번째 부터 4번째 까지 swap 한다.

즉, 1번 4번 swap, 2번 3번 swap이 일어나는 것이다.

마지막으로 2번째 부터 2번째 까지 swap 한다.

이때는 swap할 것이 없으므로(범위가 같아서) swap이 일어나지 않는다.

범위 내의 swap은 다음과 같이 할 수 있다.
예를들어 배열의 1번째 요소 부터 5번째 요소까지 swap을 한다면 다음과 같이 swap을 한다.

먼저, 요소의 양 끝을 start와 end로 정하고, 이 둘을 swap한다.

다음으로, start를 1 증가시키고, end를 1 감소시킨 다음에 이 둘의 위치에 있는 값을 swap한다.

다음으로, start를 1 증가시키고, end를 1 감소시킨다.

이때, 두 위치가 같으므로 더 swap 할 요소가 없게 되면서 swap을 종료한다.

이와 같은 방식으로 구간의 swap을 할 수 있다.

이러한 내용을 기반으로 문제를 풀면 다음과 같다.

import java.util.*;

public class Q3 {
	public static void main(String[] args) {
		int num[]=new int[100];// 최대 100개의 숫자가 주어짐.
		int n, m;
		int swapStart, swapEnd;
		int tmp;
		int i, j;
		
		Scanner input = new Scanner(System.in);
		
		n=input.nextInt();// n 입력
		m=input.nextInt();// m 입력
		
		
		for(i=0; i<n; i++) {// 배열 초기화
			num[i]=i+1;
		}
		
		for(i=0; i<m; i++) {// swap 범위 입력
			swapStart=input.nextInt()-1;// swap 시작범위
			swapEnd=input.nextInt()-1;// swap 끝 범위
			
			/*범위내에 swap 실행*/
			while(swapStart<swapEnd) {
				tmp=num[swapStart];
				num[swapStart]=num[swapEnd];
				num[swapEnd]=tmp;
				
				swapStart++;
				swapEnd--;
			}
		}
		
		for(i=0; i<n; i++) {
			System.out.print(num[i]+" ");
		}
	}

}

위 코드의 클래스 이름을 Q3에서 Main으로 변경해서 백준에 제출하면 정답임을 확인할 수 있다.

  • A4

이 문제는 과목의 점수 중 최대 점수를 찾아 나머지 점수들을 전부 최대 점수를 기준으로 수정하는 문제로, 다음과 같은 순서를 이용해 풀면 된다.

  1. 과목 갯수 및 점수 입력받기
  2. 최대 점수 찾기
  3. 최대 점수를 기준으로 각 점수를 수정
  4. 합계 및 평균 구하기

이 순서로 문제를 풀면 다음과 같다.

import java.util.*;

public class Q4 {
	public static void main(String[] args) {
		int scores[] = new int[1000];
		int subjectCnt;
		int maxScore=-1;
		float sum=0, mean=0;
		int i;
		
		Scanner input = new Scanner(System.in);
		
		subjectCnt=input.nextInt();// 과목 갯수 입력
		
		for(i=0; i<subjectCnt; i++) {// 과목 점수 입력
			scores[i]=input.nextInt();
		}
		
		for(i=0; i<subjectCnt; i++) {// 가장 높은 점수 찾기
			if(maxScore<scores[i]) {
				maxScore=scores[i];
			}
		}
		
		for(i=0; i<subjectCnt; i++) {// 점수 수정
			sum+=((float)scores[i]/maxScore)*100;// 최대 점수를 기준으로 점수 수정, 점수 합계 구하기
		}
		
		mean=sum/subjectCnt;// 평균점수 계산
		
		
		System.out.print(mean);// 출력
	}
}

위 코드의 클래스 이름을 Q4에서 Main으로 변경해서 백준에 제출하면 정답임을 확인할 수 있다.


위 주소에서 code를 다운로드 받아 eclipse로 직접 정답 확인이 가능하다.
https://github.com/isaiahIM/java_basic/tree/main/array%201D

profile
나는 생각한다. 고로 나는 코딩한다.

0개의 댓글