어제 배열을 배우고 오늘은 그 마무리를 하는 시간을 가졌다.
배열을 공부하며 느낀 것은 만든 배열을 추상화하는 연습을 해야한다는 것이었다.
또 백준에서 배열 문제를 풀어보면서, 배열 자체로 쓰는 것보다 변수를 이용해서 응용하는 것이 가독성, 활용면에서 좋다고 생각했다.
결국 자료구조를 연습하는 것 밖엔 답이 없다.
- 배열 마무리 : Swap 기법
- Method
Swap
이라는 개념은 사실 매우 간단해서 기법이라 부르기에도 애매하다.
하지만 막상 변수 2개 던져주고 서로 값을 바꾸는 코드를 짜라고 한다면 뇌정지가 쉽게 온다.
나도 천연 문과생으로서 이거 때문에 4시간을 고민한 적이 있다. 그러나 막상 해결법을 알았을 때 찾아오는 스스로에 대한 반성이란..
Swap
은 주로 배열의 정렬 sorting
과 중복 방지를 위해서 주로 다음과 같이 사용한다.
int milk = 10;
int tea = 20;
int cup = 0;
cup = milk;
milk = tea;
tea = cup;
변수로 다음과 같이 Swap
을 하면 cup
에 저장한 milk
의 값을 tea
에 옮겨줄 수 있다.
그래서 배열에 있어서도 다음과 같이 사용한다.
int[] arr = new int[] {1, 2};
System.out.println(arr[0]);
System.out.println(arr[1]);
int tmp = arr[0];
arr[0] = arr[1];
arr[1] = tmp;
위 코드를 유심히 보면, 하나의 규칙을 볼 수 있다. 바로 index
의 값이 1씩 증가한다는 것이다.
따라서 정렬을 할 때는 for
와 함께 사용한다.
int[] arr = new int[] {21, 42, 54, 6, 21};
for (int i = 0; i<arr.length-1; i++) {
for (int j = 0; j<arr.length-1; j++) {
if (arr[j]>arr[j+1]) {
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
} else {
continue;
}
}
}
정리하면 위 배열을 오름차순으로 정렬하기 위해선 두 값을 비교해서 작은 것을 앞으로 큰 것을 뒤로 보내줘야 한다. 논리적으론 index[0]
부터 비교를 시작하여 왼쪽 값이 오른쪽 값보다 클 시 Swap
을 이용하여 자리를 바꿔준다.
하지만 이는 1회에 끝나지 않는다. 그래서 위 코드를 1회 반복을 하면 {21, 42, 6, 21, 54}
가 된다. 따라서 배열의 총 길이 - 1
만큼 반복을 해줘야 한다. 물론 마지막 회전은 공회전이 될 가능성이 높다.
이런 문제를 응용하여 배열을 무작위로 뽑는 실습을 진행했다.
// 셔플
for (int i=0; i<arr.length*10; i++) {
x = (int)(Math.random()*5);
y = (int)(Math.random()*5);
int tmp = arr[x];
arr[x] = arr[y];
arr[y] = tmp;
}
// 뽑기
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
문제를 풀면서 겪었던 난항은 카드를 섞는다는 개념이 그저 무작위 난수를 인덱스로 하여 뽑는 것이었다. 하지만 난수는 범위 안에서 아무거나 나오기 때문에 중복되는 수가 뽑힐 수 있다.
그래서 중복 없이 뽑기 위해선 하나의 가정이 필요했다.
- 섞는 행위와 뽑는 행위를 나눈다.
- 값은 배열 안으로 한정한다.
물론 반복문을 통해 섞는 행위와 뽑는 행위를 동시에 진행할 수 있다.
하지만 중요한 것은 두 행위는 구분되어야 한다는 것이다.
구체적으로 배열 안의 모든 수를 무작위로 섞을 경우, 해당 배열 안에 중복되는 값은 조건2
에 의해 존재하지 않는다. 하지만 뽑는 것은 고정된 부분을 뽑아야 한다.
예를 들어 카드를 뽑는다고 치자.
1~5개의 카드를 섞지만 우리는 앞의 3장만 뽑을 것이다.
고로 각 카드의 값이 똑같지 않다는 가정 하에 중복되는 카드는 뽑히지 않는다.
Method
는 굉장히 중요하다. 따라서 기본부터 제대로 이해해야 Method
를 사용할 수 있다.
그럼 Method
는 뭘까?
Function(C) == Method(Java)
Sub Routine == Method(Java)
Method
는 'C언어'에선 Function
으로 'Pearl' 같은 언어에선 Sub Routine
이라 부른다.
이는 Method
가 코드의 흐름을 밖으로 빼냈다가 다시 본 흐름으로 돌려주기 때문이다.
물론 단번에 이해하기는 어렵다 따라서 Method
를 만들어 보면서 이해하자.
먼저 Method
는 우리가 주로 프로그램 실행에 사용하는 main()
에 모든 코드를 넣는 것을 원하지 않는다. 오히려 main()
은 하나의 바탕일 뿐, 그것을 채워주는 각각의 Method
의 활용이 필요하다.
일단 이를 비유하자면 다음과 같다.
클래스는 하나의 “회사”이고
main()
메서드는 사장이다.
main()
이 일을 할 때는 외부의 메서드를 고용한다.
따라서 Method
는 main()
의 밖에 작성되고 이를 '메서드 선언부'라 한다.
public static int plus(int num1, int num2){
int result = num1 + num2;
return result;
}
public static void main(String[] args) {
먼저 Method
를 만들기 위해선 다음의 방법을 따르자.
Method
의 이름을 정한다.Method
에 받아들일매개변수
를 정한다.Method
가 호출 시, 실행할 코드를 작성한다.return
을 통해서 반환할 값을 정해준다.- 그리고 그에 따른
return Data type
을 정해준다.
위를 통해 만들어진 바깥의 plus
를 이용하기 위해선 main()
은 내부에서 호출을 해야하며 이를 method call
이라고 한다.
그리고 호출 시, Method
는 Stack
에 쌓이고 그 위에 사용자로부터 입력 받은 Argument
가 들어가서 코드를 실행 후, 값을 호출됐던 그 자리로 반환하게 된다.
int plus(int num1, int num2) { // (반환 자료형) 메서드 명 (매개변수부)
int result = num1 + num2;
return result; // 코드의 흐름을 main으로 돌리고, result 결과값도 함께 보내라.
}
따라서 Method
를 사용할 때는 다음을 주의하자.
- 코드 흐름
Method
매개변수
인자값
지역변수
- 반환
return
과 반환자료형return DataType
- 선언부, 호출부
만약 매개변수
가 없다면, 호출 후 알아서 동작을 한 뒤 반환을 한다.
그리고 method
는 직접 만들어 쓰는 메서드를 ‘사용자 정의 메서드’와 처음부터 제공하는 ‘내장-시스템 메서드’가 있다. 이때, 자동 완성으로 보여지는 Method
의 매개변수와 리턴값, 이름을 보고 기능을 유추할 수 있도록 노력해야 한다.