Search
Duplicate

Sort

정렬(Sort)

1. 버블 정렬 (bubble sort)

두 인접한 데이터를 비교해서, 앞에 있는 데이터가 뒤에 있는 데이터보다 크면, 자리를 바꾸는 정렬 알고리즘
출처: https://en.wikipedia.org/wiki/Bubble_sort

1.1. 알고리즘 구현

n개의 리스트가 있는 경우 최대 n-1번의 로직을 적용한다.
로직을 1번 적용할 때마다 가장 큰 숫자가 뒤에서부터 1개씩 결정된다.
로직이 경우에 따라 일찍 끝날 수도 있다. 따라서 로직을 적용할 때 한 번도 데이터가 교환된 적이 없다면 이미 정렬된 상태이므로 더 이상 로직을 반복 적용할 필요가 없다.
1. for num in range(len(data_list)) 반복 2. swap = 0 (교환이 되었는지를 확인하는 변수를 두자) 2. 반복문 안에서, for index in range(len(data_list) - num - 1) n - 1번 반복해야 하므로 3. 반복문안의 반복문 안에서, if data_list[index] > data_list[index + 1] 이면 4. data_list[index], data_list[index + 1] = data_list[index + 1], data_list[index] 5. swap += 1 6. 반복문 안에서, if swap == 0 이면, break 끝
Plain Text
복사

1.2. 알고리즘 분석

반복문이 두 개 O($n^2$)
최악의 경우, n * (n - 1) / 2
완전 정렬이 되어 있는 상태라면 최선은 O(n)

1.3. 구현

def bubblesort(data): for index in range(len(data) - 1): swap = False for index2 in range(len(data) - index - 1): if data[index2] > data[index2 + 1]: data[index2], data[index2 + 1] = data[index2 + 1], data[index2] swap = True if swap == False: break return data
Python
복사

2. 선택 정렬(Selection Sort)

다음과 같은 순서를 반복하며 정렬하는 알고리즘
1.
주어진 데이터 중, 최소값을 찾음
2.
해당 최소값을 데이터 맨 앞에 위치한 값과 교체함
3.
맨 앞의 위치를 뺀 나머지 데이터를 동일한 방법으로 반복함

2.1. 알고리즘 구현

1. for stand in range(len(data_list) - 1) 로 반복 2. lowest = stand 로 놓고, 3. for num in range(stand, len(data_list)) stand 이후부터 반복 - 내부 반복문 안에서 data_list[lowest] > data_list[num] 이면, - lowest = num 4. data_list[num], data_list[lowest] = data_list[lowest], data_list[num]
Python
복사

2.2. 알고리즘 분석

반복문이 두 개 O(n^2)
실제로 상세하게 계산하면, n * (n - 1) / 2

2.3. 구현

def selection_sort(data): for stand in range(len(data) - 1): lowest = stand for index in range(stand + 1, len(data)): if data[lowest] > data[index]: lowest = index data[lowest], data[stand] = data[stand], data[lowest] return data
Python
복사

3. 삽입 정렬(Insertion Sort)

삽입 정렬은 두 번째 인덱스부터 시작
해당 인덱스(key 값) 앞에 있는 데이터(B)부터 비교해서 key 값이 더 작으면, B값을 뒤 인덱스로 복사
이를 key 값이 더 큰 데이터를 만날때까지 반복, 그리고 큰 데이터를 만난 위치 바로 뒤에 key 값을 이동
출처: https://commons.wikimedia.org/wiki/File:Insertion-sort-example.gif

3.1. 알고리즘 구현

1. for stand in range(len(data_list)) 로 반복 2. key = data_list[stand] 3. for num in range(stand, 0, -1) 반복 - 내부 반복문 안에서 data_list[stand] < data_list[num - 1] 이면, - data_list[num - 1], data_list[num] = data_list[num], data_list[num - 1]
Python
복사

3.2. 알고리즘 분석

반복문이 두 개 O($n^2$)
최악의 경우, <font size=5em>$\frac { n * (n - 1)}{ 2 }$</font>
완전 정렬이 되어 있는 상태라면 최선은 O(n)

3.3. 구현

def insertion_sort(data): for index in range(len(data) - 1): for index2 in range(index + 1, 0, -1): if data[index2] < data[index2 - 1]: data[index2], data[index2 - 1] = data[index2 - 1], data[index2] else: break return data
Python
복사

