티스토리 뷰

※ [JAVA로 배우는 자료구조] (3) 배열이란



안녕하세요. 초보개발자 갓준 입니다. 이번 포스팅에서는 자바나 다른 프로그래밍언어를 시작한 많은 사람들이 어려움을 겪는 구간인 기본적이고 간단한 자료구조인 배열에 대해서 설명해드리고자 합니다. 


먼저 자료구조란 무엇일까요? 

자료구조는 데이터 단위와 데이터 자체 사이의 물리적 또는 논리적인 관계입니다. 이 말을 새기시면서 배열을 공부를 시작하셨으면 좋겠고 배열을 공부하는 중에 자료구조라는 단어를 떠올리셨으면 좋겠습니다.


배열(array)이란?

간단한 예를 들어서 배열에 대해서 생각해보겠습니다. 만약 한 반 학생들의 시험 점수를 입력받으려면 어떻게 해야 할까요? 배열을 모른다는 시점에서 가정했을 때는 score1, score2, score3 ... 반 학생들의 점수를 저장할 변수를 모두 선언해 주셔야 할 것입니다. 이런 식으로 코딩을 한다면 어떻게 될까요? 학생 수가 10명 20명일때는 모르겠지만 한 반이 아닌 전체 학급의 점수를 입력받을때는 100개 1000의 변수를 선언해줘야 할 것입니다. 이런 경우 변수이름을 잘못 타이핑할 경우도 생기고, 문제가 많을 것입니다. 이런 경우 활용할 수 있는 자료구조가 바로 배열입니다.


코드레벨에서 생각하기 전에 배열이란 저런 학생의 수만큼을 담을 수 있는 공간을 생성해주는 것입니다. 학생이 100명이라면 100개의 방을 만들어주고, 그곳에 학생들의 점수를 담아주는 것입니다. 그렇게 한다면 몇번째 학생의 점수를 출력하는 것도 편할 것이며 100개의 변수를 선언해주는 것과 달리 하나의 변수를 한줄에 선언해주기 때문에 잘못 타이핑할 경우도 생기지 않을 것 입니다. 이런 자료구조가 바로 배열(array)입니다.


단 배열에는 조건이 있습니다. 가장 중요한 개념인 배열은 같은 자료형의 변수로 이루어진 구성요소로 이루어져야 합니다. 이 뜻은 학생들의 점수를 저장하는 100개의 공간에 학생의 이름이 들어갈 수 없으며, 점수형태로 된 것만 그 방에 들어갈 수 있는 것입니다.


코드레벨로 와서 배열을 알아봅시다. 배열은 먼저 다음과 같은 순서에 의해 사용됩니다.


①배열 선언 → ②배열에 메모리 할당 → ③배열 요소의 사용 


①먼저 배열의 선언은 이렇습니다. 

int[] a;         // int 자료형 배열 생성

  or

int a[];  


char[] b;      // char 자료형 배열 생성

  or

char b[];


String[] c;    // String 자료형 배열 생성

  or

String c[];


double[] d;  // double 자료형 배열 생성

  or

double d[];


배열 선언은 이렇게 할 수 있습니다. 


②이제 배열에 메모리 할당으로써 배열의 방을 만들어주겠습니다.

a = new int[10];        // a는 int형의 10개의 방 생성


b = new char[10];     // b는 char형의 10개의 방 생성


c = new String[10];   // c는 String형의 10개의 방 생성


d = new double[10]; // d는 double형의 10개의 방 생성


위선언으로서 배열의 방을 생성합니다. 이말은 int형을 예로들어 int형의 배열 본체를 생성 후 그것을 변수 a가 "참조"하도록 설정한다는 것입니다. 이뜻은 10개의 방을 곧 int형 a에 연결시킨다는 의미입니다.


③ 마지막으로 배열요소의 사용입니다.

a[0] = 1;                    // 배열의 0번째 방에 1을 넣는다.


b[1] = 'A';                 // 배열의 1번째 방에 'A'를 넣는다.


c[2] = "안녕하세요";    // 배열의 2번째 방에 "안녕하세요"를 넣는다.


d[3] = 3.14159;          // 배열의 3번째 방에 3.14159를 넣는다.

이런의미로 사용합니다. 여기서 어? 0번째 방이요? 저는 10개의 방을 만들었는데 0번째 방도 있나요 그럼 11개 아닌가요?

