특징 | 정렬 배열에서 사용 가능, 범위를 반으로 나눠서 탐색하는 방식 |
---|---|
장점 | 신속함 |
단점 | 정렬 배열에서 효율적. 삽입, 삭제 등 동적인 작업에는 부적합 |
안정성 | 안정 |
체크 요소 | 탐색 대상의 정렬 상태 |
시간 복잡도 | O(logN) |
function binarySearch(arr, target) {
let low = 0;
let high = arr.length - 1;
while (low <= high) {
let mid = Math.floor((low + high) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1; // 탐색 실패
}
// Ex
const arr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20];
const target = 12;
const result = binarySearch(arr, target);
if (result !== -1) {
console.log("탐색 성공! 인덱스:", result);
} else {
console.log("탐색 실패!");
}
특징 | 해시 함수로 데이터를 해시 테이블에 저장, 상수 시간 내 탐색 |
---|---|
장점 | 매우 신속. 데이터 크기에 관계없는 상수 시간 복잡도 |
단점 | 해시 충돌 위험성. 해시 함수의 성능과 충돌 처리 방법에 따른 성능 영향. 순서 보장 X |
안정성 | 안정적이나 순서가 보장되지 않음 |
체크 요소 | 충돌 처리 가능한 공간, 해시 함수 성능 |
시간 복잡도 | 평균: O(1), 최악: O(N) - 해시 충돌의 경우 |
class HashTable {
constructor(size) {
this.size = size;
this.table = new Array(size).fill(null);
}
hashFunction(key) {
return key % this.size;
}
insert(key, value) {
const index = this.hashFunction(key);
if (this.table[index] === null) {
this.table[index] = [];
}
this.table[index].push({ key, value });
}
search(key) {
const index = this.hashFunction(key);
if (this.table[index] !== null) {
for (const item of this.table[index]) {
if (item.key === key) {
return item.value;
}
}
}
return null;
}
}
// Ex
const hashTable = new HashTable(10);
hashTable.insert(5, "Apple");
hashTable.insert(15, "Banana");
hashTable.insert(25, "Orange");
console.log(hashTable.search(15)); // 출력: Banana
console.log(hashTable.search(10)); // 출력: null (탐색 실패)
특징 | 배열의 모든 요소를 순차적으로 탐색 |
---|---|
장점 | 간단. 비정렬 배열에 사용 가능 |
단점 | 최악: O(N) - 선형 증가 |
안정성 | 안정 |
체크 요소 | 큰 배열의 경우 성능 저하 |
시간 복잡도 | O(N) |
function linearSearch(arr, target) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === target) {
return i;
}
}
return -1; // 탐색 실패
}
// Ex
const arr = [3, 1, 5, 2, 4];
const target = 5;
const result = linearSearch(arr, target);
if (result !== -1) {
console.log("탐색 성공! 인덱스:", result);
} else {
console.log("탐색 실패!");
}
특징 | 연결 리스트 같은 순차 구조에서 요소를 하나씩 탐색 |
---|---|
장점 | 간단, 비정렬 데이터 구조에 사용 가능 |
단점 | 최악: O(N) - 선형 증가 |
안정성 | 안정 |
체크 요소 | 탐색하는 데이터 구조 특성에 따른 성능 변동 |
시간 복잡도 | O(N) |
function sequentialSearch(arr, target) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === target) {
return i;
}
}
return -1; // 탐색 실패
}
// Ex
const arr = [3, 1, 5, 2, 4];
const target = 5;
const result = sequentialSearch(arr, target);
if (result !== -1) {
console.log("탐색 성공! 인덱스:", result);
} else {
console.log("탐색 실패!");
}
특징 | 해시 함수로 대용량의 데이터를 해시 테이블에 저장, 상수 시간 내에 탐색 |
---|---|
장점 | 대용량 데이터에서도 신속 |
단점 | 해시 충돌 위험성, 해시 함수 성능과 충돌 처리 방법에 따른 성능 변동. 순서 보장 X |
안정성 | 안정적이나 순서가 보장되지 않음 |
체크 요소 | 충돌 처리 가능한 공간, 해시 함수 성능 |
시간 복잡도 | 평균: O(1), 최악: O(N) |
class BTreeNode {
constructor(order) {
this.order = order;
this.keys = [];
this.children = [];
}
isLeaf() {
return this.children.length === 0;
}
}
class BTree {
constructor(order) {
this.order = order;
this.root = new BTreeNode(order);
}
insert(key) {
if (this.root.keys.length === 2 * this.order - 1) {
const newRoot = new BTreeNode(this.order);
newRoot.children.push(this.root);
this.splitChild(newRoot, 0, this.root);
this.root = newRoot;
}
this.insertNonFull(this.root, key);
}
insertNonFull(node, key) {
let i = node.keys.length - 1;
if (node.isLeaf()) {
while (i >= 0 && key < node.keys[i]) {
node.keys[i + 1] = node.keys[i];
i--;
}
node.keys[i + 1] = key;
} else {
while (i >= 0 && key < node.keys[i]) {
i--;
}
i++;
if (node.children[i].keys.length === 2 * this.order - 1) {
this.splitChild(node, i, node.children[i]);
if (key > node.keys[i]) {
i++;
}
}
this.insertNonFull(node.children[i], key);
}
}
splitChild(parent, index, child) {
const newChild = new BTreeNode(this.order);
const middleIndex = Math.floor(this.order / 2) - 1;
for (let i = middleIndex + 1; i < child.keys.length; i++) {
newChild.keys.push(child.keys[i]);
}
child.keys.length = middleIndex + 1;
if (!child.isLeaf()) {
for (let i = middleIndex + 1; i < child.children.length; i++) {
newChild.children.push(child.children[i]);
}
child.children.length = middleIndex + 1;
}
parent.keys.splice(index, 0, child.keys.pop());
parent.children.splice(index + 1, 0, newChild);
}
}
// Ex
const bTree = new BTree(2);
bTree.insert(4);
bTree.insert(8);
bTree.insert(15);
bTree.insert(7);
bTree.insert(12);
console.log(bTree.root); // BTreeNode 객체 출력
B트리는 강의도 몇 개 보고 chat GPT한테 예시 코드를 물어봐도 정말 모르겠다.
모르는 걸 왜 블로깅하냐?
나중에 내가 이 시점에는 이걸 몰랐다는 것을 알기 위해서...
데일리 코딩 풀이나 하겠습니다
29번~ 회전된 배열에서의 이진 탐색~
부분적으로 오름차순 정렬*된 정수의 배열(rotated)과 정수(target)를 입력받아
target의 인덱스를 리턴해야 합니다.
부분적으로 정렬된 배열
배열을 왼쪽 혹은 오른쪽으로 0칸 이상 순환 이동할 경우 완전히 정렬되는 배열
예시
[4, 5, 6, 0, 1, 2, 3]은 왼쪽으로 3칸 또는 오른쪽으로 4칸 순환 이동할 경우 완전히 정렬됩니다.
입력
인자 1 | 인자 2 |
---|---|
rotated | target |
number 타입을 요소로 갖는 배열 | number 타입의 정수 |
rotated[i]는 정수 |
출력
number 타입을 리턴해야 합니다.
주의사항
rotated에 중복된 요소는 없습니다.
target이 없는 경우, -1을 리턴해야 합니다.
const rotatedArraySearch = function (rotated, target) {
for (let i = 0; i < rotated.length; i++) {
if (rotated[i] === target) {
return i;
}
}
return -1;
};
1.left: 0, right: arr.length - 1
2.left <= right 일 때 반복
3.mid: (left + right) / 2
4-0. rotated[mid] === target ? return mid
4-1. rotated[left] <= rotated[mid] ? 왼쪽 배열 정렬됨
4-1-1. rotated[left] < target < rotated[mid] ? right = mid - 1
4-1-2. else ? left = mid + 1
4-2. rotated[mid] < rotated[right] ? 오른쪽 배열 정렬됨
4-2-1. rotated[mid] < target < rotated[right] ? left = mid + 1
4-2-2. else? right = mid - 1
4-3. 반복 종료
5. target 없으면 ? return -1
const rotatedArraySearch = function (rotated, target) {
// TODO : 여기에 코드를 작성합니다.
let left = 0;
let right = rotated.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (rotated[mid] === target) {
return mid;
}
if (rotated[left] <= rotated[mid]) {
if (target >= rotated[left] && target < rotated[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
if (target > rotated[mid] && target <= rotated[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
};
애초에 힌트로 이진 탐색을 줘서 어드밴스드 버전으로 먼저 풀어 봤다.
이진 탐색이랑 비슷하긴 한데 추가 조건문으로 배열이 회전됐다는 걸 고려하면 됐다.
mid vs 타겟 비교, mid의 좌우 배열 중에서 탐색했다.
조건이 생각보다 많아서 좀 당황했다...
그래서 진짜 처음에 작성한 의사 코드는
이거였다. 이렇게 적으니까 좀 괜찮긴 했는데...
아니... 기계처럼 생각하기 너무 어렵네?