🥞 BE
home

정렬 알고리즘

정렬 - 순서대로 나열

정렬의 종류
O(N2N^2) 효율 정렬 알고리즘: 버블정렬, 선택정렬, 삽입정렬
O(nlognnlogn) 효율 정렬 알고리즘: 퀵 정렬, 병합 정렬, 트리 정렬, 힙 정렬
특수 알고리즘: 계수 정렬, 기수 정렬
선택정렬
삽입정렬
버블정렬
병합정렬
힙정렬
퀵정렬
트리정렬
팀정렬
n^2
n^2
n^2
nlogn
nlogn
nlogn
nlogn
nlogn

1. 정렬 알고리즘

1.1. 버블 정렬

void bubbleSort(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { swap(arr, j, j + 1); } } } }
Java
복사
array=[7, 5, 9, 0, 3, 1, 6, 2, 4, 8] def bubbleSort(data): for i in range(len(data)-1, 0, -1): for j in range(i): if data[j] > data[j+1]: data[j], data[j+1] = data[j+1], data[j] # 스와프 bubbleSort(array) print(array)
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

1.2. 선택 정렬

void selectionSort(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { int minIdx = i; for (int j = i + 1; j < arr.length; j++) { if (arr[j] < arr[minIdx]) { minIdx = j; } } swap(arr, i, minIdx); } }
Java
복사
array=[7, 5, 9, 0, 3, 1, 6, 2, 4, 8] def selectionSort(data): for i in range(len(data)): min_index=i # 가장 작은 원소의 인덱스 for j in range(i+1, len(array)): if data[min_index] > data[j]: min_index=j data[i], data[min_index] = data[min_index], data[i] # 스와프 selectionSort(array) print(array)
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

1.3. 삽입 정렬

void insertionSort(int[] arr) { for (int i = 1; i < arr.length; i++) { int tmp = arr[i]; int j = i - 1; while (j >= 0 && tmp < arr[j]) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = tmp; } }
Java
복사
array=[7, 5, 9, 0, 3, 1, 6, 2, 4, 8] def insertionSort(data): for i in range(1, len(data)): for j in range(i, 0, -1): if data[j] < data[j-1]: # 한 칸씩 왼쪽으로 이동 data[j], data[j-1] = data[j-1], data[j] else: # 자기보다 작은 데이터를 만나면 그 위치에서 멈춤 break insertionSort(array) print(array)
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

1.4. 병합 정렬

// 병합 정렬 함수 public static void mergeSort(int[] arr, int left, int right) { if (left < right) { // 중간점 찾기 int mid = (left + right) / 2; // 왼쪽 반 정렬 mergeSort(arr, left, mid); // 오른쪽 반 정렬 mergeSort(arr, mid + 1, right); // 정렬된 두 부분을 병합 merge(arr, left, mid, right); } } // 병합 함수 public static void merge(int[] arr, int left, int mid, int right) { // 두 부분을 나누기 int n1 = mid - left + 1; int n2 = right - mid; // 임시 배열 생성 int[] leftArray = new int[n1]; int[] rightArray = new int[n2]; // 임시 배열에 데이터 복사 for (int i = 0; i < n1; ++i) leftArray[i] = arr[left + i]; for (int j = 0; j < n2; ++j) rightArray[j] = arr[mid + 1 + j]; // 임시 배열들을 병합 int i = 0, j = 0; int k = left; while (i < n1 && j < n2) { if (leftArray[i] <= rightArray[j]) { arr[k] = leftArray[i]; i++; } else { arr[k] = rightArray[j]; j++; } k++; } // 남은 요소들을 복사 while (i < n1) { arr[k] = leftArray[i]; i++; k++; } while (j < n2) { arr[k] = rightArray[j]; j++; k++; } }
Java
복사
array=[6, 5, 3, 1, 8, 7, 2, 4] def merge(left, right): result=[] while len(left) > 0 and len(right) > 0: # 왼쪽 & 오른쪽 배열이 모두 존재한다면 if left[0] <= right[0]: # 왼쪽이 더 작으면 왼쪽을 추가 result.append(left[0]) left=left[1:] else: # 아니라면 오른쪽 추가 result.append(right[0]) right=right[1:] if len(left) > 0: result += left if len(right) > 0: result += right #result.extend([*left, *right]) return result def mergeSort(data): if len(data) <=1: # 배열의 길이가 1보다 작거나 같으면(원소의 개수가 1이면) return data mid = len(data)//2 # 배열을 1/2로 나누기 위해 배열의 중간 인덱스를 구함 left = mergeSort(data[:mid]) # 왼쪽 배열 병합하기 위한 호출 right = mergeSort(data[mid:]) # 오른쪽 배열 병합하기 위한 호출 result = merge(left, right) # 왼쪽 배열과 오른족 배열을 합칠 임시 배열 result 선언 return result print(mergeSort(array))
Python
복사
[1, 2, 3, 4, 5, 6, 7, 8]

