정수를 요소로 갖는 배열을 입력받아 오름차순으로 정렬하여 리턴해야 합니다.
버블 정렬(bubble sort)은 여러 정렬 알고리즘(삽입 정렬, 퀵 정렬, 병합 정렬, 기수 정렬 등) 중 가장 기본적인 알고리즘입니다.
버블 정렬 알고리즘은 아래와 같습니다.
이 모습이 마치 '거품이 밀려 올라가는 것과 같은 모습'과 같아서 bubble sort라고 부릅니다.
let output = bubbleSort([2, 1, 3]);
console.log(output); // --> [1, 2, 3]
Advanced
const bubbleSort = function (arr) {
for(let i = 0; i < arr.length; i++){
let temp = arr[i];
if(temp > arr[i+1]){
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
return arr;
};
➡️ 위의 코드는 arr.length가 3일때에만 작동하고, 그 외의 케이스에서는 오류
const bubbleSort = function (arr) {
for(let i = 0; i < arr.length; i++){
let temp;
for(let j = 0; j < arr.length - 1;j++){
if(arr[j] > arr[j + 1]){
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
if(!temp) break;
}
return arr;
};
/*
arr = [5, 4, 3, 2, 1] 인 경우, 이중 for문을 돌린다면
i=0
j=0 arr[0] > arr[1] => temp = arr[0] = 5 => [4, 5, 3, 2, 1]
j=1 arr[1] > arr[2] => temp = arr[1] = 5 => [4, 3, 5, 2, 1]
j=2 arr[2] > arr[3] => temp = arr[2] = 5 => [4, 3, 2, 5, 1]
j=3 arr[3] > arr[4] => temp = arr[3] = 5 => [4, 3, 2, 1, 5]
j=4 arr[4] > arr[5] => false 이기 때문에 if문 실행 X
temp = 5 이므로 i++
=> arr = [4, 3, 2, 1, 5]
i=1
j=0 arr[0] > arr[1] => temp = arr[0] = 4 => [3, 4, 2, 1, 5]
j=1 arr[1] > arr[2] => temp = arr[1] = 4 => [3, 2, 4, 1, 5]
j=2 arr[2] > arr[3] => temp = arr[2] = 4 => [3, 2, 1, 4, 5]
j=3 arr[3] > arr[4] => false 이기 때문에 if문 실행 X
j=4 arr[4] > arr[5] => false 이기 때문에 if문 실행 X
temp = 4 이므로 i++
=> arr = [3, 2, 1, 4, 5]
i=2
j=0 arr[0] > arr[1] => temp = arr[0] = 3 => [3, 2, 1, 4, 5]
j=1 arr[1] > arr[2] => temp = arr[1] = 3 => [2, 3, 1, 4, 5]
j=2 arr[2] > arr[3] => temp = arr[2] = 3 => [2, 1, 3, 4, 5]
j=3 arr[3] > arr[4] => false 이기 때문에 if문 실행 X
j=4 arr[4] > arr[5] => false 이기 때문에 if문 실행 X
temp = 3 이므로 i++
=> arr = [2, 1, 3, 4, 5]
i=3
j=0 arr[0] > arr[1] => temp = arr[0] = 2 => [1, 2, 3, 4, 5]
j=1 arr[1] > arr[2] => false 이기 때문에 if문 실행 X
j=2 arr[2] > arr[3] => false 이기 때문에 if문 실행 X
j=3 arr[3] > arr[4] => false 이기 때문에 if문 실행 X
j=4 arr[4] > arr[5] => false 이기 때문에 if문 실행 X
temp = 2 이므로 i++
=> arr = [1, 2, 3, 4, 5]
i=4
j=0 arr[0] > arr[1] => false 이기 때문에 if문 실행 X
j=1 arr[1] > arr[2] => false 이기 때문에 if문 실행 X
j=2 arr[2] > arr[3] => false 이기 때문에 if문 실행 X
j=3 arr[3] > arr[4] => false 이기 때문에 if문 실행 X
j=4 arr[4] > arr[5] => false 이기 때문에 if문 실행 X
temp = undefined 이므로 break으로 for문 탈출
*/
const getSwap = (idx1, idx2, arr) => {
// 1) 임시 변수를 활용
// let temp = arr[idx1];
// arr[idx1] = arr[idx2];
// arr[idx2] = temp;
// 2) Destructuring assignment를 활용(arr가 reference type이라 가능)
return [arr[idx1], arr[idx2]] = [arr[idx2], arr[idx1]];
};
const bubbleSort = (arr) => {
const arrLength = arr.length;
for (let i = 0; i < arrLength; i++) {
let swaps = 0;
for (let j = 0; j < arrLength - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swaps++;
getSwap(j, j + 1, arr);
}
}
if (swaps === 0) break;
}
return arr;
};
/*
# CASE 1
arr = [2, 1, 3]
i=0, swaps=0
j=0 arr[0] > arr[1] => swaps=1, getSwap(2, 1, arr) => arr = [1, 2, 3]
j=1 arr[1] > arr[2] => false
i=1, swaps=0
j=0, arr[0] > arr[1] => false
swap이 0이므로 for문 탈출
# CASE 2
arr = [5, 4, 3, 2, 1]
i=0
j=0 arr[0] > arr[1] => swaps=1, getSwap(5, 4, arr) => arr = [4, 5, 3, 2, 1]
j=1 arr[1] > arr[2] => swaps=2, getSwap(5, 3, arr) => arr = [4, 3, 5, 2, 1]
j=2 arr[2] > arr[3] => swaps=3, getSwap(5, 2, arr) => arr = [4, 3, 2, 5, 1]
j=3 arr[3] > arr[4] => swaps=4, getSwap(5, 1, arr) => arr = [4, 3, 2, 1, 5]
=> arr = [4, 3, 2, 1, 5]
i=1
j=0 arr[0] > arr[1] => swaps=1, getSwap(4, 3, arr) => arr = [3, 4, 2, 1, 5]
j=1 arr[1] > arr[2] => swaps=2, getSwap(4, 2, arr) => arr = [3, 2, 4, 1, 5]
j=2 arr[2] > arr[3] => swaps=3, getSwap(4, 1, arr) => arr = [3, 2, 1, 4, 5]
=> arr = [3, 2, 1, 4, 5]
i=2
j=0 arr[0] > arr[1] => swaps=1, getSwap(3, 2, arr) => arr = [2, 3, 1, 4, 5]
j=1 arr[1] > arr[2] => swaps=2, getSwap(3, 1, arr) => arr = [2, 1, 3, 4, 5]
=> arr = [2, 1, 3, 4, 5]
i=3
j=0 arr[0] > arr[1] => swaps=1, getSwap(2, 1, arr) => arr = [1, 2, 3, 4, 5]
=> arr = [1, 2, 3, 4, 5]
i=4
안쪽 for문은 지나치게 되고, swaps가 0이기 때문에 break로 for문 탈출
*/
✅ 음 이렇게 다 써내려가면서 보니, 레퍼런스 코드 동작 방식이 훨씬 효율적이네