카톡 친구 자동 삽입하기
카톡 친구 이름과 카톡 횟수를 입력하면 자동으로 위치를 찾아 삽입하는 프로그램이다. 카톡 친구의 초기 정보는 [('다현',200), ('정연',150), ('쯔위', 90), ('사나', 30), ('지효', 15)] 이며, ('친구이름', 연락횟수) 튜플 리스트 형식이다. 새로운 친구 '미나'와 40회를 입력하면 자동으로 자신의 순위에 해당하는 위치를 찾아 삽입된다. 동일한 연락횟수라면 새로운 친구를 앞 순위로 지정한다.
ex)
추가할 친구--> 미나
카톡 횟수--> 40
[('다현', 200), ('정연', 150), ('쯔위', 90), ('미나', 40), ('사나', 30), ('지효', 15)]
추가할 친구--> 혜리
카톡 횟수--> 200
[('혜리', 200), ('다현', 200), ('정연', 150), ('쯔위', 90), ('미나', 40), ('사나', 30), ('지효', 15)]
추가할 친구-->
이 문제는 선형리스트의 데이터 중간 삽입 부분의 예제인데, 파이썬 언어로 표현하도록 했다.
def insert_data(name, count):
if count < 0:
print("잘못된 입력값입니다.")
return
katok_list.append((None,None))
friend_list.append(None)
num_list.append(None)
kLen = len(katok_list)
# 이 부분 다시... 해서 완성.
for i in range (kLen-1, 0, -1):
# 입력받은 값이 전진하려던 위치 값보다 크거나 같으면, 전진 대상 위치를 i위치로 옮겨야 한다.
if count >= num_list[i-1]:
katok_list[i]=katok_list[i-1]
friend_list[i]=friend_list[i-1]
num_list[i]=num_list[i-1]
# 이때 마지막 수행이라면, 입력받은 본인을 마지막 전진 대상 위치인 i-1에 넣으면 끝난다.
if i==1:
friend_list[i-1]=name
num_list[i-1]=count
katok_list[i-1]=(name, count)
return
# 입력받은 값이 전진하려던 위치 값보다 작다면 이미 비어있는 i번째에 입력받은 값인 본인을 넣으면 된다.
elif count < num_list[i-1] :
friend_list[i]=name
num_list[i]=count
katok_list[i]=(name, count)
return
# 전역변수
# katok_list=[('다현',200), ('정연',150), ('쯔위', 90), ('사나', 30), ('지효', 15)]
katok_list=[]
friend_list=['다현','정연','쯔위','사나','지효']
num_list=[200,150,90,30,15]
for i in range (len(friend_list)):
katok_list.append((friend_list[i],num_list[i]))
# katok_list 여기에 각 값이 name과 count라는 걸 어떻게 인식시키지? ==> 그 2개의 자리를 인식시킬 2개의 리스트가 더 필요하다.
if __name__ == "__main__" :
# print(katok_list)
while(True):
friend = str(input("추가할 친구--> "))
num = int(input("카톡 횟수--> "))
insert_data(friend, num) # insert_data 함수 호출-> 위의 함수는 return으로 종료되기 때문에 모두 None으로 반환된다.
print(katok_list) # 출력되길 원하는 값인 katok_list를 따로 print문으로 출력한다.
katok_list라는 리스트에 한 원소가 튜플 형식으로 저장되어 있고, 그 튜플의 값은 사용자로부터 입력받은 2개 원소로 구성될 수 있는 상황이다. katok_list의 한 원소인 튜플을 구성하는 것이 name과 count라는 걸 어떻게 인식시켜야 하나 고민했다. 결과적으로 그 2개의 자리를 인식시킬 2개의 리스트가 어쩔 수 없이 더 필요하겠다는 생각이 들었다. 그렇게 생각하니 수업 시간에 배운 특수 다항식 처리 프로그램에서 지수가 큰 다항식의 처리 방법을 그대로 쓰는 것이었다. 300차 항까지 있는 다항식에서 계수가 0인 차수는 제외하기 위해 항 차수와 각 항의 계수 tx와 px를 각각 리스트로 만들어 매핑하는 방법 말이다.
이 문제는 2차원 리스트 구성으로 튜플이 쓰인 경우이다. 난 오히려 튜플이기 때문에 2차원 리스트로도 못 풀고, 복잡하다고 생각했다. 하지만 알고보니 튜플은 언팩되어 변수로 저장될 수 있어 더 편하다고 한다.
일례로
tx_px_list = [(300, 7), (20, -4), (0, 5)] 와 같이 전역 변수가 선언된다면
def로 정의한 함수 내에서 for term, coef in tx_px_list:와 같이 튜플 안에 있는 원소 (300, 7)을 각각 term, coef라는 변수로 순차적으로 지정할 수 있다는 것이다.
내 방식대로 문제를 다 풀고 나서 모범답안을 보니 이 문제에 대한 내 풀이와 모범답안이 다르다는 걸 알 수 있었다. 모범답안에서는 나처럼 리스트를 추가하는 게 아니라 함수를 2개 쓰는 방법을 사용했기 때문이다. 차라리 내 풀이는 이 다음 응용문제에서 요구하는 방식과 유사했다. 그 다음 문제는 2차원 리스트를 이용하는 풀이이다. 300차 항까지 있는 다항식에서 계수가 0인 차수는 제외하기 위해 항 차수와 각 항의 계수 tx와 px를 각각 리스트로 만들어 매핑할 때 2차원 리스트를 쓰라는 것이다. 그러니 사실상 지금 내 풀이는 2차원 리스트를 이용한 것도, 함수 2개로 명료한 것도 아닌 복잡한 풀이일 뿐이다.
게다가 알고리즘을 배웠으면서 시간복잡도를 고려할 생각조차 하지 못했다. 구글 바드에게 내 코드를 리뷰해달라고 했더니 내 풀이의 시간복잡도는 O(n^2)이니 이분탐색으로 풀어서 O(log n)짜리 시간복잡도를 갖게 하는 것이 좋겠다고 했다. 배운지 한달도 안 된 이분탐색 알고리즘은 떠올리지도 못하고 어떻게든 오류없는 코드 짜기 급급한 나 자신의 수준을 상기했다.
return과 print에 대해서도 다시금 생각해볼 수 있었다. return은 보이지 않게 끊어주는 역할이기에, 코드를 시각적으로 출력하기 위해서는 print문을 반드시 써야 한다. print(함수) 형식으로 "print(insert_data)"를 쓸 경우 그 함수가 끝나는 부분이 return katok_list이라면 내가 원하는 katok_list가 시각적으로 출력된다. 하지만, 그 함수가 끝나는 부분에 return이 없거나 딸랑 return만 있는 경우 반환값은 None이 된다. 결국 "print(insert_data)"의 결과는 내가 원하던 katok_list라는 리스트가 아닌 None이 되는 것이다.
따라서 def 함수 내에서는 해당 함수를 종료하고자 하는 지점에 return만을 표기하고, 시각적으로 출력되길 원하는 값은 메인함수에서 print(katok_list)와 같이 명시적으로 표기하는 것이 좋겠다는 생각이 들었다.