정렬 알고리즘에서 많이 쓰이는 유형과 sort() 원리와 콜백함수를 넣었을때의 작동 구조를 보자
참고 사이트: Tim sort에 대해 알아보자, 형님 감사합니다.
정렬을 구현하는 유형도 여러가지다.
매번 연속된 두개 인덱스를 비교하여, 정한 기준의 값을 뒤로 넘겨 정렬하는 방법
가장 쉬운 정렬
이 정렬 알고리즘은 1부터 비교를 시작하여, n-1개, n-2개,,,1개씩 비교를 반복하며, 선택 정렬과 같이 배열이 어떻게 되어있던지간에 전체 비교를 진행하므로 시간복잡도는 0(n^2)이다.
공간복잡도도 이 또한 단 하나의 배열에서만 진행하므로 0(n)이다.
function bubbleSort (array) {
for (let i = 0; i < array.length; i++) {
let swap;
for (let j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
swap = array[j];
array[j] = array[j + 1];
array[j + 1] = swap;
}
}
// console.log(`${i}회전: ${array}`);
if (!swap) {
break;
}
}
return array;
}
// console.log(bubbleSort([5, 4, 3, 2, 1]));
현재 위치에서, 그 이하의 배열들을 비교하여 자신이 들어갈 위치를 찾아, 그 위치에 삽입
이 정렬 알고리즘 또한 최악의 경우(역으로 정렬되어있을 경우)엔 n-1개,n-2개 ... 1개씩 비교를 반복하여 시간복잡도는 0(n^2)이지만, 이미 정렬되어 있는 경우에는 한번씩 밖에 비교를 하지 않아 시간 복잡도는 0(n)이다.
하지만 상한을 기준으로 하는 Big-0 notation은 최악의 경우를 기준으로 평가하므로 삽입 정렬의 시간복잡도는 0(n^2)이다.
공간복잡도는 단 하나의 배열에서만 진행하므로 0(n)이다.
function insertionSort (array) {
for (let i = 1; i < array.length; i++) {
let cur = array[i];
let left = i - 1;
while (left >= 0 && array[left] > cur) {
array[left + 1] = array[left];
left--;
}
array[left + 1] = cur;
// console.log(`${i}회전: ${array}`);
}
return array;
}
// console.log(insertionSort([5, 4, 3, 2, 1]));
Divide and Conquer, 데이터들을 잘게 쪼갠 다음에 하나로 합치는 과정에서 정렬하는 방법
걍 한마디로
분할 하는 시간은 포함되지 않음, 2개씩 쪼갠 것들을 병합할 때 시간이 걸리기에 좋든 나쁘든 O(nlogn)
(O(nlog₂n)
)로 걸린다. 즉! 데이터 분포에 영향을 덜 받는다.
하지만 쪼갤 때 어디에 담아둘 메모리가 발생하기에 '참조 지역성 원리'에 의해
로직에서 봤듯이 병합정렬은
이렇게 코드를 짜야한다.
function mergeSort (array) {
if (array.length < 2) {
return array;
}
const mid = Math.floor(array.length / 2);
const left = array.slice(0, mid);
const right = array.slice(mid);
return merge(mergeSort(left), mergeSort(right));
function merge (left, right) {
const resultArray = [];
let leftIndex = 0;
let rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
resultArray.push(left[leftIndex]);
leftIndex++;
} else {
resultArray.push(right[rightIndex]);
rightIndex++;
}
}
return resultArray.concat(left.slice(leftIndex), right.slice(rightIndex));
}
}
// console.log(mergeSort([5, 4, 3, 2, 1]));
arr.sort(fuc)
const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);
// expected output: Array ["Dec", "Feb", "Jan", "March"]
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// expected output: Array [1, 100000, 21, 30, 4]
sort()
작동 방식()안에 함수가 들어감
함수의 파라미터로 두개의 값만 받고, 보통 a, b로 작성함
이 함수가 리턴하는 값이 0보다 작을 경우, a가 b보다 앞에 오도록 정렬
이 함수가 리턴하는 값이 0보다 클 경우, b가 a보다 앞에 오도록 정렬
만약 0을 리턴하면, a와 b의 순서를 변경하지 않음(권장x)
걍 단순하게 생각해서 a>b를 1로 두면 오름차순, a<b를 1로 두면 내림차순임
기본값을 도출하는 공식은 arr.sort((a,b) => (a > b) - (a < b));
이다. 이게 어떻게 가능하냐면 맨 밑에 있으니 차근차근 보라
const arr = [2, 1, 3, 10, 1];
arr.sort()
// = arr.sort((a,b) => (a > b) - (a < b));
// [1, 1, 10, 2, 3]
const arr2 = ['banana', 'apple', 'orange']
arr2.sort()
// ['apple', 'banana', 'orange']
const arr = [2, 1, 3, 10, 1];
arr.sort()
// [1, 1, 10, 2, 3]
arr.sort((a, b) => a - b);
// 오름차순, [1, 1, 2, 3, 10]
arr.sort((a, b) => b - a);
// 내림차순, [10, 3, 2, 1, 1]
const arr2 = ['banana', 'apple', 'orange']
arr2.sort()
// 오름차순, ['apple', 'banana', 'orange']
arr2.sort((a, b) => {
if (a < b) return 1;
if (a > b) return -1;
if (a === b) return 0;
// return a < b ? 1 : -1;
})
// 내림차순, ['orange', 'banana', 'apple']
대문자, ... 소문자
이렇게 반환한다. 말 드럽게 안듣는다. 그래서 만약 대소문자 구분 없이 정렬하고 싶으면 소문자나 대문자로 통일 후 정렬해야한다let a = ['ant', 'Bug', 'cat', 'Dog']
a.sort()
// ["Bug", "Dog", "ant", "cat"]
a.sort((a, b) => {
const upperCaseA = a.toUpperCase();
const upperCaseB = b.toUpperCase();
// return upperCaseA > upperCaseB ? 1 : -1;
if (upperCaseA > upperCaseB) return 1;
if (upperCaseA < upperCaseB) return -1;
if (upperCaseA === upperCaseB) return 0;
});
배열에 감싸진 객체도 가능 각각 key와 value를 뽑아 문자열, 숫자처럼 정렬 가능하다!
// value
const arr = [
{name: 'banana', price: 3000},
{name: 'apple', price: 1000},
{name: 'orange', price: 500}
];
arr.sort(function(a, b) {
return a.price - b.price;
});
/*
[
{ name: 'orange', price: 500 },
{ name: 'apple', price: 1000 },
{ name: 'banana', price: 3000 }
]
*/
➡️팁: 배열에 안감싸져있어? 고차함수와 push 조합으로 배열 만들고 하면 되지~
배열타입의 데이터가 입력되고 각 요소는 문자열을 입력받는다. 각 문자열의 2번째 문자를 기준으로 정렬하라는 문제
진짜 어려웠다.
문자열 내 마음대로 정렬하기
slice(n)
을 하여 정렬한 뒤 넣어주고stirngs
에 넣어주고 어쩌고,,function solution(strings, n) {
let newArr = [];
let idx = [];
strings.forEach((str, i) => {
newArr.push(str.slice(n));
idx.push(i);
});
newArr.sort();
let veryNewArr = [];
newArr.forEach((newStr, j) => {
veryNewArr.push(`${strings[idx[j]].slice(0, n)}${newStr}`);
});
return veryNewArr
}
문제: 허무맹랑한 함정에 빠져 광명을 찾지 못하였음, sort
를 1도 이해 못했음,, sort()
의 기준에 대해 이해하고있음 쉬운 문젠데
초기 코드를 다 지우고 다시 했는데 머리가 맑아지며 다시 의사코드를 짰다.
sort()
로 정렬하는데 기준을 잡아주기n
)를 붙여 기준 잡아주기sort()
의 디폴트공식인 (a > b) - (a < b)
을 이용하기function solution(strings, n) {
return strings.sort((a, b) => {
if (a[n] > b[n]) {
return 1;
} else if (a[n] < b[n]) {
return -1;
} else {
return (a > b) - (a < b);
}
});
}
참고: 왜 (a > b) - (a < b)
이게 가능? JS에선 가능
⭐️ truthy, falsy 규칙으로 인해 true == 1
, false == 0
으로 취급돼서 true - false
는 곧 1이고 반대는 -1 이다.