티스토리 뷰
코딩테스트/알고리즘 & 자료구조 개념
[알고리즘 | JS] sorting algorithm(정렬 알고리즘)6 - radix sort
blueprint-12 2023. 2. 24. 21:38이전에 배웠던 정렬알고리즘 5개는 기본적으로 comparison sorts(비교 정렬)이다.
배열의 요소를 하나 하나 비교하면서 정렬했던 것이기 때문이다.(e.g. 두 요소의 크기를 비교해서 어느 위치로 옮기고 하는 작업)
아래는 기존에 배웠던 정렬 알고리즘의 평균 시간 복잡도(big O표현)이다.
- bubble sort - O(n^2)
- Insetion sort - O(n^2)
- selection sort - O(n^2)
- quick sort - O(n log (n))
- merge sort - O(n log (n))
결과를 보면 알 수 있겠지만 최대 효율이나도 n log n이 한계이다.
여기서 어떻게 더 발전할 수 있을까?
-> 비교를 통해 정렬하는 sort 알고리즘 외에 다른 유형의 sort 알고리즘이 존재한다.
이 다른 유형의 알고리즘은 데이터의 특별한 속성을 이용한다.
radix sort (기수 정렬)
- 비교를 통해 정렬하는 것이 아니라 데이터의 속성을 이용한 특별한 정렬 알고리즘
- 비교를 수행하지 않는다.(무엇이 더 작은 지, 큰 지 묻지 않음)
- 숫자로 작동한다(숫자 크기에 대한 정보를 자릿수로 인코딩한다는 사실을 이용).
- e.g.) 자릿수가 더 큰 수, 예를 들어 4자리 수가 있다면 2자리 수보다 더 크다는 것
- 보통, 실제로 사용할 때는 이진수를 이용한다. + 원하는 문자열이나 이미지를 가져와 이진 형식으로 바꿀수도 있다(but, 정렬할 때 사용할 실제 데이터는 숫자여야만 한다!)
- digit은 0 과 9 사이의 수를 말한다.
- 버킷 정렬의 일종으로 취급되기도 한다.
1-1. 기수 정렬 helper 만들기
// TODO: 자릿수 알아내기 (getDigit)
{
//abs는 음수를 고려하기 위해서 사용된 메서드
function getDigit(num, i) {
//Math.pow는 제곱 계산
return Math.floor(Math.abs(num) / Math.pow(10, i)) % 10;
}
console.log(getDigit(2234, 3));
//100의 자리에 있는 수를 구하는 거니까 3을 i로 잡고 2234에서 2를 리턴
function digitCount(num) {
//digitCount ->num이 몇자리 수인지 알려주는 함수
//Math.log10 -> 밑이 10인 로그, 10의 어떤 거듭제곱으로 이 수(num)가 되는 지 묻는다.
//num이 0일 경우에는 log10을 할때 infinity값을 갖게되기때문에 return 1 을 해준다.
if (num === 0) return 1;
return Math.floor(Math.log10(Math.abs(num))) + 1;
}
console.log(digitCount(2235234)); // 7 (7자리수)
//TODO: mostDigits(nums) -> 인자로 숫자들이 담긴 배열을 주고 가장 큰 숫자의 digits를 반환한다.
function mostDigits(nums) {
let maxDigits = 0;
// Math.max(0,12) => 두 숫자 중 더 큰 수를 반환한다.
//if문을 사용해서 x(최대 자릿수)가 현재 최댓값보다 클 경우 현재 최댓값으로 재할당하도록 작성하는 대신
//자릿수 최댓값(maxDigits)를 현재 최댓값과 nums[i]의 자릿수 계산(digitCount)중 큰 값과 같도록 설정할 수 있다.
for (let i = 0; i < nums.length; i++) {
maxDigits = Math.max(maxDigits, digitCount(nums[i]));
}
return maxDigits;
}
}
- 숫자 값이 아니라 해당 자리의 값(digit)을 구하는 것이므로 왼쪽부터 오른쪽으로가 아니라 오른쪽부터 왼쪽으로 찾는다. (10의 0제곱 = 1 오른쪽부터 0번째 자리, 10의 1제곱 = 오른쪽부터 1번째 자리, 10의 2제곱, 오른쪽부터 2번째자리)
// getDigit(num, place) - returns the digit in num at the given place value
getDigit(12345, 0); // 5
getDigit(12345, 1); // 4
getDigit(12345, 2); // 3
// digit 은 왼쪽부터가 아니라 오른쪽부터 카운트이다. 0번째 요소니까 5를 리턴한다.
1-2. 기수 정렬 구현
// TODO: Radix sort function
// loop는 maxDigits 만큼 돈다.
// 각 loop의 순회에 bucket을 만든다. *bucket은 []빈배열이다.
{
//위에 만든 helper 함수 --- 생략 ----
function radixSort(nums) {
let maxDigitsCount = mostDigits(nums);
for (let k = 0; k < maxDigitsCount; k++) {
//Array.from으로 배열 10개를 만들어준다.
let digitBuckets = Array.from({ length: 10 }, () => []);
for (let i = 0; i < nums.length; i++) {
let digit = getDigit(nums[i], k); //digit이 3이면 3번 버켓에 넣어줘야한다.
digitBuckets[digit].push(nums[i]);
}
console.log('digitBuckts :', digitBuckets);
nums = [].concat(...digitBuckets);
console.log('nums :', nums);
}
return nums;
}
radixSort([223, 1, 2464, 7456, 234, 4, 2, 664]);
}
2. 기수 정렬의 시간 복잡도
최상, 평균, 최악의 시간 복잡도: O(nk)이다.
- n은 정렬할 항목 수나 정수의 수이고, k는 기수의 도메인 크기
- n: length of array (배열의 길이로, 정렬하려는 수의 갯수)
- k: number of digits(average)
- 정수와 같은 자료의 정렬 속도가 매우 빠르다. 하지만, 데이터 전체 크기에 기수 테이블의 크기만한 메모리가 더 필요하다.
- 부동소수점 실수처럼 특수한 비교 연산이 필요한 데이터에는 적용할 수 없다.
- 주의) 모든 수가 고유하고, 무작위로 분산된 데이터를 다룰 때에는 n log n이 된다.
- 하지만 위의 경우가 아니라면 보통의 비교 정렬 알고리즘보다 빠르다.
* 공간 복잡도: O(n + k) // k는 기수의 도메인 크기
- 여기서 도메인이란 하나의 속성에서 취할 수 있는 값의 범위를 말한다.
여담:
기수정렬의 k은 가장 큰 요소의 자릿수가 아니라 큰 값 그 자체를 말한다고 한다.
chatGPT answer:
아니요, 기수 정렬에서 k는 정렬되는 요소의 최대값을 나타내며 최대값의 자릿수가 아닙니다.
예를 들어 다음과 같은 숫자 목록이 있다고 가정해 보겠습니다: {170, 45, 75, 90, 802, 24, 2, 66}과 같은 숫자 목록이 있다면 이 목록의 최대값은 802이므로 k는 802와 같습니다. 802의 자릿수가 세 자리라는 사실은 k의 값과 직접적인 관련이 없습니다.
k의 값은 정렬에 필요한 버킷의 수를 결정하는 데 사용됩니다. 구체적으로 말하자면, 각 버킷은 다양한 값을 담을 수 있는 k개의 버킷이 필요합니다. 예를 들어, k가 802이면 가장 큰 숫자에 대해 802개의 버킷이 필요합니다. 그러나 실제로는 일반적으로 버킷당 값 범위로 값을 그룹화한 다음 삽입 정렬과 같은 다른 정렬 알고리즘을 사용하여 범위 내에서 각 버킷을 정렬함으로써 더 적은 수의 버킷을 사용합니다.
기수 정렬의 시간 및 공간 복잡성은 k의 값과 정렬되는 요소의 자릿수, 정렬되는 요소의 수에 따라 달라집니다.
'코딩테스트 > 알고리즘 & 자료구조 개념' 카테고리의 다른 글
[자료구조 | JS ] 단일 연결 리스트(single linked list)와 배열(Array) (0) | 2023.04.17 |
---|---|
[자료구조 | JS] 자료구조를 배우기 전에 기본적으로 알아야하는 개념 ES2015 "class" (0) | 2023.03.05 |
[알고리즘 | JS] sorting algorithm(정렬 알고리즘)5 - quick sort (1) | 2023.02.23 |
[알고리즘 | JS] sorting algorithm(정렬 알고리즘)4 - merge sort (0) | 2023.02.22 |
[알고리즘 | JS] sorting algorithm(정렬 알고리즘)3 - insertion sort (0) | 2023.02.21 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 틸드와 캐럿
- fs모듈 넥스트
- 형제 요소 선택자
- 타입스크립트 장점
- 부트캠프항해
- && 셸 명령어
- 항해99추천비추천
- float 레이아웃
- 프리온보딩 프론트엔드 챌린지 3월
- aspect-ratio
- 원티드 프리온보딩 프론트엔드 챌린지 3일차
- D 플래그
- 원티드 FE 프리온보딩 챌린지
- Prittier
- 원티드 3월 프론트엔드 챌린지
- nvm 설치순서
- reactAPI
- 프리렌더링확인법
- 원티드 프리온보딩 FE 챌린지
- tilde caret
- getServerSideProps
- getStaticPaths
- text input pattern
- is()
- 항해99프론트후기
- grid flex
- 타입스크립트 DT
- nvm경로 오류
- 항해99프론트
- ~ ^
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함