1.5. 퀵 정렬

static int partition(int[] arr, int lo, int hi) { // 가장 마지막 인덱스를 피벗으로 설정 int pivot = arr[hi]; int left = lo; // 피벗 기준으로 작은 값 왼쪽, 큰 값 오른쪽으로 정렬 수행. for (int right = lo; right < hi; right++) { if (arr[right] < pivot) { // 현재 left 위치의 값과 right 위치의 값을 교환 int temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; left++; // left 포인터를 오른쪽으로 이동 } } // 피벗 정렬 int temp = arr[left]; arr[left] = arr[hi]; arr[hi] = temp; // 피벗의 위치 반환 return left; } // 재귀 수행 static int[] Quicksort(int[] arr, int lo, int hi) { // 배열의 범위 (lo ~ hi)가 유효한 경우에만 정렬 수행 if (lo < hi) { // partition을 수행하고 피벗의 최종 위치 얻음 int pivot = partition(arr, lo, hi); // 피벗 기준 왼쪽 부분 배열을 재귀적으로 정렬 Quicksort(arr, lo, pivot - 1); // 피벗 기준 오른쪽 부분 배열을 재귀적으로 정렬 Quicksort(arr,pivot + 1, hi); } return arr; }
Java
복사
array=[5, 7, 9, 0, 3, 1, 6, 2, 4, 8] def quickSort(data, start, end): if start >= end: # 원소가 1개인 경우 종료 return pivot = start # 피벗은 첫 번째 원소 left = start +1 right = end while left <= right: while left <= end and data[left] <= data[pivot]: # 피벗보다 큰 데이터를 찾을 때까지 반복 left += 1 while right > start and data[right] >= data[pivot]: # 피벗보다 작은 데이터를 찾을 때까지 반복 right -= 1 if left > right: # 엇갈렸다면 작은 데이터와 피벗을 교체 data[right],data[pivot]=data[pivot],data[right] else: # 엇갈리지 않았다면 작은 데이터와 큰 데이터를 교체 data[left],data[right]=data[right],data[left] quickSort(data, start, right-1) # 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬 수행 quickSort(data, right+1, end) quickSort(array, 0, len(array)-1) print(array)
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
array=[5, 7, 9, 0, 3, 1, 6, 2, 4, 8] def quickSort(data): if len(data) <= 1: # 리스트가 하나 이하의 원소만을 담고 있다면 종료 return data pivot=data[0] # 피벗은 첫 번째 원소 tail=data[1:] # 피벗을 제외한 리스트 left_side=[x for x in tail if x <= pivot] # 분할된 왼쪽 부분 right_side = [x for x in tail if x > pivot] # 분할된 오른쪽 부분 result= quickSort(left_side) + [pivot] + quickSort(right_side) return result # 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬을 수행하고, 전체 리스트를 반환 print(quickSort(array))
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
array=[5, 7, 9, 0, 3, 1, 6, 2, 4, 8] def quickSort(data, start, end): pivot = data[(start+end)//2] # 피벗은 가운데 원소 left, right = start, end while True: while data[left] < pivot: left += 1 while data[right] > pivot: right -= 1 if left >=right: break data[left], data[right] = data[right], data[left] if start < right: quickSort(data, start, right) if left < end: quickSort(data, right+1, end) quickSort(array, 0, len(array)-1) print(array)
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

1.6. 힙 정렬

void heapSort(int[] arr) { for (int i = arr.length / 2 - 1; i < arr.length; i++) { heapify(arr, i, arr.length - 1); } for (int i = arr.length - 1; i >= 0; i--) { swap(arr, 0, i); heapify(arr, 0, i - 1); } } void heapify(int[] arr, int parentIdx, int lastIdx) { int leftChildIdx; int rightChildIdx; int largestIdx; while (parentIdx * 2 + 1 <= lastIdx) { leftChildIdx = (parentIdx * 2) + 1; rightChildIdx = (parentIdx * 2) + 2; largestIdx = parentIdx; if (arr[leftChildIdx] > arr[largestIdx]) { largestIdx = leftChildIdx; } if (rightChildIdx <= lastIdx && arr[rightChildIdx] > arr[largestIdx]) { largestIdx = rightChildIdx; } if (largestIdx != parentIdx) { swap(arr, parentIdx, largestIdx); parentIdx = largestIdx; } else { break; } } }
Java
복사
array=[16, 9, 8, 14, 12, 10, 3] def heapify(data, n, i): # 힙을 구성하는 함수 largest = i # 루트 노드를 가장 큰 값으로 설정 left = 2*i+1 # 왼쪽 자식 노드 right = 2*i+2 # 오른쪽 자식 노드 if left < n and data[i] < data[left]: # 왼쪽 자식 노드가 부모 노드보다 큰 경우 largest=left if right < n and data[largest] < data[right]: # 오른쪽 자식 노드가 부모 노드나 가장 큰 자식 노드보다 큰 경우 largest = right if largest != i: # 가장 큰 노드를 부모 노드로 설정하고, 재귀적으로 힙을 구성 data[i], data[largest] = data[largest], data[i] heapify(data, n, largest) def heapSort(data): # 힙 정렬 함수 n=len(data) for i in range(n//2-1, -1, -1): # 최대 힙을 구성 heapify(data, n, i) for i in range(n-1, 0, -1): # 힙에서 요소를 하나씩 추출하여 정렬된 리스트에 추가 data[i], data[0] = data[0], data[i] # 루트 노드와 맨 마지막 요소를 교환 heapify(data, i, 0) # 힙 구성 heapSort(array) print(array)
Python
복사
[3, 8, 9, 10, 12, 14, 16]

1.6.1. 파이썬 heap 라이브러리

힙 정렬은 max heap이나 min heap 트리를 이용한 정렬 방식으로 내림차순 정렬을 위해서는 max heap이, 오름차순 정렬을 위해서는 min heap이 사용된다
heappush(): 힙에 데이터를 삽입하는 함수
heappop(): 힙에 데이터를 삭제하는 함수
1) 오름차순 정렬
파이썬에는 최소 힙(Min Heap)이 구현되어 있기 때문에 원소를 힙에 전부 삽입했다가 제거함으로써 오름차순으로 정렬 할 수 있다.
1.
모든 원소를 차례대로 heap에 삽입한다.
2.
힙에 삽입된 모든 원소를 차례대로 result에 담는다.
import heapq def heapsort(iterable): h = [] result = [] for value in iterable: # 모든 원소를 차례대로 힙에 삽입 heapq.heappush(h, value) for i in range(len(h)): # 힙에 삽입된 원소를 차례대로 꺼내어 담기 result.append(heapq.heappop(h)) return result result = heapsort([7, 5, 9, 0, 3, 1, 6, 2, 4, 8]) print(result)
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
from heapq import heappush, heappop array=[7, 5, 9, 0, 3, 1, 6, 2, 4, 8] def heapSort(iterable): h=[] for value in iterable: heappush(h, value) return [heappop(h) for i in range(len(h))] print(heapSort(array))
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2) 내림차순 정렬
파이썬에는 최대 힙(Max Heap)이 구현되어 있지 않기 때문에 내림차순 정렬을 위해서는 부호를 바꾼 뒤 최소 힙을 이용하여 정렬하고 다시 부호를 바꿔주어야 한다.
1.
모든 원소에 -를 붙인 값을 heap에 삽입한다.
2.
heap의 원소를 꺼낸 뒤 다시 -를 붙여 result에 담는다.
def heapsort(iterable): h = [] result = [] for value in iterable: # 모든 원소를 차례대로 힙에 삽입 heapq.heappush(h, -value) for i in range(len(h)): # 힙에 삽입된 원소를 차례대로 꺼내어 담기 result.append(-heapq.heappop(h)) return result result = heapsort([7, 5, 9, 0, 3, 1, 6, 2, 4, 8]) print(result)
Python
복사
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

