강해져서 돌아온 ChatGPT에게 코딩을 시켜보자 (2)

1편은 여기로 가시면 됩니다.

지금은 잘되는 걸 보면 아까는 서버 문제였나봄. 근데 지금도 네트워크 에러가 간간이 일어나는게 얘네 서버실에 커피 엎은 것 같음.


(아까 시키려던거) 입력받은 문자열 출력하기

input_string = input("문자열을 입력하세요: ")
print("입력한 문자열은", input_string, "입니다.")

가장 간단한 방식은 input()이지만, 사실 내가 알고싶은 건 이게 아니였다… 그럼 본론으로 들어가서 물어봅시다.

import sys

input_string = sys.stdin.readline().rstrip()  # 입력받은 문자열에서 개행 문자 제거
print("입력한 문자열은", input_string, "입니다.")

설명까지 잘 보면 알겠지만 sys.stdin.readline()이 input보다 빠른 대신 포기한 두가지 중 한가지(개행문자 안뗌)에 대해 언급하고 있다. 또한 sys.stdin.readline()을 이용하려면 import sys가 우선시되어야 하는 것도 잘 알고 있다.

2차원 배열 만들기

1차원 배열은 1편에서 만들었던 리스트가 1차원 배열이고, 2차원 배열은 그거 여러개를 나열해둔 것이라고 보면 된다. 일반적으로 생각하는 점(0차원)->선(1차원)->면(2차원)->입체(3차원)로 확장하는 것과 비슷한데, 리스트를 쌓으면 2차원 배열, 2차원 배열을 쭉 쌓으면 3차원 배열이 된다.

일단 첫번째로는 1부터 25까지 순차적으로 들어가는 5*5 배열을 만들어보자.

네트워크 에러가 뜬 후 한번 다시 만들어서 출력이 다르다. 처음 만들어 준 코드는 아래 코드가 맞다.

# 5x5 크기의 2차원 배열 생성
array_2d = []
for i in range(5):
    row = []
    for j in range(5):
        row.append(i*5 + j + 1)
    array_2d.append(row)

# 2차원 배열 출력
for row in array_2d:
    print(row)

네트워크 에러가 떠서 확인해보려고 미리 코드만 복사했었는데 2차원 배열을 생성하는 것 뿐 아니라 보기 좋게 출력하는 방법까지 제시하고 있다. 이게 왜 중요하냐면 저 코드에서 그냥 print(array_2d)로 하게 되면

[[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]]

솔직히 저거 5*5 배열이니까 스무스하게 넘어가는거지 8*8이나 9*9배열에서 이렇게 출력했다간 욕 바가지로 먹고 여러분들 불로장생 할 수도 있음… 진짜로.

그럼 이번에는 리스트 컴프리헨션으로 정사각형 배열이 아닌 직사각형 배열을 만들어보자.

array_2d = [[j + 1 + i * 8 for j in range(8)] for i in range(6)]
print(array_2d)

역시나 좀 더 깔끔하게 뽑고 싶다면 for문을 사용하면 된다. 이 방식은 위처럼 2차원 배열을 만드는 건 동일한데, for문 두개+몇줄을 차지하던 걸 리스트 컴프리헨션으로 한 줄로 깔끔하게 줄여버린 것.

함수 정의하기

함수 정의가 뭐냐면 def 어쩌고로 정의하는 그거다. 근데 얘네 서버실에 진짜 누가 커피라도 쏟은건가… 에러때문에 뭘 제대로 할 수가 없음.

def add_subtract(x, y):
    # 합 계산
    add = x + y
    # 차 계산
    subtract = x - y
    # 결과 출력
    print("합:", add)
    print("차:", subtract)

간단한 함수의 정의도 매우 잘 한다. 합, 차를 구하는 함수를 만들어달래서 print문까지 같이 준건데 합따로 차따로 하는거면 리턴으로 반환했을지도…?

별찍기

for i in range(1, 8):
    print("*" * i)

어… 이것도 별찍기 맞긴 맞는데… 그 가운데정렬은 뭐라고 해야 됨?

for i in range(1, 8):
    print(" " * (7-i) + "*" * (2*i-1))

정답: 피라미드

배열 탐색

이건 뭐냐면 난수 10개가 들어있는 1차원 배열에서 제일 큰 수를 찾는 방법을 묻는 것이다.

import random

# 1부터 100 사이의 랜덤한 숫자 10개를 가지는 리스트 생성
arr = [random.randint(1, 100) for _ in range(10)]

# 리스트에서 최댓값 찾기
max_num = max(arr)

print(arr)  # 리스트 출력
print("제일 큰 수:", max_num)  # 최댓값 출력

일단 여기서 두가지 짚고 넘어갈 게 있다. 첫번째로, 1편에서 리스트를 만들때는 리스트라고 했는데 이번에 질문할때는 랜덤한 숫자 10개가 들어간 1*10 ‘배열’이라고 했고 두번째로는 최댓값을 찾기 위해 적절한 모듈을 얘가 골라서 썼다는 것. 그럼 혹시 최댓값이 들어있는 ‘위치’를 출력할 수도 있는지 한번 보자. 이거 혹시 백준 빌드업?

import random

# 1부터 100 사이의 랜덤한 숫자 10개를 가지는 리스트 생성
arr = [random.randint(1, 100) for _ in range(10)]

# 리스트에서 최댓값 찾기
max_num = max(arr)

