루트(최상위 부모)에서 하위로 뻗어나가는 구조이다.정점은(Node), 자식이 없는 정점(Leaf Node)레벨은 Root로부터 몇 번째 깊이인지차수(Degree) - 자식 수

left = Index * 2;
right = Index * 2 + 1;
Parent = Math.floor(Index / 2);
class Node{
constructor(value){
this.value = value;
this.left = null;
this.right = null;
}
}
class Tree{
constructor(node){
this.root = node;
}
display(){
const queue = new Queue();
queue.enqueue(this.root);
while(queue.size){
const currentNode = queue.dequeue();
console.log(currentNode.value);
if(currentNode.left) queue.enqueue(currentNode.left);
if(currentNode.right) queue.enqueue(currentNode.right);
}
}
}
const tree = new Tree(new Node(9));
tree.root.left = new Node(3);
tree.root.right = new Node(8);
tree.root.left.left = new Node(2);
tree.root.left.right = new Node(5);
tree.root.right.right = new Node(7);
tree.root.left.right.right = new Node(4);
[루트 - 왼쪽 자식 - 오른쪽 자식] 순으로 순회[왼쪽 자식 - 루트 - 오른쪽 자식] 순으로 순회[왼쪽 자식 - 오른쪽 자식 - 루트] 순으로 순회class Queue{
constructor(){
this.queue = [];
this.front = 0;
this.rear = 0;
}
enqueue(value){
this.queue[this.rear++] = value; //rear 영역에 값을 넣고 rear인덱스를 하나 증가
}
dequeue(){
const value = this.queue[this.front];
delete this.queue[this.front];
this.front++;
return value;
}
peek(){ //큐의 가장 앞에 있는 값 알아내기
return this.queue[this.front];
}
size(){ //큐의 길이는 끝 - 처음
return this.rear - this.front;
}
}
const q = new Queue();
class Node{
constructor(value){
this.value = value;
this.left = null;
this.right = null;
}
}
class Tree{
constructor(node){
this.root = node;
}
display(){
const queue = new Queue();
queue.enqueue(this.root);
while(queue.size){
const currentNode = queue.dequeue();
console.log(currentNode.value);
if(currentNode.left) queue.enqueue(currentNode.left);
if(currentNode.right) queue.enqueue(currentNode.right);
}
}
BFS(){ // 너비 우선 탐색 [ 10, 6, 15, 3, 8, 20 ]
const result = [];
const q = new Queue();
q.enqueue(this.root);
console.log(this.root.value);
while(q.front !== q.rear){
const cur = q.dequeue();
result.push(cur.value);
if(cur.left) q.enqueue(cur.left);
if(cur.right) q.enqueue(cur.right);
}
return result;
}
DFSPreOrder(){ // 전위순회 [ 10, 6, 3, 8, 15, 20 ]
const result = [];
function PreOrder(node){
result.push(node.value);
if(node.left) PreOrder(node.left);
if(node.right) PreOrder(node.right);
}
PreOrder(this.root);
return result;
}
DFSInOrder(){ // 중위순회 [ 3, 6, 8, 10, 15, 20 ]
const result = [];
function InOrder(node){
if(node.left) InOrder(node.left);
result.push(node.value);
if(node.right) InOrder(node.right);
}
InOrder(this.root);
return result;
}
DFSPostOrder(){ // 후위순회 [ 3, 8, 6, 20, 15, 10 ]
const result = [];
function PostOrder(node){
if(node.left) PostOrder(node.left);
if(node.right) PostOrder(node.right);
result.push(node.value);
}
PostOrder(this.root);
return result;
}
}
const tree = new Tree(new Node(10));
tree.root.left = new Node(6);
tree.root.right = new Node(15);
tree.root.left.left = new Node(3);
tree.root.left.right = new Node(8);
tree.root.right.right = new Node(20);
class MaxHeap{
constructor() {
this.heap = [null];
}
push(value){
this.heap.push(value);
let currentIndex = this.heap.length - 1 // 현재 인덱스는 힙 길이 - 1
let parentIndex = Math.floor(currentIndex / 2);
while(parentIndex !== 0 && this.heap[parentIndex] < value){
const temp = this.heap[parentIndex];
this.heap[parentIndex] = value; // 부모 위치와 추가된 요소의 인덱스와의 교환
this.heap[currentIndex] = temp;
// 위 작업을 반복하기 위한 로직
currentIndex = parentIndex;
parentIndex = Math.floor(currentIndex / 2);
}
}
pop(){
const returnValue = this.heap[1]; //Root 정점 제거하기 위해
this.heap[1] = this.heap.pop(); //마지막 요소로 루트를 채워줌
//루트로부터 아래로 내려가면서 비교하기 위한 변수들
let currentIndex = 1;
let leftIndex = 2;
let rightIndex = 3;
while(this.heap[currentIndex] < this.heap[leftIndex] ||
this.heap[currentIndex] < this.heap[rightIndex]){
if(this.heap[leftIndex] < this.heap[rightIndex]){ //왼쪽보다 오른쪽이 클 경우
const temp = this.heap[currentIndex];
this.heap[currentIndex] = this.heap[rightIndex];
this.heap[rightIndex] = temp;
currentIndex = rightIndex;
}
else{
const temp = this.heap[currentIndex];
this.heap[currentIndex] = this.heap[leftIndex];
this.heap[leftIndex] = temp;
currentIndex = leftIndex; //바뀐 후 그 밑의 자식들을 탐색하기 위해
}
leftIndex = currentIndex * 2;
rightIndex = currentIndex * 2 + 1;
}
return returnValue;
}
}
const heap = new MaxHeap();
heap.push(45);
heap.push(36);
heap.push(100);
heap.push(57);
heap.push(27);
heap.push(39);
heap.push(66);
console.log(heap.pop()); //100
console.log(heap.heap); // [ null, 66, 57, 45, 36, 27, 39]
class MinHeap{
constructor() {
this.heap = [null];
}
push(value){
this.heap.push(value);
let currentIndex = this.heap.length - 1 // 현재 인덱스는 힙 길이 - 1
let parentIndex = Math.floor(currentIndex / 2);
while(parentIndex !== 0 && this.heap[parentIndex] > value){
const temp = this.heap[parentIndex];
this.heap[parentIndex] = value; // 부모 위치와 추가된 요소의 인덱스와의 교환
this.heap[currentIndex] = temp;
// 위 작업을 반복하기 위한 로직
currentIndex = parentIndex;
parentIndex = Math.floor(currentIndex / 2);
}
}
pop(){
const returnValue = this.heap[1]; //Root 정점 제거하기 위해
this.heap[1] = this.heap.pop(); //마지막 요소로 루트를 채워줌
//루트로부터 아래로 내려가면서 비교하기 위한 변수들
let currentIndex = 1;
let leftIndex = 2;
let rightIndex = 3;
while(this.heap[currentIndex] > this.heap[leftIndex] ||
this.heap[currentIndex] > this.heap[rightIndex]){
if(this.heap[leftIndex] > this.heap[rightIndex]){ //왼쪽보다 오른쪽이 클 경우
const temp = this.heap[currentIndex];
this.heap[currentIndex] = this.heap[rightIndex];
this.heap[rightIndex] = temp;
currentIndex = rightIndex;
}
else{
const temp = this.heap[currentIndex];
this.heap[currentIndex] = this.heap[leftIndex];
this.heap[leftIndex] = temp;
currentIndex = leftIndex; //바뀐 후 그 밑의 자식들을 탐색하기 위해
}
leftIndex = currentIndex * 2;
rightIndex = currentIndex * 2 + 1;
}
return returnValue;
}
}
const heap = new MinHeap();
heap.push(45);
heap.push(36);
heap.push(100);
heap.push(57);
heap.push(27);
heap.push(39);
heap.push(66);
console.log(heap.pop()); // 27
console.log(heap.heap); // [null, 36, 45, 39, 57, 66, 100]
구글이나 네이버 등에서 검색 시 자동완성을 하려면 어떻게 해야할까?

