[강의 요약]
[Part 03. 자료구조&알고리즘 with Python_ Ch 03. 알고리즘] 강의 수강
27_병합 정렬부터 30_퀵 정렬(실습)까지 강의 수강하였음
🐢 100일 챌린지 🔥 : [▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰░ ] 49/100일 (49%)
연휴에도 쉴 수 없다... 악으로 깡으로 버텨라
[27_병합 정렬]
▶ 병합 정렬(Merge Sort)이란?
리스트를 반으로 나눠서 각각 정렬한 후, 다시 합치는 정렬 알고리즘을 말한다.
대표적인 분할 정복 알고리즘이고, 시간복잡도는 O(n log n)이어서 효율적 + 안정적인 정렬 방식이다.
이해를 위해서 강의자료 이미지를 가져왔다.
▶ 코드 : 병합 정렬 알고리즘을 재귀적으로 구현
def mSort(ns):
if len(ns) < 2:
return ns
midIdx = len(ns) // 2
leftNums = mSort(ns[0:midIdx])
rightNums = mSort(ns[midIdx:])
mergedNums = []
leftIdx = 0; rightIdx = 0
while leftIdx < len(leftNums) and rightIdx < len(rightNums):
if leftNums[leftIdx] < rightNums[rightIdx]:
mergedNums.append(leftNums[leftIdx])
leftIdx += 1
else:
mergedNums.append(rightNums[rightIdx])
rightIdx += 1
mergedNums = mergedNums + leftNums[leftIdx:]
mergedNums = mergedNums + rightNums[rightIdx:]
print(f'mergedNums: {mergedNums}')
return mergedNums
nums = [8, 1, 4, 3, 2, 5, 10, 6]
print(f'mergedNums: {mSort(nums)}')
[출력 결과]
중간중간 병합된 결과를 출력해서 과정을 추적할 수 있다.
mergedNums: [1, 8]
mergedNums: [3, 4]
mergedNums: [1, 3, 4, 8]
mergedNums: [2, 5]
mergedNums: [6, 10]
mergedNums: [2, 5, 6, 10]
mergedNums: [1, 2, 3, 4, 5, 6, 8, 10]
mergedNums: [1, 2, 3, 4, 5, 6, 8, 10]
[28_병합 정렬(실습)]
▶ 실습 문제
▶ sortMod.py : 병합 정렬 함수 모듈
def mSort(ns, asc=True):
if len(ns) < 2:
return ns
midIdx = len(ns) // 2
leftNums = mSort(ns[0:midIdx], asc=asc)
rightNums = mSort(ns[midIdx:], asc=asc)
mergedNums = []
leftIdx = 0; rightIdx = 0
while leftIdx < len(leftNums) and rightIdx < len(rightNums):
if asc: # 오름차순
if leftNums[leftIdx] < rightNums[rightIdx]:
mergedNums.append(leftNums[leftIdx])
leftIdx += 1
else:
mergedNums.append(rightNums[rightIdx])
rightIdx += 1
else: # 내림차순
if leftNums[leftIdx] > rightNums[rightIdx]:
mergedNums.append(leftNums[leftIdx])
leftIdx += 1
else:
mergedNums.append(rightNums[rightIdx])
rightIdx += 1
mergedNums += leftNums[leftIdx:]
mergedNums += rightNums[rightIdx:]
return mergedNums
▶ mergeEx.py : 메인 실행 파일
import random as rd
import sortMod as sm
rNums = rd.sample(range(1, 101), 10)
print(f'not sorted rNums: {sm.mSort(rNums)}')
print(f'merge sorted rNums by ASC: {sm.mSort(rNums)}')
print(f'merge sorted rNums by DESC: {sm.mSort(rNums, asc=False)}')
asc 매개변수 : True면 오름차순, False면 내림차순 정렬 수행
[출력 결과]
not sorted rNums: [57, 4, 90, 28, 33, 71, 12, 86, 1, 42]
merge sorted rNums by ASC: [1, 4, 12, 28, 33, 42, 57, 71, 86, 90]
merge sorted rNums by DESC: [90, 86, 71, 57, 42, 33, 28, 12, 4, 1]
[29_퀵 정렬]
▶ 퀵 정렬(Quick Sort)이란?
기준값(pivot)을 중심으로 작은 값, 같은 값, 큰 값으로 분리하고
이 과정을 재귀적으로 반복하는 정렬 방식
불안정 정렬이지만 평균 성능이 매우 우수하고
평균 시간복잡도는 O(n log n)이며
최악의 경우 시간복잡도는 O(n²)이다. (이미 정렬된 리스트 등의 경우)
▶ 코드
def qSort(ns):
if len(ns) < 2: # 기저 조건
return ns
midIdx = len(ns) // 2 # 중앙값을 피벗으로 선택
midVal = ns[midIdx]
smallNums = [] # 피벗보다 작은 값들
sameNums = [] # 피벗과 같은 값들
bigNums = [] # 피벗보다 큰 값들
for n in ns:
if n < midVal:
smallNums.append(n)
elif n == midVal:
sameNums.append(n)
else:
bigNums.append(n)
# 분할된 리스트에 대해 재귀적으로 qSort 수행
# 세 리스트를 순서대로 이어 붙여 리턴
return qSort(smallNums) + sameNums + qSort(bigNums)
nums = [8, 1, 4, 3, 2, 5, 4, 10, 6, 8]
print(qSort(nums))
피벗 중심 분할 → 재귀 호출 → 합치기
[출력 결과]
[1, 2, 3, 4, 4, 5, 6, 8, 8, 10]
[30_퀵 정렬(실습)]
▶ 실습 문제
▶ sortMod.py : 퀵 정렬 함수
def qSort(ns, asc=True):
if len(ns) < 2:
return ns
midIdx = len(ns) // 2
midVal = ns[midIdx]
smallNums = []
sameNums = []
bigNums = []
for n in ns:
if n < midVal:
smallNums.append(n)
elif n == midVal:
sameNums.append(n)
else:
bigNums.append(n)
if asc:
return qSort(smallNums, asc=asc) + sameNums + qSort(bigNums, asc=asc)
else:
return qSort(bigNums, asc=asc) + sameNums + qSort(smallNums, asc=asc)
퀵 정렬 (분할 → 재귀 → 병합)
▶ quickEx.py : 실행 코드
import random as rd
import sortMod as sm
rNums = rd.sample(range(1, 101), 10)
print(f'not sorted rNums: {rNums}')
print(f'quick sorted rNums by ASC: {sm.qSort(rNums)}')
print(f'quick sorted rNums by DESC: {sm.qSort(rNums, asc=False)}')
랜덤 숫자 10개 생성
qSort() 함수를 이용해 오름차순 / 내림차순 출력
[출력 결과]
not sorted rNums: [17, 3, 89, 52, 41, 26, 78, 8, 34, 60]
quick sorted rNums by ASC: [3, 8, 17, 26, 34, 41, 52, 60, 78, 89]
quick sorted rNums by DESC: [89, 78, 60, 52, 41, 34, 26, 17, 8, 3]
[나의 생각 정리]
병합 정렬과 퀵 정렬은 구조는 비슷해 보이지만, 동작 원리와 장단점은 달랐다.
두 정렬 모두 재귀 기반으로 작동하면서 병합 정렬은 일정한 성능, 퀵 정렬은 중앙값 기준으로 빠른 평균 성능을 보였다.
[적용점]
병합 정렬 = 안정적, 퀵 정렬 = 속도 중심. 이므로 데이터의 특성과 상황에 따라 선택해서 사용하면 된다.
“이 글은 제로베이스 데이터 스쿨 주 3일반 강의 자료 일부를 발췌하여 작성되었습니다.”
'제로베이스 데이터 취업 파트타임 > 100일 챌린지_일일 학습 일지' 카테고리의 다른 글
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.06] (0) | 2025.05.06 |
---|---|
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.05] (1) | 2025.05.05 |
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.03] (0) | 2025.05.03 |
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.02] (0) | 2025.05.02 |
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.01] (1) | 2025.05.01 |