Java의 자료구조에 대해 알아보자.
어떠한 데이터를 프로그램적으로 관리할 때, 비용을 절감하는 것이 중요하다.
예를 들어 데이터를 검색할 때 , 정렬할 때, CRUD를 할때 등등
프로그램을 짤 때 비용이란, 1) 메모리 2) CPU(속도) 를 의미한다.
메모리를 적게, 속도를 빠르게 할 수록 비용이 절감된다.
그러나 둘 모두를 적용시킬 수는 없다.
메모리를 적게쓰면 속도가 느려지고, 메모리를 많이쓰면 속도가 빨라진다.
Java의 자료구조 특징은 이미 만들어진 라이브러리를 활용하는 경우가 많다는 것이다. 이에 반해 C는 보통 자체적으로 구현하는 경우가 많다.
Java로 자료구조를 배우는 것과 관련해 Do it! 자료구조와 함께 배우는 알고리즘 입문 자바 편 책을 추천받았다.
비용이 최소화 될 수 있도록 간단한 코드를 작성해보자.
아래의 코드는 랜덤으로 주어지는 3개의 숫자 중 최댓값을 찾는 코드이다.
public class Hello {
static int m1(int a, int b, int c) {
//표준함수 없이 작성
int max = a;
if(b>max) {max = b;}
if(c>max) {max = c;}
return max;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) { //검증을 위한 반복
//1: 최댓값 찾기
int a = new Random().nextInt(100);
int b = new Random().nextInt(100);
int c = new Random().nextInt(100);
int max = m1(a, b, c);
System.out.println(max + ":" + a + " " + b + " " + c);
System.out.println(max);
}
}
}
아래의 코드는 랜덤으로 주어진 3개의 숫자 중 가운데값을 찾는 것이다.
public class Hello {
public static void main(String[] args) {
int a = new Random().nextInt(100);
int b = new Random().nextInt(100);
int c = new Random().nextInt(100);
int m;
if(a>b) { //a가 max or med
if(a>c){ //a가 max
if(b>c) {
m = b;
}else m = c;
} else m = a;
}else { //a가 min or med
if(a<c) { //a가 min
if(b>c) {
m = c;
}else m = b;
} else m = a;
}
System.out.println(m + ":" + a + " " + b + " " + c);
}
}
위 코드에서 최적화를 진행하면, 기존에 존재하는 Math.max()를 활용하여 다음과 같이 수정 가능하다.
public class Hello {
public static void main(String[] args) {
int a = new Random().nextInt(100);
int b = new Random().nextInt(100);
int c = new Random().nextInt(100);
int m;
if(a>b) { //a가 max or med
if(a>c){ //a가 max
m = Math.max(b, c); //m = b>c?b:c;
} else m = a;
}else { //a가 min or med
if(a<c) { //a가 min
m = Math.min(b, c); //m = b>c?c:b;
} else m = a;
}
System.out.println(m + ":" + a + " " + b + " " + c);
}
}
추가로 if-else문을 삼항 연산을 활용하면 아래의 코드처럼 작성할 수도 있다.
public class Hello {
public static void main(String[] args) {
int a = new Random().nextInt(100);
int b = new Random().nextInt(100);
int c = new Random().nextInt(100);
int m;
if(a>b) { //a가 max or med
m = (a>c) ? Math.max(b, c) : a;
}else { //a가 min or med
m = (a<c) ? Math.min(b, c) : a;
}
//한번 더 적용하면
// m = (a>b)
// ? (a>c) ? Math.max(b, c) : a
// : (a<c) ? Math.min(b, c) : a;
System.out.println(m + ":" + a + " " + b + " " + c);
}
}
어떠한 프로그램을 작성할 때는, 문제 해결 -> 라이브러리 화(함수생성) -> 여러 testcase를 통한 점검 순으로 진행하는 것이 좋다.
아래의 코드는 누적하여 더하기 및 곱하기를 구현한 코드이다.
먼저 main 함수안에 구현하고, 함수로 빼고, for문을 통해 testcase를 실행하면 된다.
public class Hello { //문제 해결 -> 라이브러리 화(함수생성) -> 점검
static int m1(int num) {
int sum = 0;
for (int i = 1; i <= num; i++) {
sum += i;
}
return sum;
}
static int m2(int num) {
int sum = 1;
for (int i = 1; i <= num; i++) {
sum *= i;
}
return sum;
}
public static void main(String[] args) {
System.out.println(m1(100));
System.out.println(m2(5));
}
}
자바에서 2차원 배열은 기본적으로 int[][] br = new int[3][4]; //new int[세로길이][가로길이];
형태를 가진다.
또한 printf를 활용하면 다양한 format으로 배열을 출력 할 수 있다.
public class Hello {
public static void main(String[] args) {
int[] ar = new int[10];
int[][] br = new int[3][4]; //new int[세로길이][가로길이];
System.out.println(br.length); //세로 길이를 얻는다.
System.out.println(br[0].length); //가로 길이를 얻는다.
//세로로 탐색
for (int i = 0; i < br.length; i++) { //세로 제어
for (int j = 0; j < br[i].length; j++) { //가로 제어
br[i][j] = i * br[i].length + j;
}
}
//출력
for (int i = 0; i < br.length; i++) { //세로 제어
for (int j = 0; j < br[i].length; j++) { //가로 제어
System.out.print(br[i][j] + " ");
} System.out.println();
}
//printf 사용
System.out.printf("%d호랑이\n", 88);
System.out.printf("%d호랑이%d\n", 88, 99);
System.out.printf("%4d호랑이%4d\n", 88, 99);
System.out.printf("%04d호랑이%04d\n", 88, 99);
for (int i = 0; i < br.length; i++) { //세로 제어
for (int j = 0; j < br[i].length; j++) { //가로 제어
System.out.printf("%2d", br[i][j]);
} System.out.println();
} System.out.println();
for (int[] is : br) {
for (int data : is) {
System.out.printf("%2d", data );
} System.out.println();
} System.out.println();
}
}
10개의 숫자가 담긴 배열이 있을 때, index 0번과 9번을 교환하고, 1번과 8번을 교환하는 코드를 작성해보자.
이와 같은 프로그램은 주로 순차 정렬이 되어 있는 배열에서 역순 정렬으로 바꿀때 사용한다.
public class Hello {
public static void main(String[] args) {
int[] ar = new int[10];
for (int i = 0; i < ar.length; i++) {
ar[i] = new Random().nextInt(100);
}
for (int i = 0; i < ar.length; i++) {
System.out.print(ar[i] + " ");
} System.out.println();
// t = a;
// a = b;
// t = t;
for (int i = 0; i < ar.length/2; i++) {
int temp;
temp = ar[i];
ar[i] = ar[ar.length-1-i];
ar[ar.length-1-i] = temp;
//System.out.println(i + " " + (ar.length-1-i));
} System.out.println();
for (int i = 0; i < ar.length; i++) {
System.out.print(ar[i] + " ");
} System.out.println();
}
}
이번에는 소수를 출력하는 프로그램을 작성해보자.
public class Hello {
public static void main(String[] args) {
for (int num = 0; num < 100; num++) {
boolean isPrime = true;
for (int i = 2; i < num / 2; i++) { // 대칭이므로 num길이 전체를 볼필요가 없고, 절반만 확인하면 된다.
if (num % i == 0) {
isPrime = false;
break;
}
}
if (isPrime)
System.out.println(num + " : ");
// System.out.print(num + " : ");
// System.out.println(isPrime ? "소수이다" : "소수아님");
}
}
}
마지막으로 1월 1일부터 12월 31일까지의 달력을 출력하는 프로그램을 작성해보자.
이때 주어진 정보는 다음과 같다.
1) 2023년 1월 1일은 일요일이다.
2) 윤달이 없다고 가정한다.
3) 매월 일수는 31 28 31 30 31 30 31 31 30 31 30 31이다.
public class Hello {
public static void main(String[] args) {
int InitDay = 0;
int[] Month = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
for (int a = 0; a < 12; a++) {
System.out.println(a + 1 + "월달 달력");
System.out.println("일 월 화 수 목 금 토");
for (int b = 0; b < InitDay; b++)
System.out.print(" ");
for (int b = 0; b < Month[a]; b++) {
System.out.printf("%2d ", b + 1);
if ((InitDay + b) % 7 == 6) {
System.out.println();
}
}
InitDay = (InitDay + Month[a]) % 7;
System.out.println("\n");
}
}
}
결과는 다음과 같다.
핵심은 매월 시작 요일을 구하는 것이라고 생각된다.