JAVA/기본 개념

[JAVA] 배열

soyeonisgood 2022. 7. 16. 13:44

배열의 선언과 초기화

  • - C언어와 다르게 JAVA는 포인터 접근 불가.
  • - 배열은 선언과 메모리 할당 후 사용 가능. 두 개 동시에 해도 됨.
  • - 배열은 선언만 하면 안됨. 꼭 크기를 정해주거나, 초기화해주어야함.
  • ex) int[] a = new int[] {} ; //오류
  • - num[5] 초기화하면 오류 발생. 당연함. num[0]~num[4] 까지밖에 없음. (0~'x-1' 까지 사용)
  • - 정수형 배열은 초기화 하지 않아도 메모리 할당 시 0으로 초기화됨.
  • - 배열은 크기를 변경할 수 없음. 크기 변경되면 이전 배열은 위치를 참조할 수 없어서 garbage collector의 대상이 되어 새로운 배열을 만듬.
  • - 선언과 동시에 초기화 가능. 초기화 하는 경우 초기값 개수가 배열 요소의 수가 됨.
		int[] num; 		   // 1) 배열 선언
		num = new int[5];  // 2) 메모리 할당 (5개 저장할 수 있는 정수형 배열)
		 // num: 배열의 이름. 배열 첫번째 위치의 참조값(주소) 가짐.
		
		int[] num = new int[5];  // 배열 선언과 메모리 할당
		
		// 배열 요소 접근
		// 첨자는 0 ~ "요소수-1" 까지 사용 가능
		num[0]=1; num[1]=3; num[2]=5; num[3]=7; num[4]=9;
		
		// 첨자가 "요소수-1"를 벗어나면 런타임 오류 발생
		//num[5]=11;  // ArrayIndexOutOfBoundsException
		
		// 배열 요소의 수 : length 필드로 요소수를 알 수 있다.
		System.out.println("배열 갯수: "+num.length);

		for(int i=0; i<num.length; i++) {
			s+=num[i];
		}


		int[] a = new int[3];
		a[0]=10; a[1]=20; a[2]=30;
		
		System.out.println("배열의 크기를 3개로 선언하고 값을 할당 후.");
		for(int i=0; i<a.length; i++) {
			System.out.print(a[i]+ " ");  //10 20 30
		}
		System.out.println();
		
		//garbage collector: 메모리 회수의 대상
		a=new int[5];
		a[3]=40; a[4]=50;
		
		System.out.println("\n배열의 크기 5로 변경 후.");
		for(int i=0;i<a.length;i++) {
			System.out.print(a[i]+ " ");  // 0 0 0 40 50
		}

        //두 래퍼런스 변수가 하나의 배열 공유
		int [] a = new int[3];
		a[0]=10; a[1]=20; a[2]=30;
		int[] b = a;
		b[0]+=5;
		b[1]+=100;
		
		System.out.println("\nb 배열...");
		for(int n:b) {
			System.out.print(n+" ");  //15 120 30

		// 배열 선언과 동시에 초기화
		// 선언과 동시에 초기화하는 경우 아래처럼 new int[] 생략 가능.
		int[] a = new int[] {2, 4, 6, 8, 10};
        // 선언과 초기화 따로따로 한다면, new int[] 생략 불가.
		int [] b;
		// b = {1,3,5,7,9}; //컴파일 오류. 
		b = new int[] {1,3,5,7,9};
 

 

 

배열 - 향상된 for문

  • for( 자료형 변수 : 배열명 ) {
  •       // 실행문
  • }
		int[] score = new int[5];
		score[0] = 100; score[1] = 90; score[2] = 80; score[3] = 90;
		score[4] = 90;
		
		int tot=0, ave;
		for(int n : score) {
			tot += n;
		}

배열을 이용한 난수 출력

  • Math.random(): 0<=Math.random()<1 이므로, 1~100까지 난수 출력은 *100 후 +1.
    • 복원 추출
  • 중복 제거를 위해 이중for문 사용하여 i--;
		/*  
		//복원 추출
		int n;
		 for(int i=0; i<10; i++) {
			 n= (int)(Math.random()*100)+1;
			 System.out.print(n+" ");
		 }
		 System.out.println();
		 */

		// 중복 제거
		int[] n = new int[10];
		for(int i=0; i<10; i++) {
			n[i] = (int)(Math.random()*100)+1;
			
			for(int j=0; j<i; j++) {
				if(n[i]==n[j]) {
					i--;
					break; //생략해도 문제는 없지만, 생략하면 불필요한 비교를 하게 됨.
				}
			}
		}

1~10까지의 난수 100개 발생하여 한줄에 10개씩 출력하고, 횟수 카운트

		int[] count = new int[10];
		int n;
		
		for(int i=0; i<100; i++) {
			n = (int)(Math.random()*10)+1;
			count[n-1]++;
			System.out.printf("%3d", n);
			if((i+1)%10==0) {
				System.out.println();
			}
		}
		
		System.out.println("\n숫자별 발생 횟수: ");
		for(int i=0; i<count.length; i++) {
			System.out.println((i+1)+" : "+count[i]);
		}

로또 구매 프로그램

  • 입력 받은 수 만큼 로또 구매
  • 한 개가 끝나면 중복 초기화 후 다음 진행
  • 만약 로또 번호를 정렬하고 싶다면, Arrays.sort(num); 추가. 정렬 포스팅 참고.
		int[] num = new int[6];
		
		int buy;
		Scanner sc = new Scanner(System.in);

		
		do {
			System.out.print("구매 개수 [1-5] ? ");
			buy = sc.nextInt();
		}while(buy<1 || buy>5);
		
		for(int i=0; i<buy; i++) {   //i=0,j=0
			for(int j=0; j<6; j++) {
				num[j] = (int) (Math.random()*45)+1;
				for(int k = 0; k<j; k++) {
					if(num[k]==num[j]) {
						j--;
						break;
					}
				}
			}

            //Arrays.sort(num); //정렬
			System.out.print((i+1)+"번째: ");
			for(int n : num) {
				System.out.printf("%5d", n);
			}
			System.out.println();
				
		}
  • Arrays의 sort는 바로 내림차순 정렬할 수 없음. Integer로 변환해서 정렬해야함.
		int[] num = new int[10];
		for(int i=0; i<num.length; i++) {
			num[i] = (int)(Math.random()*100)+1;
		}
		
		System.out.print("발생된 난수 : ");
		for(int n:num) {
			System.out.print(n+" ");
		}
		System.out.println();
		
		//오름차순 정렬
		Arrays.sort(num);
		System.out.print("오름차순 정렬 후 난수 : ");
		for(int n:num) {
			System.out.print(n+" ");
		}
		System.out.println();
		
		// int를 Integer로 변환
		Integer[] aa = Arrays.stream(num).boxed().toArray(Integer[]::new);
		Arrays.sort(aa, Comparator.reverseOrder());
		for(Integer n : aa) {
			System.out.print(n+" ");
		}

 

년, 월을 입력 받아 달력 출력

  • 칸 수가 맞지 않을 수 있음. 요일칸은 조정이 힘들다.
		Scanner sc = new Scanner(System.in);
		int y, m, tot, w;
		int[] days = new int[] {31, 28, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31};
		
		do {
			System.out.print("년도 ? ");
			y = sc.nextInt();
		}while(y<1);
		
		do {
			System.out.print("월 ? ");
			m = sc.nextInt();
		}while(m<1 || m>12);
		
		// 입력 받은 년도의 2월 마지막 날짜
		days[1] = y%4==0&&y%100!=0||y%400==0? 29 : 28;
		
		//1.1.1 ~ y-1년 12월 31일까지 날 수
		tot = (y-1)*365 + (y-1)/4 - (y-1)/100 + (y-1)/400;
		
		// y년 m-1월 까지 날 수
		for(int i=0; i<m-1; i++) {
			tot += days[i];
		}
		
		// y냔 m월 1일까지 날 수
		tot++;
		
		w = tot % 7;
		
		System.out.printf("\n\t%d년 %d월\n", y, m);
		System.out.println("  일   월   화   수  목   금  토");
		System.out.println("----------------------------");
		
		//1일 앞부분 공백처리
		for(int i=0;i<w;i++) {
			System.out.print("    ");
		}
		
		//1일부터 마지막날짜까지 출력하기
		for(int i=1; i<days[m-1]; i++) {
			System.out.printf("%4d", i);
			if(++w%7 ==0) {
				System.out.println();
			}
		}
		
		if(w%7!=0) {
			System.out.println();
		}
		System.out.println("----------------------------");

		sc.close();
  • 출력 결과

 

 

2차원 배열

  • 자바는 2차원 배열이 존재하지 않고, 배열의 배열이 존재한다.
  • 배열이 다른 배열의 레퍼런스를 참조하는 형태이다.

 

 

가변 배열

  • 2차원배열도 가변배열로 초기화 가능
  • 2차원배열 출력은 향상된 for문으로 잘 안쓴다.
		int[][] a = new int[][] {{10,20,30}, {40,50,60}, {70,80,90}};
		int[][] b = new int[][] {{1,2,3,4}, {5,6}, {7,8,9,10,11}};

		System.out.println("a배열 행 수: "+a.length); // 3
		System.out.println("a[1] 열 수: "+a[1].length); // 3
		
		System.out.println("b배열 행 수: "+b.length); // 3
		System.out.println("b[1] 열 수: "+b[1].length); // 2
		
		System.out.println("a[1][2]: " + a[1][2]);  //60
		//System.out.println("b[1][2]: " + b[1][2]);  // 런타임오류

        // 2차원배열 향상된 for문
		for(int[] rows :a) {
			for(int n: rows) {
				System.out.printf("%5d", n);
			}
			System.out.println();
		}

 

5행 5열의 배열 ㄹ문자 형태로 출력

		int[][] a = new int[5][5];
		int n=0;
		
		
		for(int i=0; i<5; i++) {
			for(int j=0; j<5; j++) {
				n++;
				if(i%2==1) { 
					a[i][4-j] = n;
				} else {
					a[i][j] = n;
				}
			}
		}
		
		for(int i=0; i<5; i++) {
			for(int j=0; j<5; j++) {
				System.out.printf("%5d", a[i][j]);
			}
			System.out.println();
		}

	}
  • 출력 결과

