인접한 두 개의 원소를 비교하며 자리를 계속 교환하는 방식
정렬 과정
시간 복잡도 :
ex) [5, 9, 2, 3, 6] 을 버블정렬하는 과정
- 1 번째 패스(구간 [0:4]) : [5, 9, 2, 3, 6]→[5, 2, 9, 3, 6]→[5, 2, 3, 9, 6]→[5, 2, 3, 6, 9]
- 2 번째 패스(구간 [0:3]) : [2, 5, 3, 6, 9]→[2, 3, 5, 6, 9]→[2, 3, 5, 6, 9]
- 3 번째 패스(구간 [0:2]) : [2, 3, 5, 6, 9]→[2, 3, 5, 6, 9]
- 4 번째 패스(구간 [0:1]) : [2, 3, 5, 6, 9]
- 정렬 끝 : [2, 3, 5, 6, 9]
n = int(input())
arr = list(map(int, input().split()))
# arr: 정렬할 리스트, n: 원소의 개수
def BubbleSort(arr, n):
for i in range(n-1, 0, -1):
for j in range(0, i):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
return arr
print(BubbleSort(arr, n))
항목들의 순서를 결정하기 위해 집합에 각 항목이 몇 개씩 있는지 세는 작업을 하여, 선형 시간에 정렬하는 효율적인 알고리즘
단, 정수나 정수로 표현할 수 있는 자료에 대해서만 적용 가능
(각 항목의 발생 횟수 기록을 위해, 정수 항목으로 인덱스되는 카운트들의 배열을 사용하기 때문)
카운트들을 위한 충분한 공간을 할당하려면 집합 내의 가장 큰 정수를 알아야 함
시간 복잡도 :
def CountingSort(arr, k) # k : 배열에서 가장 큰 수
# arr : 입력 배열(1 to k)
# c : 카운트 배열
c = [0]*(k+1)
n = len(arr)
for i in range(0, n): # 숫자 갯수를 카운트하여 c에 대입
c[arr[i]] += 1
for j in range(1, k+1): # c[j-1]까지의 누적합을 c[j]에 대입
c[j] += c[j-1]
tmp = [0] * n
for i in range(n-1, -1, -1):
c[arr[i]] -= 1
tmp[c[arr[i]]] = arr[i]
return tmp
시간 복잡도 :
arr = [4,7,1,3,5,2]
for i in range(len(arr)-1):
for j in range(i+1, len(arr)):
if arr[i]>arr[j]:
# tmp = arr[i]
# arr[i]=arr[j]
# arr[j]=tmp
arr[i], arr[j] = arr[j], arr[i] # 파이썬 스타일
print(arr)
arr = [4,7,1,3,5,2]
result = []
for i in range(len(arr)):
result.append(arr[i])
for j in range(i, 0, -1):
if result[j]<result[j-1]:
result[j], result[j-1] = result[j-1], result[j]
print(result)
def partition(left, right):
pivot = arr[left] # 피봇을 배열의 가장 왼쪽 값으로 초기화
i, j = left, right
# i, j 가 교차 시, i, j는 피봇을 기준으로 작은 값과 큰 값들의 경계에 위치
while i <= j:
while i <= j and arr[i] <= pivot: # i : 왼쪽에서 오른쪽 방향으로 피봇보다 큰 값을 탐색
i += 1
while i <= j and arr[j] >= pivot: # j : 오른쪽에서 왼쪽 방향으로 피봇보다 큰 값을 탐색
j -= 1
if i < j : # i와 j가 결정된 이후, arr[i]와 arr[j]를 SWAP
arr[i], arr[j] = arr[j], arr[i]
arr[left], arr[j] = arr[j], arr[left]
return j
def quick_sort(left, right):
if left < right: # 시작 인덱스보다 끝 인덱스가 큰 경우
mid = partition(left, right)
quick_sort(left, mid-1)
quick_sort(mid+1, right)
arr = [7, 2, 5, 3, 4, 5]
n = len(arr)
quick_sort(0, n-1) # 시작 인덱스와 끝 인덱스를 인자로 전달
print(arr)
def partition(left, right):
pivot = arr[left] # 피봇을 배열의 가장 왼쪽 값으로 초기화
i, j = left, right
# i, j 가 교차 시, i, j는 피봇을 기준으로 작은 값과 큰 값들의 경계에 위치
while i <= j:
while i <= j and arr[i] <= pivot: # i : 왼쪽에서 오른쪽 방향으로 피봇보다 큰 값을 탐색
i += 1
while i <= j and arr[j] >= pivot: # j : 오른쪽에서 왼쪽 방향으로 피봇보다 큰 값을 탐색
j -= 1
if i < j : # i와 j가 결정된 이후, arr[i]와 arr[j]를 SWAP
arr[i], arr[j] = arr[j], arr[i]
arr[left], arr[j] = arr[j], arr[left]
return j
def quick_sort(left, right):
if left < right: # 시작 인덱스보다 끝 인덱스가 큰 경우
mid = partition(left, right)
quick_sort(left, mid-1)
quick_sort(mid+1, right)
arr = [7, 2, 5, 3, 4, 5]
n = len(arr)
quick_sort(0, n-1) # 시작 인덱스와 끝 인덱스를 인자로 전달
print(arr)
알고리즘 | 평균 수행시간 | 최악 수행시간 | 알고리즘 기법 | 비고 |
---|---|---|---|---|
버블 정렬 | 비교 교환 | 쉽게 구현 | ||
카운팅 정렬 | 비교환 | n이 비교적 작을 때만 가능 | ||
선택 정렬 | 비교 교환 | 교환의 횟수가 버블, 삽입정렬보다 작음 | ||
퀵 정렬 | 분할 정복 | 최악의 경우 O(n^2)이지만, 평균적으로 가장 빠름 | ||
삽입 정렬 | 비교 교환 | n의 개수가 작을 때 효과적 | ||
병합 정렬 | 분할 정복 | 연결리스트의 경우 가장 효율적인 방식 |