라고 하실 수 있습니다. 배열의 방은 0번째 방부터 시작됩니다. 처음에 int a[10];을 선언해줬죠? 그건 방의 개수입니다. 각 방에는 번호가 있겠죠. 그 방의 번호는 0부터 시작한다는 소리입니다. 즉 10개의 방을 선언해줬을 경우 0~9 9까지의 방이 생성되는 것입니다.


이제 예제들을 통해서 배열에 대해 더 알아보겠습니다.  

첫번째 예제로 10개의 방에 1~100까지의 숫자중 2의 배수 10개를 방에 담아보겠습니다.



public class Test06
{
	public static void main(String[] args)
	{
		System.out.println("10개의 방에 1~100사이의 2의 배수 10개 넣기");
		int[] a = new int[10];		                // 10개의방(배열) 선언
		int j = 2;					// 짝수로 변할 수, 배열방에 들어갈 숫자

		for(int i=0;i<a.length;i++)
		{
			a[i] = j;				// i번째 방에 j값을 넣어준다.
			j += 2;					// j를 2만큼 증가시킨다.
		}

		for(int k=0;k<a.length;k++)	                // 출력용 for문
		{
			System.out.print(a[k]+ "  ");
		}
		System.out.println();
	}
}

이러한 코드가 나오게 되었는데요. 이 것을 보고 제가 위해서 알려드리지 않아 헷갈리는 부분이 있으실 수 있습니다. 먼저 a.length라는 부분인데요. 자바에서는 배열.length를 사용할 경우 배열의 길이가 반환되게됩니다. 즉 a의 배열은 10이 반환되겠죠? length라는 것을 쓰는데는 이유가 있습니다. 지금은 한개의 배열로만 코드를 구성하고 있지만, 여러개의 배열로 구성한다 가정했을때 for문이나 다른 반복문 사용시 10이나 20같은 숫자를 넣어주게 된다면, 나중에 코드를 다시봤을때는 이게 왜 10이지? 20이지? 많이 헷갈릴 것입니다. 그렇기에 length를 쓴다면 가독성 부분에서나 직접 하나하나 숫자를 입력안해줘도 되는 이점을 가지실 수 있을 것입니다. 


제가 위의 배열 선언부에서 말씀드리지 않은 부분이 있어 추가적으로 말씀드리려 합니다. 

int[] a = new int[5];    // 배열을 선언과 동시에 배열공간 할당하기

int[] b = {1,2,3,4,5};    // 배열 선언과 동시에 값을 할당하기

바로 위의 코드에 보이는 부분인데요. 첫번째로 배열은 선언과 동시에 공간 할당이 가능합니다. 굳이 제가 위해서 설명해드린 것처럼 따로 따로 쓰지 않아도 되는 부분을 설명해드린것이고, 두번째는 배열은 선언과 동시에 값을 할당하는 것이 가능합니다. 따로 따로 값을 넣지 않아도 선언과 동시에 값을 저렇게 할당하게 되면 그 순서대로 1은 0번째 2는 1번째 이런 순서로 들어가는 것입니다. 그럼 여기서 많은 궁금증이 생기실텐데요. 그러면 저 배열은 몇개의 방을 할당받았는지 어떻게 압니까? 방을 몇개 생성할지 모르는데 몇개를 넣어야 하죠? 라는 궁금증들이 생기실 겁니다. 먼저 저 코드는 5개의 숫자를 넣어기 때문에 자동으로 방이 5개가 생성된 다는 것입니다... 

그럼 6개나 7개를 넣으면 그렇게 바뀌나요? 음.. 바뀐다는 표현은 적절하지 못하지만 일단 선언부에서 저렇게 선언을 한다면 값을 할당받은 만큼 방을 생성한다는 뜻입니다. 제가 바뀐다는 표현이 적절하지 못하다는 이유는 바로 이것입니다.


※ 배열 사용 시 주의 사항 : 배열은 절대로 방의 갯수가 바뀔 수 없습니다.


배열은 절대로 방의 갯수가 바뀔 수 없다는 것인데요. 인터넷에 검색을 해보게 되면 동적배열이든 뭐든 배열의 공간을 바꿀 수 있다는 소리가 간혹 있을 것입니다. 이런 것은 틀린 것입니다. 배열은 절대로 방의 갯수가 바뀔수 없습니다. 편법을 써서 바꾸는 방법이 있기는 하지만 그 배열의 방공간을 바꾼다는 의미는 아닙니다. 이런게 안된다는 겁니다. int b[] 가 5개의 공간을 할당받았는데 값을 하나 더 넣고 싶어, 공간 하나를 추가해줘 이런 것이 배열에서는 불가능! 하다는 것입니다.


