배열 (Array)

김찬희·2023년 2월 13일
0

KH정보교육원

목록 보기
5/27

JVM 메모리 구조(참고)

▶ 배열

같은 자료형의 변수를 하나의 묶음으로 다루는 것
배열은 저장된 값마다 인덱스 번호가 0부터 시작하여 설정

▶ 배열 선언과 할당

√ 배열 선언

자료형[] 배열명;
자료형 배열명[];

√ 배열 할당

자료형[] 배열명 = new 자료형[배열크기];
자료형 배열명[] = new 자료형[배열크기];
ex)
int[] arr = new int[3];
int arr[] = new int[3];

▶ 배열 저장구조

배열은 참조 변수로 Heap영역에 할당되며 배열 공간의 주소를 저장
배열 공간의 주소를 이용해 인덱스를 참조하는 방식으로 값 처리

▶ 배열 초기화

√ 인덱스를 이용한 초기화

	arr[0] = 1;
	arr[1] = 2;

√ for문을 이용한 초기화

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

※ index가 순차적으로 증가함에 따라 초기화할 리터럴 값이 규칙적이라면 반복문을 통해 배열 초기화 가능
√ 선언과 동시에 초기화

	int[] arr = {1, 2, 3, 4, 5};
    int[] arr = new int[] {1, 2, 3, 4, 5};
    String fruit[] = {"사과", "포도", "참외"};

배열 복사

√ 얕은 복사
객체의 주소 값만 가져와 참조형 변수에 저장하고 하나의 객체를 두 변수가 참조하는 것

√ 깊은 복사
새로운 배열 객체를 생성하여 기존 배열의 데이터를 복사하는 것

