<서론>

한동안 알고리즘을 쉬고 있었다. 사실 한창 할때만큼은 아니라도 하루에 간단한 문제 하나 정도는 풀려고 했었는데, 태생이 나태한 인간이라 정말 몇 개월을 알고리즘 문제 하나 안풀고 보냈다. 그러다 최근 코딩 테스트를 몇 번 보게 될 기회가 생겼는데, 오랜만에 해서 그런지 역시나 제대로 풀 지 못했다. 특히 배열을 파라메터로 사용할 때 얕은 복사 문제가 발생해서, 계속 오답이 나오는 경우가 있었다.

그래서 이 글을 통해 JAVA 배열의 얕은 복사와 깊은 복사에 관해 정리하려 한다.


 

 

<본론>

얕은 복사와 깊은 복사는 자료형이 참조형(Reference type)인 경우에 나뉜다. 기본형(Primitive type)에 경우 값 복사만 이뤄지기 때문에 얕은 복사인지 깊은 복사인지 고민할 필요가 없다.

그래서 참조형의 얕은 복사와 깊은 복사에 대해 알아보자.

 

1. 얕은 복사

얕은 복사는 해당 객체의 주소값을 복사하는 것이다. 결국 객체명은 다를 지언정 같은 값을 참조하는 것이다. 객체명은 다르지만 각 객체의 주소는 같다.

1
2
3
int[] orgArr = {1,2,3,4,5};
int[] copyArr = new int[5];
copyArr = orgArr;
cs

위와 같이 그저 "="로 표시하면 얕은 복사가 된다.

위 코드에서는 얕은 복사가 되었기 때문에 orgArr의 원소 값이 변경되면 copyArr의 값도 같이 변화한다.

orgArr과 copyArr의 주소 역시 동일하다.

1
2
3
4
5
6
7
8
9
10
class Test {
    public static void main(String[] args) {
        int[] test = {1,2,3,4,5}
        methodTest(test);
    }
    