이제 배열을 더 잘 알기 위해서 예제문제를 몇개 풀어보겠습니다. 제가 자료구조 관련해서 포스팅을 하고 있기에 

첫번째 문제는 배열을 역순으로 바꾸고 출력하여라! 입니다. 이문제는 배열을 뒤에서 부터 출력하여라가 아닌 맨뒤의 값이 제일 앞에오게 하고 맨뒤2번째가 2번째에 위치하도록 이라는 문제입니다. 풀이해보겠습니다.



public class Test07
{
	public static void main(String[] args)
	{
		int[] a = {28,21,10,3,6,9,18};	// 7개의 배열방 생성 및 값 할당
		
		int size = a.length;

		for(int i=0; i<size/2;i++)
		{
			a[i] = a[i]^a[size-i-1];
			a[size-i-1] = a[size-i-1]^a[i];
			a[i] = a[size-i-1] ^ a[i];
		}

		for(int j=0;j<size;j++)
		{
			System.out.print(a[j] + " ");
		}

		System.out.println();
	}
}

7개의 방에 7개의 값을 할당 받고 28과 18, 21과 9, 10과 6을 바꾸면 되겠다는 로직을 생각해 내실 수 있을 것입니다. 그러기 위해서 for문은 i를 0부터 i를 a배열의 길이/2까지 반복하게 합니다. 이것의 이유는 짝수일 경우 반복문의 길이의 반까지 돌려 i를 기준점으로 삼고 양쪽의 값을 바꿔주면 되고 홀수개일 경우도 가운데값 빼고 양쪽 값을 교환하게 합니다. 인터넷에서 찾으시는 코드와 다른 코드 다른 연산자가 있죠? 바로 비트 xor (^)연산자입니다. 제가 국비지원교육을 받을 때 알게 된 꿀팁인데 이것은 정수형 값을 교환할때 굉장히 유익하게 쓰입니다. 비트 xor연산자를 세번 저렇게 사용할 경우 3개의 값이 바뀌게 됩니다. 연산자 수업이 아니니 자세한 설명은 생략하겠습니다. 궁금하신 분들은 직접 써보시면서 보면 알게 되실 것입니다.  


다음은 배열을 이해하신 분들이라면 금방 이해하실수 있는 다차원 배열입니다. 쉽게 설명하기 위해서 필자는 2차원 배열까지만 설명해드리겠습니다. 2차원 배열에서는 행과 열만을 기억하시면 됩니다. 

먼저 1차원배열과의 비교로 설명해드리겠습니다. 정수형 배열 10칸을 생성하겠습니다. 

예) int[] i = new int[10];

(i) 는 10개의 공간을 할당받습니다.

그럼 이런식으로 배열의 공간이 생기겠죠?

■ ■ ■ ■ ■ ■ ■ ■ ■ ■ 


이렇게 말이죠..


그러면 2차원 배열은 어떨가요?


먼저 선언법은 이렇습니다.

int[][] j = new int[5][10];  <- 5개의 행과 10개의 행을 가지는 배열공간 할당 == 50개의 배열공간 할당


그러면 이런식으로 배열 공간이 생성됩니다.

   →10

↓■ ■ ■ ■ ■ ■ ■ ■ ■ 

 5■ ■ ■ ■ ■ ■ ■ ■ ■ 

   ■ ■ ■ ■ ■ ■ ■ ■ ■ 

   ■ ■ ■ ■ ■ ■ ■ ■ ■ 

   ■ ■ ■ ■ ■ ■ ■ ■ ■ 


이런식으로 배열의 공간이 구성됩니다. 무슨 뜻인지 아시겠죠?


네 2차원 배열은 이렇습니다. 이게 단 거 같습니다. 3차원 배열은 개념만 설명해드리자면 사람들이 다 3차원은 면이다 면이다 하는데 저는 그말이 참 어렵더라구요. 그냥 이렇게 이해하시면 될 것 같습니다. 

만약 int[][][] j = new int[2][5][10];

이렇게 된다면 아까 위에서 j배열은 저렇게 공간이 할당된다 했었죠? 저런배열이 2개 생성된다는 뜻입니다.