package edu.kh.array.ex;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class ArrayEx1 {

	/* 배열 (자료구조)
	 * - 같은 자료형의 변수를 하나의 묶음으로 다루는 것.
	 * - 묶여진 변수들은 하나의 이름(배열명)으로 불러지고
	 *   각각의 변수는 index를 이용해서 구분함
	 * - index는 0부터 시작
	 * */
	
	// 배열 기본 사용법 1
	public void ex1() {
		// 배열 선언
		int[] arr;
		// - int 배열을 참조할 공간 할당하고 이를 arr 이라고 부르겠다.
		// * 기본 자료형 8개를 제외한 나머지는 "참조형" 이라고 한다!
		
		// 배열 할당
		arr = new int[4];
		// - 새롭게 int형 변수 4개짜리 배열을 생성하고 
		//   이를 arr에 대입
		//     -> arr이 해당 배열을 참조
		//     -> 해당 배열을 부를 때 arr 이라고 부르면 됨. 
		
		// 배열 이용
		
		// 1) 배열 각 요소에 값 대입
		arr[0] = 10;
		arr[1] = 30;
		arr[2] = 20;
		arr[3] = 4;
		
		// 2) 배열 각 요소의 값 얻어오기
		System.out.println("arr[0] : " + arr[0]);
		System.out.println("arr[1] : " + arr[1]);
		System.out.println("arr[2] : " + arr[2]);
		System.out.println("arr[3] : " + arr[3]);
		
		System.out.println("==================");
		// 3) for문 + 배열
		int sum = 0;  // 합계
		for(int i=0;i<4;i++) {
			System.out.printf("arr[%d] : %d\n",i,arr[i]);
			sum += arr[i];
		}
		System.out.println(sum);
	}

	// 배열 기본 사용법2 : 초기화
	public void ex2() {
		// 배열 : 같은 자료형의 변수를 하나의 묶음으로 다루는 것
		
		// 1)        3) 2)
		int[] numbers = new int[4];
		// 1) Stack 영역에 int배열을 참조하기 위한 변수 
		//    numbers를 선언 
		
		// 2) Heap 영역에 새롭게 int 4칸짜리 배열을 할당
		//    -> index 번호 추가, 기본값(0)으로 초기화
		//     + 시작주소 부여 ex) 0x5123
		
		// 3) Heap 영역에 생성된 배열의 시작 주소(0x5123)를 
		//    Stack 영역 참조 변수 numbers에 대입한다.
		//    -> numbers가 배열을 참조함
	
		// 1. 정말 numbers에 주소가 저장 되었을까??
		System.out.println(numbers);  // [I@7c30a502 (주소로 만든 숫자)
									  // -> 지금은 주소로 봐도 무관
		
		// 2. 정말 기본값(0)으로 초기화 되었을까?
		System.out.println(numbers[0]);
		System.out.println(numbers[1]);
		System.out.println(numbers[2]);
		System.out.println(numbers[3]);
		// -> 컴파일러가 0으로 초기화 하였음을 확인
		
		System.out.println("=================");
		// 배열 초기화
		
		// 1) 인덱스를 이용한 초기화
		numbers[0] = 100;
		numbers[1] = 5;
		numbers[2] = 300;
		numbers[3] = 99;
		
		// breakpoint : debug모드로 실행 시 해당 줄의 코드가 수행되기 전 멈춤
		System.out.println("=================");
		
		// for문을 이용한 초기화
		
		// ** 배열명.length : 배열의 길이(칸 수)를 반환
		for(int i=0;i<numbers.length;i++) {
			numbers[i]= i * 10 + 1;
		}
		System.out.println("================");
		
		// 선언과 동시에 초기화
		int[] numbers2 = {100, 200, 300, 400, 500, 600};
						 // new 구문 생략
		System.out.println("================");
	}
	
	// 배열 기본 사용법 3
	public void ex3() {
		// 3명의 키를 입력 받아 평균 구하기
		
		// 1번 키 입력 : 170.5
		// 2번 키 입력 : 165.7
		// 3번 키 입력 : 180.4
		
		// 입력 받은 키 : 170.5  165.7  180.4
		// 평균 키 : 172.20cm
		
		Scanner sc = new Scanner(System.in);
		
		double[] heightArray = new double[3];  // 0.0  0.0  0.0
		for(int i=0;i<heightArray.length;i++) {
			System.out.printf("%d번 키 입력 : ",i+1);
			heightArray[i] = sc.nextDouble();
		}
		System.out.print("\n입력 받은 키 : ");
		double sum = 0.0;  // 키 합계 저장용 변수
		for(int i=0;i<heightArray.length;i++) {
			// i = 0, 1, 2
			System.out.print(heightArray[i] + " ");
			
			sum += heightArray[i];
		}
		System.out.printf("\n평균 키 : %.2fcm", sum/heightArray.length);
		
	}
	
	// 배열 기본 사용법 4
	public void ex4() {
		// 오늘의 점심 메뉴 뽑기
//		String[] menuArr = new String[10];
		String[] menuArr = {"김밥+라면", "서브웨이", "KFC", "맘스터치", "순대국", "뼈해장국", "닭갈비", "마라탕", "우육면", "파스타", "샐러드"};
		
		// 0부터 배열 길이의 범위 내에서 난수 발생
		int index = (int)(Math.random() * menuArr.length);
		System.out.println("오늘의 점심 메뉴!! : "+menuArr[index]);
		
	}
	
	// 배열 사용 시 주의사항!!
	public void ex5() {
		
		// 배열의 범위를 넘어선 index를 참조하는 경우
		
		int[] arr = {10,30,50,70,90};
		
		// arr에 저장된 값 모두 출력
		for(int i=0;i<=arr.length;i++) {  // i = 0, 1, 2, 3, 4, 5
			System.out.println(arr[i]);
			
		}
		// Array Index OutofBounds Exception : Index 5 out of bounds for length 5
		// 배열 인덱스 범위초과 예외(에러)
		// : 인덱스 5번은 길이 5짜리 배열의 범위를 초과했다.
		
		
		// 문제점 : for문의 조건식에서 i의 범위가
		//          arr 배열의 인덱스 범위를 초과하는 값까지 
		//          증가하도록 작성되어 실행시 for문 내 출력 구문에서
		//          ArrayIndexOutOfBoundsException이 발생함.
		
		// 해결방법 : 조건식을 i < arr.length로 수정하여 
        //	          i가 배열의 인덱스 범위를 초과하지 않도록 함. 
	}
	
	// 배열 사용법 6 
	public void ex6(){
		// 인원 수를 입력 받아 그 크기만큼의 정수 배열을 선언 및 할당하고
		// 각 배열 요소에 점수를 입력 받아 저장.
		// 입력이 완료되면 합계, 평균, 최고점, 최저점을 출력
		Scanner sc = new Scanner(System.in);
		System.out.print("입력 받을 인원 수 : ");
		int size = sc.nextInt();
		int[] scoreArr = new int[size];
		
		int sum = 0;  // 합계 저장용 변수
		
		// 반복하면서 입력
		for(int i = 0; i<scoreArr.length;i++) {
			System.out.print((i+1) +"번 점수 입력 : ");
			scoreArr[i] = sc.nextInt();
			
			sum += scoreArr[i];
		}
		System.out.println();  // 개행
		
		int max = scoreArr[0];  // 1) 매우 작은 수
								// 2) 배열의 0번 인덱스 값
		int min = scoreArr[0];	// 1) 매우 큰 수
								// 2) 배열의 0번 인덱스 값
		
		// 최고/최저점 인덱스 저장용 변수
		int maxIndex = 0;  // 0번 인덱스
		int minIndex = 0;  
		
		// 최대/최소 구하기
		for(int i = 0;i<scoreArr.length;i++) {
			if(scoreArr[i]>max) {
				// 기존 max(최대값)보다 현재 배열 요소의 값이 더 큰 경우
				max = scoreArr[i];
				maxIndex = i;  // 최고점 인덱스
			} 
			if(scoreArr[i]<min) {
				// 기존 min(최소값)보다 현재 배열 요소의 값이 더 작은 경우
				min = scoreArr[i];
				minIndex = i;  // 최저점 인덱스
			}
		}
		
		System.out.println("합계 : " + sum);
		System.out.println("평균 : " + ((double)sum/size));
		System.out.printf("최고점 : %d (%d번 학생)\n", max, maxIndex + 1 );
		System.out.printf("최저점 : %d (%d번 학생)\n", min, minIndex + 1 );
	}
	
	// 배열 내 데이터 검색
	public void ex7() {
		// 입력 받은 정수가 배열에 존재하면 몇 번 인덱스에 있는지 출력
		// 없으면 "존재하지 않습니다." 출력
		
		int[] arr = {100, 200, 100, 400, 500, 600, 700, 800, 900, 1000};
		
		Scanner sc = new Scanner(System.in);
		int input = sc.nextInt();
//		// 1) 초기값을 인덱스 범위에 포함되지 않는 값을 작성
//		int index = -1;
//		for(int i=0;i<arr.length;i++) {
//			if(arr[i] == input) {  // 입력값과 현재 인덱스 값이 같으면
//				index = i;
//			}
//		}
//		if(index < 0) {  // 일치하는 결과가 없음
//			System.out.println("존재하지 않습니다.");
//		} else {
//			System.out.println(index+1);
//		}
		
		// 2) flag 변수를 이용하는 방법
		int index = 0;
		boolean flag = true;  // 신호 용도의 변수
		// 검색 for문 종료 후
		// flag가 true : 검색 결과 없음
		// flag가 false : 검색 결과 존재
//		
//		for(int i=0;i<arr.length;i++) {
//			if(input == arr[i]) {  // 입력값과 일치하는 값이 존재하는 경우
//				index = i;
//				flag = false;
//				break;  // 일치하는 값을 찾은 경우
//				        // 더 이상 반복하지 않음 (성능 개선)
//			}
//		}
//		if(flag) {
//			System.out.println("존재하지 않습니다.");
//		} else {
//			System.out.println(index);
//		}
		
		// 배열에 같은 값이 있을 때
		for(int i=0;i<arr.length;i++) {
			if(input == arr[i]) {  // 입력값과 일치하는 값이 존재하는 경우
				index = i;
				System.out.println(index+1);
				flag = false;
			}
		}
		if(flag) {
			System.out.println("존재하지 않습니다.");
		}
	}
	
	// 얕은 복사 / 깊은 복사
	public void ex8() {
		// 얕은 복사
		// - 참조하는 배열/객체의 주소만을 복사하여
		//   서로 다른 참조변수가 하나의 배열/객체를 참조함. (공유하는개념)
		
		// 깊은 복사
		// - 원본과 같은 자료형, 크기는 같거나 더 큰 배열을 만들어 
		//   원본의 데이터를 모두 복사하는 방법 (복제의 개념)

		// 얕은 복사 확인
		int[] arr1 = {10, 20, 30, 40, 50};
		int[] copyArr1 = arr1;  // arr1에 저장된 배열 주소값을 복사
								// arr1, copyArr1이 같은 배열 참조
		
		// 1) 참조하는 구조가 같은가?
		System.out.println("arr1 : " + arr1);
		System.out.println("copyArr1 : " + copyArr1);
		
		// arr1 : [I@7c30a502
		// copyArr1 : [I@7c30a502  (같음)
		
		// 2) 복사본의 값을 변경할 경우 원본이 변하는가?
		copyArr1[0] = 9999;
		System.out.println("arr1 : " +Arrays.toString(arr1));
		System.out.println("copyArr1 : " +Arrays.toString(copyArr1));
		
		System.out.println("------------------------------");
		
		// 깊은 복사 확인
		int[] arr2 = {5, 6, 7, 8};
		
		// 깊은 복사를 진행할 arr2 배열과 같은 크기의 배열을 준비
		int[] copyArr2 = new int[arr2.length];
		
		// for문을 이용해서 깊은 복사
//		for(int i=0;i<arr2.length;i++) {
//			copyArr2[i] = arr2[i];
//		}
		
		// System.arraycopy()를 이용한 깊은 복사
		// shift + f2
		
		// System.arraycopy(원본 배열명, 원본 배열 복사 시작 인덱스,
//							복사 배열명, 복사 배열 삽이 시작 인덱스,
//							복사 길이);
		System.arraycopy(arr2, 0, copyArr2, 0, arr2.length);
		
		// 1) 참조하는 주소가 같은가?
		System.out.println("arr2 : " + arr2);
		System.out.println("copyArr2 : " + copyArr2);
		
		// 2) 복사본의 값을 변경할 경우 원본이 변하는가?
		copyArr2[0] = 9999;
		System.out.println("arr2 : " + Arrays.toString(arr2));
		System.out.println("copyArr2 : " + Arrays.toString(copyArr2));
	}
}
profile
김찬희입니다.

0개의 댓글