E J O T Y

D I N S X

C H M R W

B G L Q V

A F K P U 

 

 

4행 4열에, 중복되지 않는 무작위 알파벳 출력

  • label 사용해야함.
		char [][]c = new char[4][4];
		
		for(int i=0; i<4; i++) {
			for(int j=0; j<4; j++) {
				c[i][j] = (char)((Math.random()*26)+65);
				
				gogo:
				for(int a=0;a<=i;a++) {
					for(int b=0;b<4;b++) {
						if(a==i && j<=b) {
							break gogo;
						}
						
						//중복문자 검사
						if(c[i][j]==c[a][b]) {
							j--;
							break gogo;
						}
					}
				}
			}
		}
		
		for(int i=0; i<4; i++) {
			for(int j=0; j<4; j++) {
				System.out.printf("%3c", c[i][j]);
			}
			System.out.println();
		}
		
	}
  • 출력 결과

H R M C

P Y B Q

O W N E

J G A S

 

배열의 값 복제 arraycopy()

  • arraycopy ( 원본배열, 원본시작위치, 복사할배열, 복사시킬위치, 복사갯수)
		int[] a = new int[] { 10, 20, 30 };
		int[] b;

		b = a;  // a와 b는 같은 배열. 주소 공유.
		
		b[1]=2000;

		System.out.println(Arrays.toString(a));
		System.out.println(Arrays.toString(b));
		
		System.out.println(a==b);  //동일한 주소


		int[] a = new int[] { 10, 20, 30 };
		int[] b = new int[a.length];
		
		// 배열의 내용 다른 배열에 복사
		// 원본배열, 원본시작위치, 복사할배열, 복사시킬위치, 복사갯수
		System.arraycopy(a, 0, b, 0, a.length); 
		
		System.out.println(Arrays.toString(a));
		System.out.println(Arrays.toString(b));
		
		System.out.println(a==b);  // false. 다른 주소

		String[] s1 = new String[] {"java", "oracle", "html"};
		String[] s2 = new String[6];
		// 숫자배열은 0으로 초기화
		// 객체는 null로 초기화. String은 클래스
		
		System.arraycopy(s1, 0, s2, 1, s1.length-1);
		// s2 => | null | java | orcle | null | null | null

		
		System.out.println("s1...");
		for(String s: s1) {
			System.out.print(s+" ");
		}
		System.out.println();
		
		System.out.println("s2...");
		for(String s: s2) {
			System.out.print(s+" ");
		}
		System.out.println();

 