    static void methodTest(int[] arr) {
        arr[1= 99;
    }
}
 
cs

어찌보면 당연한 것일 수도 있지만 위 코드처럼 메소드의 파라미터로 배열을 사용하고

해당 배열을 메소드 내에서 수정한다면 당연히 배열 값도 변경한다.

나는 이 부분에서 원하지 않는 수정이 발생했기 때문에 고생을 했다.

이 부분을 해결하기 메소드 내에 깊은 복사를 진행하고 복사한 배열을 변경하도록 메소드를 수정했다.

 

2. 깊은 복사

깊은 복사는 해당 객체의 값을 복사하는 것이다. 따라서 해당 값을 갖는 또다른 객체를 신규로 생성한다고 생각할 수도 있다. 당연히 각 객체의 주소는 다른 값이다.

1
2
3
4
5
int[] orgArr = {1,2,3,4,5}
int[] copyArr = new int[5];
for(int i=0; i<orgArr.length; i++) {
    copyArr[i] = orgArr[i];
}
 
cs

위 코드처럼 각 원소에 값을 직접 넣는 식으로 작성한다면 깊은 복사가 발생한다. 이 경우 orgArr이 변경되더라도 copyArr의 값은 변경되지 않는다.

 

1
2
3
4
5
6
int[] orgArr = {1,2,3,4,5}
int[] copyArr1 = new int[5];
int[] copyArr2 = new int[5];
 
copyArr1 = Arrays.copyOf(orgArr, orgArr.length);
System.arraycopy(orgArr,0,copyArr2,0,orgArr.length);
cs

반복문을 통해서 직접 값을 입력하는 방법 말고도 위 코드처럼 메소드를 사용하여 깊은 복사를 진행할 수도 있다. for문과 같은 반복문을 통해서 배열을 복사하는 것보다 위와 같은 코드로 배열을 복사하는 편이 좀 더 직관적인 것 같아서 위 방법을 더 사용한다.

https://stackoverflow.com/questions/18638743/is-it-better-to-use-system-arraycopy-than-a-for-loop-for-copying-arrays

 

Is it better to use System.arraycopy(...) than a for loop for copying arrays?

I want to create a new array of objects putting together two smaller arrays. They can't be null, but size may be 0. I can't chose between these two ways: are they equivalent or is one more effici...

stackoverflow.com

Stackoverflow 형님들 글을 보자면, 반복문을 통해서 배열을 복사하는 것보다, System.arraycopy나 Arrays.copyOf가 더 빠른 것을 알 수 있다. 읽기에도, 쓰기에도, 성능에도 더 좋기 때문에 힘들게 반복문으로 쓰지 말자.

 

위의 메소드들을 응용하여 2차원 배열도 깊은 복사를 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
int[][] orgArr = new int[3][5];
int[][] copyArr = new int[3][5];
// orgArr 초기화
for(int i=0; i<orgArr.length; i++) {
    for(int j=0; j<orgArr[i].length; j++) {
        orgArr[i][j] = i*j;
    }
}
 
for(int i=0; i<orgArr.length; i++) {
    System.arraycopy(orgArr[i], 0, copyArr[i], 0, orgArr[i].length);
}
 
cs

위 코드처럼 배열을 원소로 갖는 배열이라고 생각하고, 각 원소를 깊은 복사하면 된다.


 

 

<결론>

원리를 안다면 정말 간단한 문제지만, 가끔씩 깜빡 잊고 넘어가는 부분이다. 이번에 코딩 테스트를 풀면서 이 문제 때문에 정말 아까운 시간만 많이 소비했었다. 평소 알고리즘 공부를 꾸준히 했으면 이런 문제는 일어나지 않았을 것이고, 혹시 똑같이 실수 했더라도 그 실수를 바로 잡는데 시간이 얼마 걸리지 않았을 것이다.

이번 코딩테스트를 하고 난 후 반성의 의미로 이 글을 정리했다. 앞으로는 실수하지 말자..

 

 

<참고자료>

https://dog-foot-story.tistory.com/27

 

[Java] 02. 배열의 복사(Arrays.copy)

배열 복사하는 방법 1. HashCode값 복사 (얕은 복사) scores의 해시코드 값이 scores1, scores2에 복사된다. 스택의 같은 공간에 접근함으로 힙에 담겨있는 값을 가져오게 된다. 따라서 기존 배열인 scores가 변경..

dog-foot-story.tistory.com

 

출처 네이버

평소 수학, 과학 교양 도서를 좋아했기때문에, 다시 독서를 하게 된다면 우선 이런 책들로 읽으려 했다.

최근 과학보다 수학 분야에 관심이 조금 더 생겨서 수학 관련 책을 읽기로 결정했다.

그러다 눈에 띈 책이 이번에 읽은 "숫자 없이 모든 문제가 풀리는 수학책"이다.

목차만 읽었는데도 느낌이 바로 팍 왔다.

이 책은 분명 재밌을 것이다!

책이 얇기도 해서 금방 읽을 수 있을 것 같았다.

 

 

결론부터 말하면 이 책은 약간 실망스러웠다. 책 자체는 읽기 쉬웠고 나름 흥미도 있었는데, 내가 원했던 수학 교양서는 이런 게 아니었다.

좀더 수학 관련된 이야기가 나왔으면 했었는데 아쉬웠다.

이 책의 부제인 '복잔합 세상을 심플하게 꿰뚫어보는 수학적 사고의 힘' 을 염두해두지 책을 접한 것이 실망의 원인이었다.

수학보다는 '수학적 사고' 란 것에 중점을 두고 이 세상을 어떤 식으로 대해야하는가에 대해 서술한 책이었다.

난 수학 그 자체에 대한 이야기를 읽고 싶었던 것인데 나의 이런 욕구를 충족시키지 못해 아쉬었다.

그래도 이 책의 도입부, 수학이 무엇인지에 대해 정의하고 설명하는 부분과 인공지능과 인간의 사고구조의 차이에 대한 부분은 무척 흥미진진했다.

 

수학은 하나의 언어일뿐이며, 수학이 어려운 이유는 수학 우주를 설명하는 언어를 알지 못하기 때문이라는 말은 공감이 가는 말이었다.

누군가 '번역'을 해줄 수만 있다면 충분히 이해할 수 있는 세계지만

수학 언어인 여러 수식이나 기호들을 우리가 알지못하기 때문에 이해할 수 없는 것이다.

난 '번역'을 통해 수학 우주의 일부를 이해하게 되었을 때의 즐거움때문에 계속 수학 교양 도서를 찾고 있다.

 

 

이번에 읽은 "숫자 없이 모든 문제가 풀리는 수학책"은 수학 우주의 또다른 곳을 이해할 수 있게 도와주는 '번역본' 같은 책일 것이라 예상했으나 그런 책은 아니라 아쉬웠다.

수학이란 학문이 어떤 것이며, 앞으로 수학을 어떻게 대해야하는 지에 대한 내 나름에 정의가 생긴 것 같아 읽기 잘한 것 같다.

아무튼 이번 독서도 끝!

'취미 > ' 카테고리의 다른 글

거의 모든 IT의 역사(정지훈 지음, 메디치)  (0) 2020.01.23

출처 네이버

2017년에 알라딘에서 중고로 구매한 책이었다.

주변 지인의 소개로 읽게된 책이었는데 취향과 맞지 않아서 얼마 못 읽고 중단한 책이다.

새해 목표로 책을 1달에 1권은 읽자고 잡아 그 기회로 이 책을 다시 집게 되었다.

목표 달성을 위해 이번엔 중도 하차는 하지 않았지만 이 책 한 권을 읽는데 꼬박 한달이 걸렸다.

 

 

우선 책 소개부터 하자면..

이 책은 70년대 개인용 컴퓨터 출시 이후부터 현재(현재라고 하기엔 책 출판이 2010년이다. 무려 10년 전 이야기)까지 IT 업계에 선두가 되기 위해 실리콘밸리의 기업들이 어떤 식의 전략을 들고 왔고 어떻게 성공했으며, 어떻게 실패했는지에 대해 이야기해준다.

좀더 이야기의 맛을 살리기 위해 딱딱한 역사적 사실을 나열하기보다는 마치 삼국지의 영웅들을 표현하듯 IT 업계에서 큰 영향을 끼친 인물에 대해 표현한다.

책을 읽다보면 우리가 다 알만한 스티브 잡스나 빌 게이츠같은 매우 유명한 사람 말고도 큰 성과를 낸 수많은 인물들이 등장한다. 그리고 각 인물들에 대해서도 간략하게 설명해주는데, 책 한 권을 위해 정말 큰 노력이 있었겠다는 생각이 들었다. 읽다보면 생생하다 라는 느낌을 넘어서 저자의 정보력에 경외심이 들 정도다.

IT업계의 역사에 대해 조금이라도 관심이 있다면 이 책은 정말 재밌게 읽을 수 있는 책임은 분명하다.

 

 

이 책을 처음 시도할 때 얼마 못 읽고 그만 뒀었는데, 1970년 대 개인용 컴퓨터 부분에 대한 이야기가 나에게는 지루했다.

사실 내가 IT에 관심이 가기 시작한 것은 2000년대 중반이 넘어서이고, 사실 2000년 이후에도 컴퓨터와 같은 IT보다는 핸드폰과 같은 디바이스에 관심이 있던터라 책의 앞 부분은 내 머리에 잘 들어오지 않았다.

그 당시에는 IT업계를 주도했던 기업들이었지만 이름을 들어보지 못한 기업들도 있었고, 그 당시에 컴퓨터 상황 얘기들을 들으면서 전혀 공감하지 못했다. 나도 알만한 이야기들이 나오는 2000년 대부터야 머릿속에 이야기들이 제대로 그려지면서 재밌게 읽을 수 있었다.

 

이 책의 시점으로 가장 최근일인 2000년대 후반과 2010년 이야기를 하면서 앞으로의 IT 업계에 대해 저자가 예상하는 글도 읽을 수 있었는데, 어떻게 보면 저자가 예상한 미래를 살고 있는 입장에서 이 글은 굉장히 흥미로웠다. 저자의 예상이 맞고 틀리고도 재미있는 점이긴 했지만, 2010년 이후 '기업들이 왜 이런 서비스나 디바이스를 개발했을까', '이 기업은 자신들의 방향을 왜 이쪽으로 했을까' 와 같은 질문에 대답이 되었다는 것이 제일 재밌었다. 그동안 그저 소비자의 입장에서 속칭 저 기업은 왜 삽질하는 걸까 라고 생각한 적이 꽤나 있었는데, 비록 실패로 돌아갔지만 해당 서비스를 하게 된 기업의 근거가 무엇이었는지 알 수 있었다.

 

 

책 분량으로 보면 절대로 한 달이나 걸릴 책은 아니었지만, 독서가 취미가 아니라 힘겹게 읽은 책 같다. 오래전부터 내 책장에 한 구석을 차지하고 선 언젠가는 해치워야할 숙제였는데, 이제야 그 숙제를 다한 것 같아서 책의 내용과는 별개로 후련하기도 하다.

+ Recent posts