버블정렬, 선택정렬, 삽입정렬
오늘은 최대한 간단하게 핵심 내용만 요약 정리!
개발자들한테는 기술 면접 단골 질문일 수 있겠다.
탐색
정렬
여기서 내가 오늘 배운 정렬의 종류들도 '정렬'이라는 문제를 해결하기 위한 알고리즘의 하나라는 맥락으로 다룬다는 걸 인지하고 있어야 한다.
O(n^2)
이 된다. (내외부 루프를 다 도니까) 따라서 비효율적인 정렬 방식이라고 여겨진다. 선택 정렬은 예시로 적어두는게 나중에 이해하기에도 더 쉽겠다.
만약 [3,5,4,2,1]
이라는 리스트를 정렬하고자 한다 해보자.
[5,4,2,3]
중에 최솟값을 찾고 swap한다.[1,2,4,5,3]
O(n^2)
로 버블정렬과 동일하다.O(n)
이 된다. O(n^2)
이 된다. 오늘은 아래 실습을 해보았다.
[버블정렬, 선택정렬, 삽입정렬 구현]
"""
파이썬에서 제공되는 sort와 같은 내장함수를 사용하면 안됩니다.
반복문과 조건문만을 활용하여 구현하시길 바랍니다.
"""
def bubble_sort(li):
"""
# 문제 1.
거품정렬을 구현해주세요.
매개변수로 들어온 리스트를 오름차순으로 정렬해주세요.
단 매개변수로 들어오는 요소는 전부 정수입니다.
ex)
li = [54, 26, 93, 17, 77, 31]
bubble_sort(li)
print(li) # [17, 26, 31, 54, 77, 93]
"""
for n in range(len(li)-1, 0, -1):
for i in range(n):
if li[i] > li[i+1]:
li[i], li[i+1] = li[i+1], li[i]
#print(li)
#print('------------')
return li
'''
[기록] - 내가 만들고자 하는 버블소팅 흐름
li = [54, 26, 93, 17, 77, 31]
# 1. idx 0, 1 비교 => 0 > 1 이므로 스왑. [26, 54, 93, 17, 77, 31]
# 2. idx 1, 2 비교 => 1 < 2 이므로 유지. [26, 54, 93, 17, 77, 31]
# 3. idx 2, 3 비교 => 2 > 3 이므로 스왑. [26, 54, 17, 93, 77, 31]
# 3. idx 3, 4 비교 => 3 > 4 이므로 스왑. [26, 54, 17, 77, 93, 31]
# 4. idx 4, 5 비교 => 4 > 5 이므로 스왑. [26, 54, 17, 77, 31, 93]
=> 이렇게 맨 끝의 93은 찾아짐. 93을 제외한 원소에 대해 이 과정을 반복.
=> 근데 이 첫 과정이야 for i in range(len(li)-1):로 li[i], li[i+1] 비교하면 되는데, 이걸 어떻게 추가로 반복되게 할 수 있을까?
=> 이 과정을 몇번 반복해야하지?
두번째 루프 결과 => [26,17,54,31,77,93]
세번째 루프 결과 => [17,26,31,54,77,93] # 찾아짐. 3번째만에..? 이게 예외는 없을까?
네번째 루프 결과 => [17,26,31,54,77,93] # 변동 없음.
what if li = [10, 5, 3, 7, 2]
1. [5,3,7,2,10]
2. [3,5,2,7,10]
3. [3,2,5,7,10]
4. [2,3,5,7,10] # 찾아짐. 여기서 알 수 있는 건 두번째 원소가 픽스될때까지 루프 돌리는게 안정적일 것 같다는 점.
=> 즉, len(li)-1 번 돌리자.
!!!코드 짜보니 결과는 잘 나옴!!!
--
def bubble_sort(li):
n = 0
while n != len(li)-1:
for i in range(len(li)-1):
if li[i] > li[i+1]:
li[i], li[i+1] = li[i+1], li[i]
else:
pass
n+=1
return li
--
- 버블정렬에선 원래 맨 끝에 확정된 걸 제외하고 나머지를 비교하는 거 아닌가..? 내가 짠 코드가 버블소팅이 맞나..?
=> 질문해봤는데, 버블 소팅이 아니라고 할 수는 없지만 불필요한 연산이 계속 일어나기 때문에 좋은 코드라고 할 수는 없다고 함.
- 그럼 수정해보자.. 하나씩 줄여나가는 방법에 대해 힌트 얻었다!
# for n in range(len(li)-1, 0, -1): 결국 이렇게 보는 범위를 줄여나가는게 핵심이었다.
=> 참고로 주석처리한 print문 포함해서 돌려보면 어떤 과정을 거쳐서 버블 소팅이 이루어지는지도 볼 수 있다. 신기하네.
'''
def insertion_sort(li):
"""
# 문제 2.
삽입정렬을 구현해주세요.
매개변수로 들어온 리스트를 오름차순으로 정렬해주세요.
단 매개변수로 들어오는 요소는 전부 정수입니다.
ex)
li = [54, 26, 93, 17, 77, 31]
insertion_sort(li)
print(li) # [17, 26, 31, 54, 77, 93]
"""
for i in range(1, len(li)):
for j in range(i,0,-1):
if li[j-1] > li[j]:
li[j-1], li[j] = li[j], li[j-1]
return li
'''
삽입 정렬의 핵심 컨셉은 첫 값을 정렬되었다고 보고 신병을 넣어주면서 그 안에서 재정렬시켜나가는 것.
if li = [1,8,10,2,5,6]
then i = 1,2,3,4,5
if i = 1;
j = 1
if li[0] > li[1]가 참이야? 아니야!
넘어가
li = [1,8,10,2,5,6]
if i = 2;
j = 2,1
if j = 2
if li[1] > li[2]가 참이야? 아니야!
넘어가
li = [1,8,10,2,5,6]
j= 1
if li[0] > li[1]이 참이야? 아니야!
넘어가
li[1,8,10,2,5,6]
if i = 3;
j = 3,2,1
if j = 3
if li[2] > li[3]이 참이야? 참이야!
그럼 둘이 바꿔!
li = [1,8,2,10,5,6]
if j = 2
if li[1] > li[2]이 참이야? 참이야!
그럼 둘이 바꿔!
li = [1,2,8,10,5,6]
이런 식으로 외내부 루프에 의해 차례로 돈다.. 신기하네..
'''
def selection_sort(li):
"""
# 문제 3.
선택정렬을 구현해주세요.
매개변수로 들어온 리스트를 오름차순으로 정렬해주세요.
단 매개변수로 들어오는 요소는 전부 정수입니다.
ex)
li = [54, 26, 93, 17, 77, 31]
selection_sort(li)
print(li) # [17, 26, 31, 54, 77, 93]
"""
for i in range(len(li)): # 0,1,2,3,4,5
cur_index = i
min_num = li[i] # 현재 위치를 최솟값으로 지정하고 이너 루프 시작
for j in range(i+1,len(li)): # 지정된 최솟값 다음부터 탐색한다.
if li[j] < min_num: # 새로 최솟값을 발견했다면?
min_num = li[j]
cur_index = j # 최솟값의 index를 변경
if cur_index != i: # 최솟값의 index가 바뀌었다면 둘을 swap.
li[i], li[cur_index] = li[cur_index], li[i]
return li
[재귀 복습]
"""
Bare Minimum Requirements
예외사항에 따라 어떻게 될지 결과를 예상해봅시다.
요구사항:
중요한 조건은 재귀를 반드시 활용해야 합니다.
마이너스값이 입력되었을 경우, 예외처리해주는 코드를 작성하세요.
마이너스값을 입력해도 마이너스값도 정상수행되야 합니다.
출력결과값에 대해서는 '입력받은 n부터 1씩 감소하며(또는 증가하며) 0까지 출력하면 됩니다.
입출력값에 대한 별도 양식은 없으니 조건에 따른 구현만 하시면 됩니다.
각 문제 코드 위에 작성된 '@counter'는 변경하지 마세요.
"""
class counter:
"""
해당 코드를 수정하지 마세요!
"""
def __init__(self, function):
self.function = function
self.cnt = 0
def __call__(self, *args, **kwargs):
self.cnt += 1
return self.function(*args, **kwargs)
@counter
def print_to_zero_pos(n, result_list):
"""
# 문제 1.
1 이상의 양수를 입력받아 입력받은 수부터 0까지 구하는 함수를 작성해주세요.
재귀함수를 꼭 사용해주셔야합니다.
result_list안에 결과 값을 넣어주세요.
(result_list를 어떻게 사용하는지는 아래 코드 사용 예제를 참고해주세요.)
해당 코드 사용 예제
pos = int(input("input : ")) # 5
result_list = []
print_to_zero_pos(pos, result_list)
print(result_list) # [5,4,3,2,1,0]
"""
#if n < 0:
#raise ValueError # 예외 처리하면 pytest 통과가 안되네..? 음.
if n == 0:
result_list.append(0)
return result_list
else:
result_list.append(n)
print_to_zero_pos(n-1, result_list)
return result_list
@counter
def print_to_zero_neg(n, result_list):
"""
# 문제 2.
-1 이하의 음수를 입력받아 입력받은 수부터 0까지 구하는 함수를 작성해주세요.
재귀함수를 꼭 사용해주셔야합니다.
result_list안에 결과 값을 넣어주세요.
(result_list를 어떻게 사용하는지는 아래 코드 사용 예제를 참고해주세요.)
해당 코드 사용 예제
neg = int(input("input : ")) # -3
result_list_neg = []
print_to_zero_neg(neg, result_list_neg)
print(result_list_neg) #[-3,-2,-1,0]
"""
#if n > 0:
#raise ValueError # 예외 처리하면 pytest 통과가 안되네..? 음.
if n == 0:
result_list.append(0)
return result_list
else:
result_list.append(n)
print_to_zero_neg(n+1, result_list)
return result_list