var bubbleSort = function(array) {
var length = array.length;
var i, j, temp;
for (i = 0; i < length - 1; i++) { // 순차적으로 비교하기 위한 반복문
for (j = 0; j < length - 1 - i; j++) { // 끝까지 돌았을 때 다시 처음부터 비교하기 위한 반복문
if (array[j] > array[j + 1]) { // 두 수를 비교하여 앞 수가 뒷 수보다 크면
temp = array[j]; // 두 수를 서로 바꿔준다
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
return array;
};
//javascript
function selectionSort(arr) {
for (let i = 0; i < arr.length; i++) {
let min_index = i;
for (let j = i + 1; j < arr.length; j++) {
if (arr[min_index] > arr[j]) {
min_index = j;
}
}
let temp = arr[min_index];
arr[min_index] = arr[i];
arr[i] = temp;
}
return arr;
}
#python
def selectionSort(arr) {
for i in range(len(arr)):
min_index = i
for j in range(i+1, len(arr)):
if arr[min_index] > arr[j]:
min_index = j
arr[i], arr[min_index] = arr[min_index], arr[i]
return arr
}
//javascript
function insertIndex(sorted_arr, value) {
for(let i in sorted_arr){
if(value < sorted_arr[i]){
return i;
}
}
return sorted_arr.length;
}
function insertSort(arr) {
let sorted_arr = [];
while (arr.length != 0){
let value = arr.shift();
let index = insertIndex(sorted_arr, value);
sorted_arr.splice(index, 0, value);
}
return sorted_arr;
}
#python
def insertSort(array):
for i in range(1,len(array)):
for j in range(i, 0, -1):
if array[j] < array[j - 1]:
array[j], array[j - 1] = array[j - 1], array[j]
else:
break
return array
function mergeSort(arr){
if (arr.length <= 1){
return arr;
}
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right){
let result = [];
while (left.length && right.length){
if (left[0] < right[0]){
result.push(left.shift());
} else {
result.push(right.shift());
}
}
while (left.length) {
result.push(left.shift());
}
while (right.length) {
result.push(right.shift());
}
return result;
}
재귀 호출이 한번 진행될 때마다 최소한 하나의 원소는 최종적으로 위치가 정해지므로, 이 알고리즘은 반드시 끝난다는 것을 보장할 수 있다.
//javascript
function quickSort(arr){
if (arr.length <= 1){
return arr;
}
const pivot = arr[0]; //기준점
const left = [];
const right = [];
for (let i=1; i<arr.length; i++){
if(arr[i] < pivot){
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quickSort(left).concat(pivot, quickSort(right));
}
#python
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)
# 모든 원소의 값이 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=' ') # 띄어쓰기를 구분으로 등장한 횟수만큼 인덱스 출력
힙 정렬은 완전 이진 트리를 기본으로 하는 힙(Heap) 자료구조를 기반으로한 정렬 방식이다. (완전 이진 트리는 삽입할 때 왼쪽부터 차례대로 추가하는 이진 트리를 말한다)
힙에는 부모 노드의 값이 자식 노드의 값보다 항상 큰 최대 힙과 그 반대인 최소 힙이 존재한다.
주의할 점은 부모-자식 관계간의 이야기이고, 형제간은 고려하지 않는다.
시간복잡도는 worst, best, average 모두 O(nlogn) 을 가진다.
위와 같은 방식으로 힙 정렬을 할 수 있다. 랜덤한 순서의 숫자들을 힙으로 만들어 넣고, 힙에서 하나씩 제거하면 된다. 가장 큰 값 또는 가장 작은 값 순서로 빠지기 때문에 알아서 정렬이 된다.
그렇다면 당연히 최악의 경우에도 조금 더 빠른 힙 정렬이 좋은 거 아닌가?
그렇게 단순한 문제가 아니다. Big-O notation은 컴퓨터 계산 속도의 대략적인 측정 방법이고, 힙 정렬에는 Heapify 라는 특수한 작업이 있다. 바로 정렬되는 값이 힙에서 빠져나오면서 다시 힙 상태로 돌아가기 위해 원소들끼리 자리를 바꾸는 작업이다.
데이터가 많지 않다면 큰 영향이 없겠지만, 많은 수의 데이터를 정렬하고자 한 다면 Heapify 작업에서의 swap 수행은 무시할 수 없게 된다.