알고리즘&자료구조

for문, do-While문, 입출력, 배열

yoon9 2022. 3. 7. 23:41

 

1. 입력값 중에 최댓값을 구하는 메서드

public class Yoon {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.println("숫자를 입력해주세요.");
        String[] str = br.readLine().split(" ");

        int[] arr = new int[str.length];

        
        for(int i = 0; i < arr.length; i++){
            arr[i] =Integer.parseInt(str[i]);
        }

        int max = arr[0];
        for(int j = 1; j<arr.length; j++){
            

             
            if(max < arr[j]){
                
                max = arr[j];
            }

        }

        System.out.println("최댓값은"+max+"입니다");

        }




    }

 

" "를 기준으로 입력값을 str배열에 잘라서 삽입합니다.

Scanner를 이용하면 간편하지만 성능면에서는 Buffer를 이용한 BufferedReeader보다 느립니다.

입출력 경우에는 성능이라고 보면 속도의 차이라고 봅니다.

이렇게 위와 같이 간단한 예제에서는 차이가 별로 없겠지만 좀 더 많은 데이터들을 입출력을 하는 경우에는 성능차이가 납니다.

 

백준에서 한 번 메모리나 처리속도를 측정해봤습니다

 public static void main(String[] args)throws IOException{
     BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");

        int a = Integer.parseInt(st.nextToken());
        int b = Integer.parseInt(st.nextToken());

        System.out.println(a + b);
        } //BufferedReader를 이용.
        
        
public static void main(String[] args){
          Scanner sc = new Scanner(System.in);

        int a =sc.nextInt();
        int b =sc.nextInt();

        System.out.println(a+b);
        }//Scanner를 이용.

 

코드의 수는 Scanner가 적습니다 하지만,

성능

위에가 Scanner를 이용한 것이고, 밑에가 BufferedReader를 이용한 것입니다.

이렇게 짧은 코드에도 성능차이가 존재합니다.

Scanner는 1KB 크기의 버퍼를 갖기 때문에 입력이 바로 전달이 됩니다. 그 반면에

BufferedReader는 8KB 크기의 버퍼를 가져 buffer에 입력들을 저장하였다 한 번에 전송하기 때문에 속도가 더 빠릅니다. 

그리고 다시 본론으로 돌아와, arr에 입력된 값들을 담아두고 max에 arr배열의 0번째값을 초기화를 해주고,

차례대로 처음부터 배열의 끝까지 검색을 해주면 원래 있던 값보다 클 경우에는 max값을 변경을 해주어 최종적으로 최댓값을 구합니다.

 

 