2차원 배열의 array.copy() 사용 시 주의할 점

  • - 2차원배열에서는 값이 아닌 주소가 복사됨.
  • - a배열
    • a<-0x100 0x100|0x110| ---> 10 20 30
    •                           |0x150| ---> 40 50 60
  • - arraycopy 후 b배열
    • b<-0x200  0x200|0x110|
    •                            |0x150|
  • - 값의 주소를 복사해야함.
		int[][] a = new int[][] {{10,20,30},{40,50,60}};
		int[][] b = new int[a.length][a[0].length];
				   // new int[2][3]
		
		System.arraycopy(a, 0, b, 0, a.length);  
			// 2개만 복사. 2차원 배열은 주소를 복사. 
		
		System.out.println("a 배열...");
		for(int i=0; i<a.length; i++) {
			for(int j=0; j<a[i].length; j++) {
				System.out.print(a[i][j]+" ");
			}
			System.out.println();
		}
		
		System.out.println("b 배열...");
		for(int i=0; i<b.length; i++) {
			for(int j=0; j<b[i].length; j++) {
				System.out.print(b[i][j]+" ");
			}
			System.out.println();
		}
		
		b[1][1] = 200;
		System.out.println(a[1][1] + ":" + b[1][1]);  // 200 : 200
  • 아래 코드와 같이 수정하여 for문을 사용해 값의 주소를 복사해야함.
		// for문 사용하여 값의 주소 복사
		for(int i=0; i<a.length; i++) {
			System.arraycopy(a[i], 0, b[i], 0, a[i].length);  
		}