1.7. 계수 정렬

array=[7, 5, 9, 0, 3, 1, 6, 2, 9, 1, 4, 8, 0, 5, 2] 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=' ') # 띄어쓰기를 구분으로 등장한 횟수만큼 인덱스 출력
Python
복사
0 0 1 1 2 2 3 4 5 5 6 7 8 9 9
array=[7, 5, 9, 0, 3, 1, 6, 2, 9, 1, 4, 8, 0, 5, 2] def countingSort(array): count = {} result =[] for num in array: count[num] = count.get(num,0)+1 for num in range(min(array), max(array)+1): while num in count and count[num] != 0: result.append(num) count[num] -= 1 return result print(countingSort(array))
Python
복사
[0, 0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9]

2. 파이썬의 정렬 라이브러리

정렬함수: sort(), sorted()
정렬 함수에 들어갈 수 있는 인자
key: 정렬 기준을 정하는 함수를 기반으로 정렬
reverse: 오름차순/내림차순 여부를 결정
array=[7, 5, 9, 0, 3, 1, 6, 2, 4, 8] result1=sorted(array) result2=sorted(array, reverse=True) print(result1) print(result2)
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
array=[7, 5, 9, 0, 3, 1, 6, 2, 4, 8] array.sort() print(array)
Python
복사
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
array=[('바나나',2),('사과',5),('당근',3)] def setting(data): return data[1] result=sorted(array, key=setting) print(result)
Python
복사
[('바나나', 2), ('당근', 3), ('사과', 5)]
array=[[0, 4], [0, 2], [1, 3], [2, 1]] def second(x): return x[1] print(sorted(array, key=second)) print(sorted(array, key=lambda x: x[1]))
Python
복사
[[2, 1], [0, 2], [1, 3], [0, 4]]
[[2, 1], [0, 2], [1, 3], [0, 4]]