class Queue{
constructor(){
this.queue = [];
this.front = 0;
this.rear = 0;
this.size = 0;
}
enqueue(value){ // 데이터 삽입
this.queue[this.rear++] = value; // rear영역에 값을 넣고 rear 인덱스를 하나 증가
this.size++;
}
dequeue(){ // front에서 데이터 삭제
const value = this.queue[this.front];
delete this.queue[this.front];
this.front++;
this.size--;
return value;
}
peek(){ // 큐의 맨 앞에 값 알아내기
return this.queue[this.front];
}
}
class Node{
constructor(value = ' '){
this.value = value;
this.children = new Map(); // 키로 사용할 간선 정보, 이전 정점의 값 정보를 위해 맵 객체로 저장
this.isWordsFlag = false;
}
}
class Trie{
constructor(){
this.root = new Node(); //root는 공백
}
insert(string){
let currentNode = this.root;
for(const char of string){
if(!currentNode.children.has(char)){ // 자른 문자열을 키(간선) 으로 가지고 있지 않다면
currentNode.children.set(
char,
new Node(currentNode.value + char) // cat이 있는 상태에 can을 추가한다면 c,a가 있다는 걸 확인 후 n만 추가한 정점 생성
)
}
currentNode = currentNode.children.get(char);
}
currentNode.isWordsFlag = true;
}
search(string){ // 단어가 있는지 조회
let currentNode = this.root;
for(const char of string){
if(!currentNode.children.has(char)){
return undefined;
}
currentNode = currentNode.children.get(char);
}
console.log(currentNode);
return currentNode;
}
has(string){
return this.search(string) ? true : false;
}
autoWord(answer){
const currentNode = this.search(answer);
if(currentNode === undefined){
return "해당 단어가 없습니다.";
}
const words = [];
const q = new Queue();
q.enqueue(currentNode);
while(q.size){
let current = q.dequeue();
if(current.isWordsFlag){ // 삽입된 문자들을 정확히 기억해주는 변수
words.push(current.value);
}
for(const item of current.children.values()){
q.enqueue(item);
}
}
return words;
}
}
const trie = new Trie();
trie.insert("cat");
trie.insert("can");
trie.insert("car");
trie.insert("cart");
trie.insert("cannn");
console.log(trie.autoWord("car")); //[ ' car', ' cart' ]
autoWord(answer){
const currentNode = this.search(answer);
if(currentNode === undefined){
return "해당 단어가 없습니다.";
}
const words = [];
const q = new Queue();
q.enqueue(currentNode);
while(q.size){
let current = q.dequeue();
if(current.isWordsFlag){ // 있어야만 모든 간선과 이전 정점 정보가 함께 나오지 않는다.
words.push(current.value);
}
for(const item of current.children.values()){
q.enqueue(item);
}
}
return words;
}
어느정도 정렬이 되어있는 상태에선 퀵 정렬보다 빠르다.정렬 되어있는 요소들을 반씩 제외하며 찾는 알고리즘
const Array = [1,1,5,124,400,600,1000,2345,6789];
function binarySearch(array, findValue){
let left = 0;
let right = Array.length - 1;
let mid = Math.floor((left + right) / 2);
while(left < right){
if(Array[mid] === findValue){
return mid;
}
if(Array[mid] > findValue){ //가운데보다 찾는 숫자가 작다면 -> 왼쪽 진행
right = mid - 1;
}
else{
left = mid + 1;
}
mid = Math.floor((left + right) / 2);
}
return -1; // 찾는 값이 배열에 존재하지 않을 경우
}