4. 병합 정렬 (merge sort)

재귀용법을 활용한 정렬 알고리즘
1.
리스트를 절반으로 잘라 비슷한 크기의 두 부분 리스트로 나눈다.
2.
각 부분 리스트를 재귀적으로 합병 정렬을 이용해 정렬한다.
3.
두 부분 리스트를 다시 하나의 정렬된 리스트로 합병한다.

4.1. 알고리즘 구현

mergesplit 함수 만들기
만약 리스트 갯수가 한개이면 해당 값 리턴
그렇지 않으면, 리스트를 앞뒤, 두 개로 나누기
left = mergesplit(앞)
right = mergesplit(뒤)
merge(left, right)
merge 함수 만들기
리스트 변수 하나 만들기 (sorted)
left_index, right_index = 0
while left_index < len(left) or right_index < len(right):
만약 left_index 나 right_index 가 이미 left 또는 right 리스트를 다 순회했다면, 그 반대쪽 데이터를 그대로 넣고, 해당 인덱스 1 증가
if left[left_index] < right[right_index]:
sorted.append(left[left_index])
left_index += 1
else:
sorted.append(right[right_index])
right_index += 1

4.2. 알고리즘 분석

다음을 보고 이해해보자
몇 단계 깊이까지 만들어지는지를 depth 라고 하고 i로 놓자. 맨 위 단계는 0으로 놓자.
다음 그림에서 n/2^2 는 2단계 깊이라고 해보자.
각 단계에 있는 하나의 노드 안의 리스트 길이는 n/2^2 가 된다.
각 단계에는 2^i 개의 노드가 있다.
따라서, 각 단계는 항상 2^i * n / 2^i = O(n)$</font>
단계는 항상 log_2 n 개 만큼 만들어짐, 시간 복잡도는 결국 O(log n), 2는 역시 상수이므로 삭제
따라서, 단계별 시간 복잡도 O(n) * O(log n) = O(n log n)

4.3. 구현

def merge(left, right): merged = list() left_point, right_point = 0, 0 # case1 - left/right 둘다 있을때 while len(left) > left_point and len(right) > right_point: if left[left_point] > right[right_point]: merged.append(right[right_point]) right_point += 1 else: merged.append(left[left_point]) left_point += 1 # case2 - left 데이터가 없을 때 while len(left) > left_point: merged.append(left[left_point]) left_point += 1 # case3 - right 데이터가 없을 때 while len(right) > right_point: merged.append(right[right_point]) right_point += 1 return merged def mergesplit(data): if len(data) <= 1: return data medium = int(len(data) / 2) left = mergesplit(data[:medium]) right = mergesplit(data[medium:]) return merge(left, right)
Plain Text
복사

5. 퀵 정렬 (quick sort)

기준점(pivot 이라고 부름)을 정해서, 기준점보다 작은 데이터는 왼쪽(left), 큰 데이터는 오른쪽(right) 으로 모으는 함수를 작성함
각 왼쪽(left), 오른쪽(right)은 재귀용법을 사용해서 다시 동일 함수를 호출하여 위 작업을 반복함
함수는 왼쪽(left) + 기준점(pivot) + 오른쪽(right) 을 리턴함

5.1. 알고리즘 구현

quicksort 함수 만들기
만약 리스트 갯수가 한개이면 해당 리스트 리턴
그렇지 않으면, 리스트 맨 앞의 데이터를 기준점(pivot)으로 놓기
left, right 리스트 변수를 만들고,
맨 앞의 데이터를 뺀 나머지 데이터를 기준점과 비교(pivot)
기준점보다 작으면 left.append(해당 데이터)
기준점보다 크면 right.append(해당 데이터)
return quicksort(left) + pivot + quicksort(right) 로 재귀 호출
리스트로 만들어서 리턴하기: return quick_sort(left) + [pivot] + quick_sort(right)

5.2. 알고리즘 분석

병합정렬과 유사, 시간복잡도는 O(n log n)
단, 최악의 경우
맨 처음 pivot이 가장 크거나, 가장 작으면
모든 데이터를 비교하는 상황이 나옴
O(n^2)

5.3. 구현

def qsort(data): if len(data) <= 1: return data pivot = data[0] left = [ item for item in data[1:] if pivot > item ] right = [ item for item in data[1:] if pivot <= item ] return qsort(left) + [pivot] + qsort(right)
Plain Text
복사