본문 바로가기

파이썬

[Python] 곱하기 * 를 이용하여 2차원 배열 선언하기

파이썬은 코딩테스트를 처음 준비하는 이들에게 좋다.

 

하지만 아이러니하게도 파이썬 문법을 빠삭히 알지 못하기 때문에 문제를 풀 때 종종 실수를 하기도 한다.

 

오늘은 내가 범했던 실수에 대해 이야기하려 한다.

 

백준 2606 바이러스 문제 풀면서 작성했던 메모

문제 소개

 관련 문제 >>> https://www.acmicpc.net/problem/2606

 

2606번: 바이러스

첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하인 양의 정수이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍

www.acmicpc.net

 

 

 

2중 리스트를 활용해 그래프를 구현해보려고 아래와 같이 초기화 코드를 작성했다.

networks = [[0] * 컴퓨터 개수] * 컴퓨터 개수

#  ------ 내가 원했던 모습
# 0: 연결되지 않은 상태
# 1: 연결이 된 상태

#  ------ 예시
if arr[0][2] == 1 : # 참: 0번 컴퓨터와 2번 컴퓨터는 연결되어 있다.
if arr[0][3] == 0 : # 참: 0번 컴퓨터와 3번 컴퓨터는 접점이 없다.

 

 

하지만 입력값을 받아 반복문을 통해 연결 관계를 확인하던 중 이상한 것을 발견했다.

 

for i in range(connected_sum): # i = 0
    a, b =map(int, sys.stdin.readline().split(" ")) # a = 1, b = 2
    networks[a-1][b-1]=1
    networks[b-1][a-1]=1

 

디버깅 해 보니  i=0 을 지나고 각 배열 요소가 같은 값을 갖고 있었다.

의도한 대로라면 networks[0][1], networks[1][0] 부분만 1로 변경되어야 했다.

실제로는 networks[0][1] 이 변경되면서 networks[1][1] , networks[2][1] ..., networks[6][1]  모두가 1로 바뀌었다.

networks[1][0] 의 값이 변경될 때도 마찬가지.

그래서 이런 결과가 나온 것이었다.

 

이를 보고 생각했다.

 

 

아! 얘네 지금 같은 주소값을 참조하고 있구나!
# 얕은 복사가 일어난다
networks = [[0] * 컴퓨터 개수] * 컴퓨터 개수

# 깊은 복사가 일어난다
networks = [ [0 for _ in range(N)] for row in range(N)]

 

이렇게 변경을 하고 나니 의도한 대로 결과가 진행되었다.

 

 

# Create a list with 5 references of same sublist
MyList = [[]] * 5

for objects in MyList:
    print(id(objects))

#output: id() 는 매개변수의 주소를 출력한다. 포인터 개념이다.

200792200
200792200
200792200
200792200
200792200

위와 같은 코드로 리스트를 선언하게 되면 리스트의 각 리스트가 같은 주소 공간을 가리키게 된다.

이에 흥미를 느끼고 몇 가지를 시도해 보았다.

 

MyList = [[0] * 5] * 5
MyList[0][2] = 1
MyList[0][3] = 5
MyList[0][4] = 1

print("-" * 100)

for objects in MyList:
    for arr in objects:
        print("value: ", arr, end=" ")
        print("  id: ", id(arr), end=" || ")
    print()
    print("-" * 100)

 

처음에는 내부 리스트끼리 동일한 주소 공간을 갖고 있기 때문이라고 생각했다.

하지만 알고 보니 그 리스트 내 요소들끼리도 동일한 주소 공간을 갖고 있었다.

 

이와 관련해 코드를 여러번 돌리다 보니 대략적인 그림이 그려졌다.

 

문제의 코드 라인을 다시 보자

networks = [[0] * 컴퓨터 개수] * 컴퓨터 개수

 

networks[n][:] 은 각각 동일한 주소 공간을 가리키고 있다. ( [0, ..., 0]  의 주소 공간)

때문에 이 주소 공간에 저장된 배열의 값이 변한다면 networks[n][:]은 똑같이 변하게 될 것이다.

 

networks[n][k] 라 칭하게 되면 networks에서 해당 위치에 있는 요소를 자연히 가리키게 되는 것이고

이에 따라 자연스럽게 k번째에 있는 배열 요소의 값이 변화하는 것이다.

 

이는 파이썬의 변수 스코프와도 관련이 있는 듯하다.

 

더 자세한 내용은 다음 포스팅에서 다뤄보도록 하겠다.