# 최댓값이 있는 위치(인덱스) 찾기
max_index = arr.index(max_num)

print(arr)  # 리스트 출력
print("제일 큰 수:", max_num)  # 최댓값 출력
print("최댓값의 위치:", max_index+1)  # 최댓값의 위치(인덱스+1) 출력

2차원 배열에서 어떻게 하는지까지 물어보면 ㄹㅇ 백준 빌드업 되니까 패스… 근데 값을 넣고 인덱스 찾는 법이 있긴 있었구나… 했는데 저거 문자열에서 찾는거네???

정렬 알고리즘

이게 종류가 많은데 일일이 다 하다간 서버 뻑나서 내 혈압이 오를 것 같으니 병합정렬이랑 퀵, 힙, 트리(이진 트리를 만들어서 정렬한다는데 뭔지 궁금했음)만 해보자. (당연하지만 2차원 배열에는 안통함)

병합 정렬

import random

def merge_sort(arr):
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    left = arr[:mid]
    right = arr[mid:]

    left = merge_sort(left)
    right = merge_sort(right)

    return merge(left, right)

def merge(left, right):
    result = []
    i, j = 0, 0

    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    if i < len(left):
        result += left[i:]
    if j < len(right):
        result += right[j:]

    return result

arr = [random.randint(1, 100) for _ in range(10)]
print("Before sort:", arr)

sorted_arr = merge_sort(arr)
print("After sort:", sorted_arr)

본문

병합정렬(merge sort)은 분할정복(divide and conquer) 알고리즘 중 하나로, 배열을 반으로 나눈 뒤, 나눈 각 부분을 재귀적으로 정렬하고, 그 결과를 병합하여 전체를 정렬하는 알고리즘입니다.

파이썬에서는 sorted() 함수를 사용하면 간단하게 정렬할 수 있습니다.

하지만, 이번에는 병합정렬을 직접 구현하여 1부터 100까지 중 랜덤한 숫자 10개가 있는 1*10의 배열을 정렬해보겠습니다.

위 코드에서 merge_sort() 함수는 재귀적으로 호출하여 배열을 반으로 나누고, merge() 함수를 사용하여 각 부분 배열을 정렬하여 병합하는 과정을 거칩니다.

merge() 함수는 각 부분 배열을 정렬하여 병합하며, 두 배열을 비교하여 작은 값을 결과 리스트에 추가하고, 마지막에 남은 부분 배열을 추가합니다.

위 코드를 실행하면, 1부터 100까지 중 랜덤한 숫자 10개가 있는 배열이 생성되어 출력되고, 병합정렬을 거친 후 정렬된 배열이 출력됩니다.

이게 일단 길어서 화면 캡처가 안되고… 돌려봤는데 정렬이 깔-끔하다. 스크롤 캡처 해보려고 했는데 일단 전체샷만 찍히고(시종점을 정할수가 없음) 괴랄하게 찍혀서 차라리 내가 하는게 낫겠다 수준이었음.

퀵 정렬

import random

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr)//2]
    less, equal, greater = [], [], []
    for num in arr:
        if num < pivot:
            less.append(num)
        elif num == pivot:
            equal.append(num)
        else:
            greater.append(num)
    return quick_sort(less) + equal + quick_sort(greater)

arr = [random.randint(1, 100) for _ in range(10)]
print("Before sorting:", arr)
arr = quick_sort(arr)
print("After sorting:", arr)

근데 이게 하다보니까 단점이라고 할 것까지는 아닌데, 보통 예시 코드로 설명해줄때는 중간과정을 출력하게끔 하는데 얘는 그런거 없다. 과정샷? 주문해야 나올듯…

힙 정렬

나도 뭔지는 모름… 힙 트리를 이용한다는데…

import heapq
import random

# 1부터 100까지 중 랜덤한 숫자 10개로 이루어진 리스트 생성
lst = random.sample(range(1, 101), 10)

# heapq 모듈을 사용하여 힙 정렬 실행
heapq.heapify(lst)
sorted_lst = []
for i in range(len(lst)):
    sorted_lst.append(heapq.heappop(lst))

print(sorted_lst)

이 힙이 두 종류인데 하나는 맥스 힙(최대 힙)이라고 해서 루트가 항상 제일 큰 거, 반대로 민 힙(최소 힙)이라고 해서 루트가 항상 제일 작은 게 있다. 근데 이렇게 얘기하면 루트? 트리 아래요? 아뇨 그 가운데 하나짜리. 맨 위에놈.

트리 정렬

배열로도 구현은 가능한데 배열이 커질수록 시간이 기하급수적으로 늘어나기때문에 비추라고 한다. (나도 이거 처음봤음)

총평의 총평

원하는 조건이나 알고리즘같은 것만 설명 잘 하면 쓸만한데 문제가 두 가지 있었다. 첫번째로 얘 종특인데 한글로 입력하면 응답이 느려서 그 시간에 차라리 내가 구글링하는게 더 빠르게 생겼고, 두번째로 오늘 전체적으로 서버가 개판인건지 누가 서버실에 커피를 엎었는지 느린 응답과 시너지를 이뤄서, 겨우겨우 응답하나 했더니 오류야. 야이씨 이럴바엔 내가 하고 말지가 되었다.

결론은 한국어가 좀 느린거 감수하면 쓸만한데 서버 상태가 멀쩡하기를 기도하고 쓰자.