3. 자바의 정렬 라이브러리

4. 예제

4.1. 위에서 아래로

하나의 수열에는 다양한 수가 존재한다. 이러한 수는 크기에 상관없이 나열되어 있다.
이 수를 큰 수부터 작은 수의 순서로 정렬해야 한다. 수열을 내림차순으로 정렬하는 프로그램을 작성하시오.
<입력조건>
첫째 줄에 수열에 속해 있는 수의 개수 N이 주어진다(1<=N<=500)
둘째 줄부터 N+1번째 줄까지 N개의 수가 입력된다. 수의 범위는 1이상 100,000이하의 자연수이다.
<출력조건>
입력으로 주어진 수열이 내림차순으로 정렬된 결과를 공백으로 구분하여 출력한다.
동일한 수의 순서는 자유롭게 출력해도 괜찮다.
n=int(input()) array=[] for i in range(n): array.append(int(input())) array=sorted(array, reverse=True) for i in array: print(i, end=' ')
Python
복사
3
15
27
12
27 15 12

4.2 성적이 낮은 순서로 학생 출력하기

N명의 학생 정보가 있다. 학생 정보는 학생의 이름과 학생의 성적으로 구분된다.
각 학생의 이름과 성적 정보가 주어졌을 때 성적이 낮은 순서대로 학생의 이름을 출력하는 프로그램을 작성하시오.
<입력조건>
첫 번째 줄에 학생의 수 N이 입력된다.(1<=N<=1,000,0001 <= N <= 1,000,000)
두 번째 줄부터 N+1번째 줄에는 학생의 이름을 나타내는 문자열 A와 학생의 성적을 나타내는 정수 B가 공백으로 구분되어 입력된다.문자열 A의 길이와 학생의 성적은 100이하의 자연수이다.
<출력조건>
모든 학생의 이름을 성적이 낮은 순서대로 출력한다.
성적이 동일한 학생들의 순서는 자유롭게 출력해도 괜찮다.
n = int(input()) array = [] for i in range(n): data = input().split() array.append((data[0], int(data[1]))) array.sorted(array, key=lambda student: student[1]) for student in array: print(student[0], end=' ')
Python
복사
2
홍길동 95
이순신 77
이순신 홍길동