일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 26 | 27 | 28 | 29 | 30 | 31 |
- STL
- CS231n
- test-helper
- 프로그래머스
- ssd
- 그리디
- C++
- 이것이 코딩테스트다 with 파이썬
- 모두를 위한 딥러닝 강좌 시즌1
- AWS
- 머신러닝
- ubuntu
- 코드수행
- Object detection
- MySQL
- 1단계
- 실전알고리즘
- SWEA
- Python
- pytorch
- 백준
- docker
- 딥러닝
- 자료구조 및 실습
- 전산기초
- cs
- 2단계
- 3단계
- 구현
- 파이썬
- Today
- Total
곰퓨타의 SW 이야기
[이것이 코딩테스트다 with 파이썬] 정렬 본문
최근 보고 있는 책인 '이것이 코딩테스트다 with 파이썬 편_나동빈_한빛미디어' 책을 읽으면서 정리하고자 한다.
www.hanbit.co.kr/store/books/look.php?p_code=B8945183661
이것이 취업을 위한 코딩 테스트다 with 파이썬
IT 취준생이라면 누구나 가고 싶어 하는 카카오, 라인, 삼성전자의 2016년부터 2020년까지의 코딩 테스트와 알고리즘 대회의 기출문제를 엄선하여 수록하였다.
www.hanbit.co.kr
정렬
데이터를 특정한 기준에 따라서 순서대로 나열하는 것
-> 데이터를 정렬하면 이진 탐색이 가능하다.
선택정렬
데이터가 무작위로 여러 개 있을 때, 가장 작은 데이터를 선택하여 맨 앞에 있는 데이터와 바꾸고 , 그 다음 작은 데이터를 선택해 앞에서 두 번째 데이터와 바꾸는 과정
--> 매번 가장 작은 것을 선택하여 정렬
선택 정렬은 N-1만큼 가장 작은 수를 찾아서 맨 앞으로 보내야 한다. + 매번 가장 작은 수를 찾기 위해서 비교 연산이 필요하다.
N + (N-1) + (N-2) + ... + 2 = N(N+1)/2 ==> 시간 복잡도는 O(N^2)이다.
array = [7,5,9,0,3,1,6,2,4,8]
for i in range(len(array)):
min_index = i # 가장 작은 원소의 인덱스
for j in range(i+1, len(array)):
if array[min_index] > array[j] :
min_index = j
array[i], array[min_index] = array[min_index], array[i] # 스와프
print(array) # [0,1,2,3,4,5,6,7,8,9]
선택 정렬을 사용하는 경우 10000개 이상이면 정렬 속도가 급격히 느려진다. 따라서 파이썬에 내장된 정렬 라이브러리는 내부적으로 C언어 기반이어서 훨씬 빠르게 동작함을 알 수 있다.
삽입정렬
데이터를 하나씩 확인하며 각 데이터를 적절한 위치에 삽입한다.
선택 정렬에 비해 구현 난이도가 높지만, 삽입 정렬은 필요할 때만 위치를 바꾸므로 실행 시간 측면에서 효율적이다.
-> 데이터가 거의 정렬되어 있을 때 훨씬 효율적이다.
특정한 데이터의 왼쪽에 있는 데이터들은 이미 정렬이 된 상태이므로 자기보다 작은 데이터를 만났다면 더 이상 데이터를 살펴볼 필요 없이 그 자리에 삽입한다.
반복문이 2번 중첩되어 시간 복잡도는 O(N^2) 이다.
정렬이 어느 정도 되어 있는 최선의 경우라면 O(N)까지도 가능하여 선택정렬보다 잘 될 수 있다.
array = [7,5,9,0,3,1,6,2,4,8]
for i in range(1,len(array)) :
for j in range(i,0,-1) : # 인덱스 i부터 1까지 감소하며 반복하는 문법
if array[j] < array[j-1]: # 한 칸씩 왼쪽으로 이동
array[j], array[j-1] = array[j-1], array[j]
else : # 자기 보다 작은 데이터를 만나면 그 위치에서 멈춘다.
break
print(array)
퀵정렬
기준 데이터(피벗)를 설정하고 그 기준보다 큰 데이터와 작은데이터의 위치를 바꾼다. 그 후, 반으로 나누는 방식으로 동작한다.
호어 분할 방식 (Hoare Partition)
1. 리스트에서 첫 번째 데이터를 피벗으로 정한다.
2. 피벗 설정 후, 왼쪽에서부터 피벗보다 큰 데이터를 찾고 오른쪽에서부터 피벗보다 작은 데이터를 찾는다.
3. 2번에서 찾은 두 데이터를 교환한다
4. 왼쪽에서부터 찾은 값과 오른쪽에서 찾은 값의 위치가 엇갈리는 경우, 작은 데이터와 피벗데이터를 교환한다.
5. 교환된 피벗 위치를 기준으로 양쪽의 데이터를 나누어서 1-4 번을 수행한다.
--> 재귀함수의 동작 원리와 같다.
------> 종료 조건 : 현재 리스트의 데이터 개수가 1개인 경우
직관적인 퀵소트 코드
array = [5,7,9,0,3,1,6,2,4,8]
def quick_sort(array, start, end) :
if start >= end : # 원소가 1개인 경우 종료
return
pivot = start # pivot 은 첫 번째 원소
left = start + 1
right = end
while left <= right:
# 피벗보다 큰 데이터를 찾을 때까지 반복
while left <= end and array[left] <= array[pivot] :
left += 1
# 피벗보다 작은 데이터를 찾을 때까지 반복
while right > start and array[right] >= array[pivot] :
right -= 1
if left > right : # 엇갈렸다면 짝은 데이터와 피벗 교체
array[right], array[pivot] = array[pivot] , array[right]
else : # 엇갈리지 않았다면 작은 데이터와 큰 데이터의 교체
array[left], array[right] = array[right], array[left]
# 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬 수행
quick_sort(array,start, right-1)
quick_sort(array,right+1, end)
quick_sort(array, 0, len(array)-1)
print(array)
파이썬의 장점을 살린 퀵소트 코드
array = [5,7,9,0,3,1,6,2,4,8]
def quick_sort(array) :
# 리스트가 하나 이하의 원소만을 담고 있다면 종료
if len(array) <= 1:
return array
pivot = array[0] # 피벗은 첫번째 원소
tail= array[1:] # 피벗을 제외한 리스트
left_side = [x for x in tail if x <= pivot] # 분할된 왼쪽 부분
right_side = [x for x in tail if x>pivot] # 분할 된 오른쪽 부분
# 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬을 수행하고 전체 리스트를 반환
return quick_sort(left_side) + [pivot] + quick_sort(right_side)
print(quick_sort(array))
이는 최악의 경우에는 시간 복잡도가 O(N^2) 이지만, 평균 시간 복잡도는 O(NlogN) 이다.
계수정렬(count sort)
특정한 조건이 부합할 때만 사용할 수 있지만 빠른 정렬 알고리즘이다.
모든 데이터가 양의 정수이라면 데이터의 개수가 N, 데이터 중 최댓값이 K일 때 시간 복잡도는 O(N+K) 를 보장한다.
가장 큰 데이터와 가장 작은 데이터의 차이가 1,000,000을 넘지 않을 때 효과적으로 사용할 수 있다.
모든 범위를 담을 수 있는 리스트를 사용하기 때문이다. (시간 복잡도 측면에서는 좋지만 공간 복잡도개념에서는 좋지 않다.)
1. 가장 큰 데이터와 가장 작은 데이터의 범위가 모두 담길 수 있도록 하나의 리스트를 생성한다.
2. 리스트의 모든 데이터를 0으로 한다.
3. 데이터를 하나씩 확인하며 데이터의 값과 동일한 인덱스의 데이터를 1씩 증가시킨다.
# 모든 원소의 값이 0보다 크거나 같다고 가정
array = [7,5,9,0,3,1,6,2,9,1,4,8,0,5,2]
# 모든 범위를 포함하는 리스트 선언(모든 값은 0으로 초기화)
count = [0]*(max(array) + 1)
for i in range(len(array)) :
count[array[i]] += 1 # 각 데이터에 해당하는 인덱스의 값 증가
for i in range(len(count)) :
for j in range(count[i]) :
print(i,end=' ') # 띄어쓰기를 구분으로 등장한 횟수만큼 인덱스 출력
파이썬 정렬 라이브러리
sorted() : 퀵정렬과 동작방식이 비슷한 병합 정렬을 기반으로 만들어졌다. 이는 최악의 경우에도 O(NlogN)을 보장한다는 특징이 있다.
sort() : 리스트에 내장된 함수로 정렬된 리스트를 반환하는 것이 아닌 내부 원소가 바로 정렬된다.
# 1
array= [7,5,9,0,3,1,6,2,4,8]
result = sorted(array)
print(result)
# 2
array= [7,5,9,0,3,1,6,2,4,8]
array.sort()
print(array)
lambda 활용
# lambda
def add(a,b) :
return a+b
print(add(3,7))
print((lambda a,b : a+b)(3,7))
# lambda로 튜플의 두 번째 원소 기준 정렬
array = [(0,1),(3,0),(2,2)]
array= sorted(array, key=lambda x : x[1])
print(array)
key를 활용, 튜플에서 두번째 데이터 기준 정렬하고 싶은 경우
array = [('바나나',2), ('사과',5), ('당근',3)]
def setting(data):
return data[1]
result = sorted(array,key = setting)
print(result)
정렬 문제 유형
1. 정렬 라이브러리로 풀 수 있는 경우
2. 정렬 알고리즘의 원리에 대해서 물어보는 경우
3. 빠른 정렬이 필요한 경우 : 계수 정렬
'TIL > 자료구조 및 알고리즘' 카테고리의 다른 글
[이것이 코딩테스트다 with 파이썬] 다이나믹 프로그래밍 (0) | 2021.04.20 |
---|---|
[이것이 코딩테스트다 with 파이썬] 이진탐색 (0) | 2021.04.17 |
[이것이 코딩테스트다 with 파이썬] bfs/dfs (0) | 2021.04.15 |
[이것이 코딩테스트다 with 파이썬] 구현 (0) | 2021.04.15 |
[이것이 코딩테스트다 with 파이썬] 그리디 알고리즘 (0) | 2021.04.15 |