코드를 통해서 2차원배열을 자세히 알아보겠습니다.


2차원배열의 첫번째 코드로는 바로 1부터 25까지의 저장입니다.



public class Test08
{
	public static void main(String[] args)
	{
		// 배열의 배열 선언과 메모리 할당
		int[][] arr = new int[5][5];
		// 배열에 들어갈 값
		int num=1;
		// 초기화
		for(int i=0;i<arr.length;i++)	//5회반복
		{
			for(int j=0;j<arr[i].length;j++){//5회반복
				arr[i][j]=num;
				num++;
			}
		}

		//배열의 배열 요소 전체 출력
		for(int i=0;i<arr.length;i++)
		{
			for(int j=0;j<arr[i].length;j++){
				System.out.printf("%3d",arr[i][j]);
			}
			System.out.println();
		}
	}
}

바로 이런식으로 2차원 배열은 이루어지는데요. 쉽게 생각했을 때 1차원 배열의 문제는 대부분 for문 한개로 구성이 가능합니다. 왜냐면 배열의 인덱스 즉 방번호의 값을 하나면 넣으면 되니까요. 

예) a[i] = n; 이렇게 말이죠. 2차원 배열의 문제는 방번호가 2개로 되어있습니다. 행과 열 즉 쉽게 방으로 이해해서는 층수라고 생각하시면 됩니다. 1층의 방의 첫번째 방은 [0][0] 2층의 방의 3번째는 [1][2]이렇게 말이죠.  그렇게 해서 for문 2개를 통해 값을 저장시켜 줄 수 있는 것입니다. 만약 3차원이면 for문이 3개겠죠?^^ 맞습니다.


그리고 저 코드에서 궁금하실 부분이 하나 있으실 것입니다. arr[i].length?이건 뭐지? 라고 생각하실수 있습니다. 1차원 배열에서의 length란 배열의 길이만 출력하는 것이었죠. 2차원배열의 배열.length는 곧 행의 수입니다. 그리고 arr[i].length는 곧 행번호에 해당하는 열의 개수입니다. 쉽게 1층의 방의 갯수 2층의 방의 갯수라고 생각하시면 됩니다. 


2차원배열은 따로 문제해결을 하지 않고 마지막으로 배열의 복사에 대해서 배우고 넘어가겠습니다. 

배열은 쉽게 깊은 복사와 얕은 복사가 있습니다.

① 배열의 얕은 복사 -> 주소 값 복사

int[] a = {1,2,3,4,5};

int[] b;

b = a;


② 배열의 깊은 복사 -> 요소 값 복사

int[] a = {1,2,3,4,5};

int[] b;

b = a.clone();


첫번째로 배열의 얕은 복사는 주소 값 복사라고 써있죠. 주소에 대한 개념이 없으신 분들은 저것을 보고 이해를 못하셨을 수 있습니다. 먼저 얕은 복사의 특징은 복사를 통해서 2개의 배열이 값을 공유한다는 것입니다. 이것을 쉽게 생각하면 윈도우의 바로가기랑 비슷하다고 생각하시면 됩니다. a가 원래의 프로그램입니다. b는 바로가기파일 입니다. a가 변경될 경우 b의 바로가기 파일도 변경되겠죠? 그런 개념입니다. 여기서 추가적으로는 바로가기는 수정할 수 없지만 배열은 수정할 수 있기 때문에 b에서 값을 바꾸면 a도 값이 바뀌는 상황이 발생하게 됩니다. 


두번째는 바로 배열의 깊은 복사인데요. 이것은 얕은 복사, 주소복사에서 값의 공유를 뺏다고 생각하시면 됩니다. 즉 a배열 b배열이 따로따로 다른 파일이 되고 b는 a의 배열값만 쏙 빼먹은 것입니다. 여기서는 자바에서 기본적으로 지원해주는 메소드인 clone()을 사용했지만, for문으로 구성해서 직접 배열에 값을 담아줘도 배열의 깊은 복사가 이루어집니다.



이상으로 배열에 대한 설명을 마무리하겠습니다. 글 봐주신 모든 분들께 감사드리고요. 이상 초보개발자 갓준이었습니다. 초보개발자 여러분의 많은 소통 부탁드리고 질문하시면 성심껏 답변해드리니 언제든 질문해주세요~!!!

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함