2. 중간값을 구하는 메서드.

 

 public static int middle(int a, int b, int c) {
        int[] arr = {a, b, c};
        int middle = 0;

        if (a >= b) {
            if (b >= c){
                return b;

            }else if(a <= c){
                return a;

            }else return c;//여기까지는 수가 크면 중간값이 바로 나오고 아니면 다 같은값으로 나오기때문에 아무거나 리턴해도 중간값이다.
        }else if(a > c){
            return a;
        }else if(b > c){
            return c;
        }else return b;

배열의 최솟값과 최댓값을 구하는 것은 전체 탐색하여 값만 바꿔주면되지만,

중간값을 구하는경우는 경우의 수가 13가지가 존재하기때문에 경우의 수만 잘 따져준다면, 어려움이 없이 풀 수 있다.

 

3. 1부터 n까지의 하는 메서드(for,do-while)

 

public class Main {


        public static void main(String[] args){
           	nSum(3); //for문을 이용한 정수의합

            doWhile(2); //do-while문을 이용한 정수의합



}

    public static void nSum(int a){
            int i =0;
            int sum = 0;//값의 합

                for( i = 1; i <= a; i++){
                    sum += i;
                    System.out.println(i);
                }
        System.out.println(i);

    }

    public static void doWhile(int a) {


            int sum = 0;//합
            int i =1;
        do{
            sum += i;
            i++;
        }while (i<=a);


        System.out.println("합은"+sum);
    }

}

for문과 달리 do-while문은 do{}의 부분을 일단 먼저 실행을 한 후에 while문의 조건을 판단을 한 후에 true일 경우에는 계속 do{}영역의 부분을 실행을 하며, while문이 false가 될 때까지 반복된다.

이것이 사전 판단 반복과 사후 판단 반복의 차이입니다.

 

 

4.구구단만들기&별찍기

 

public class Main {

    public static void main(String[] args){
        a(3);//구구단출력.
        b(8);//피라미드형태의 별찍기
    }

    
    public static void a(int n){

        for(int i = 1; i <= n; i++){
            for(int j = 1; j<= n; j++){
                System.out.println(i+"*"+j+"="+(i*j));
            }
        }
    }

    public static void b(int n){

        for(int i = 0; i < n; i++){

            for(int k = 0; k < n-i; k++){
                System.out.print("");
            }

            for(int j = 0; j < i*2+1; j++){
                System.out.print("*");
            }
            System.out.println();
        }

        }


}

위에 코드는 중첩for문을 이용하여 만든 방식입니다.

 

5.배열복사&배열의 역순정리.

public class Main {

    public static void main(String[] args){

        cloneArr(6);//clone메서드를 이용한 배열복사

        String[] a = {"훈이", "유리", "철수", "짱구"}; //임의의 배열선언.
        
        rArr(a);//a의 배열을 역순으로 정리.
    }

    public static void cloneArr(int n){
        int [] a = new int[n];//a의 배열을 만들고

        int j = 0;

        for(int i = 0; i < n; i++){//배열에 값을 1부터 넣어준다.

            a[i] = j;
            j++;

        }

        int[]b= a.clone();//a의 배열을 b로 복제
        for(int c :b){
            System.out.println(c);
        }

    }




    public static void rArr(String[] a ){
        String k =" ";//변수의 값을 바꾸기 위하여 잠시 보관용 변수.
        for(int i = 0; i<a.length/2; i++){
            k = a[i];

            a[i] = a[a.length-1-i];

            a[a.length-1-i] = k;



        }
        for(int i = 0; i < a.length; i++){
            System.out.print(a[i]+' ');
        }



    }



}

 

위에 배열의 역순의 방법은 for문을 이용하여 배열의 첫번째 인덱스와 마지막 인덱스를 계속하여 교체하는방법으로 역순으로 정리할 수 있습니다.

 

두번째로는 배열의 복사인데 자바에서는 배열을 복사하는메서드는 여러가지 존재합니다.

위의 방식은 Object.clone()의 방식을 사용하였습니다.

또 다른 배열복제 메서드는  아래와 같습니다.

 

Arrays.copyOf()

Arrays.copyOfRange()

System.arraycopy()

 

왜 이렇게 배열복사 메서드가 여러가지일까요?

배열의 얕은 복사깊은 복사가 있기 때문입니다.

 

간단한 예를 보면,

 public static void main(String[] args)  {
        int[] n = {1, 2, 3, 4, 5, 6};
        int[] m = n;
        
        System.out.println(Arrays.toString(m)); //->[1, 2, 3, 4, 5, 6]
        
        System.out.println(n); //배열의 주소[I@7c30a502
        System.out.println(m); //배열의 주소[I@7c30a502
        
        n[0] =2;//값 변경.
        
        System.out.println(Arrays.toString(m));//->[2, 2, 3, 4, 5, 6]
    }//배열의 얕은 복사

위에 코드를 보면 얕은복사 일 경우입니다

사실상 복사라는 것 보다는 배열n를 참조하여 사용한다고 생각을 하시면 될 것 같습니다.

배열 n의 값이 바뀌면 배열m도 따라서 똑같이 바뀌며 주소값도 서로 같습니다.

 

 

 

 
 public static void main(Sting[]args){
 		int[] n = {1, 2, 3, 4, 5, 6};
        int[] m = new int[n.length];

        for(int i = 0; i < n.length; i++){
            m[i] = n[i];
        }
        //배열의 깊은복사

        System.out.println(Arrays.toString(m));//[1, 2, 3, 4, 5, 6] 복사완료

        System.out.println(n);//[I@7c30a502 주소값
        System.out.println(m);//[I@49e4cb85

        n[0] =2;
        System.out.println(Arrays.toString(n)); //->[2, 2, 3, 4, 5, 6]
        System.out.println(Arrays.toString(m)); //->[1, 2, 3, 4, 5, 6]
  }

위와 같은 경우는 깊은복사 일 경우입니다

얕은복사와 달리 참조하는게 아니라 그대로 원본의 배열을 그대로 받아서 저장을 하며, 배열의 주소값도 다르며,

원본의 배열의 값이 달라진다고 한들, 복사한 배열은 달라지지 않습니다.

 

 

public static void main(String[] args){


        int[] a = {1,2,3,4,5,6,7};
        int[] b= Arrays.copyOf(a, a[4]);// a의 배열을 a의 원하는 인덱스까지 복사.
        System.out.println(Arrays.toString(b));//->{1,2,3,4,5}

         
         int[] c = Arrays.copyOfRange(a,a[1],a[4]);//배열의 시작점 끝점 지정 할 수있음.
         System.out.println(Arrays.toString(b));//->{3,4,5}
         
         int[] d={12,13,14,15,16,17};
         System.arraycopy(a,0,d,0,3);//(배열원본, 배열원본의 복사시작점, 복사를하여서 받을 배열, 복사시작배열, 복사원소를 받을개수)
         System.out.println(Arrays.toString(d));//->{1,2,3,15,16,17}
}

또 다른 메서드들은 이렇게 위와같이 시작점과 끝점을 지정하여 배열을 복사할 수 있습니다