Web Dev/2. JS 알고리즘

[자바스크립트로하는 자료구조와 알고리즘] 6- 10장

hYhY1234 2021. 5. 21. 00:49
728x90
// 6-10장
// 6장 자바스크립트 객체
let javaScriptObject = {};
let testArray = [1,2,3,4];
javaScriptObject.array = testArray;
javaScriptObject.title = 'Algorithms';
console.log(javaScriptObject);

function ExampleClass() {
  this.name = "JavaScript";
  this.sayName = function() {
    console.log(this.name)
  }
}

let example1 = new ExampleClass();

example1.sayName();


function ExampleClass2() {
  this.name = "JavaScript";
  this.array = [1,2,3,4,5];
}

ExampleClass2.prototype.sayName = function() {
    console.log("prototype", this.name)
}

let example2 = new ExampleClass2();

example2.sayName();

function ExampleClass3(name, size) {
  let privateName = name;
  let privateSize = size;
  
  this.getName = function() { return privateName }
  this.setName = function(name) { privateName = name; }
  
  this.getSize = function() { return privateSize; }
  this.setSize = function(size) { privateSize = size; }
}

let example = new ExampleClass3("Sammie", 3);
example.setSize(12);
console.log(example.privateName);
console.log(example.getName());
console.log(example.size);
console.log(example.getSize());


function Animal(name, animalType){
  this.name = name;
  this.animalType = animalType;
}
Animal.prototype.sayName = function(){ console.log(this.name); }
Animal.prototype.sayAnimalType = function(){ console.log(this.animalType); }

function Dog(name){
  Animal.call(this, name, "Dog")
}

Dog.prototype = Object.create(Animal.prototype);
console.log("hello", Dog.prototype);


let myAnimal = new Animal("ditto", "pokemon");
myAnimal.sayName();
myAnimal.sayAnimalType();

let myDog = new Dog("candy", "dog");
myDog.sayName();
myDog.sayAnimalType();


// 7장 자바스크립트 메모리 관리
function someLargeArray() {
  return new Array(1000000);
}

let exampleObj = {
  'prop1': someLargeArray(),
  'prop2': someLargeArray()
}

function printProperty(prop){
  console.log(prop);
}

printProperty(exampleObj['prop1']);

// 8장 재귀
// 기저조건(종료조건)이 꼭 있어야한다. 
function countDownToZero(n){
  if(n < 0){
    return;
  }
  
  console.log(n);
  countDownToZero(n-1);
}

countDownToZero(12);

// 분할 정복 방식
const cache = {};
cache[0] = 0;
cache[1] = 1;
function getNthFibo(n){
  if(n <= 1){
    return n;
  }
  if(cache[n]){
    return cache[n];
  }
  const cur = getNthFibo(n-1) + getNthFibo(n-2);
  cache[n] = cur;
  return cur;
}

getNthFibo(10);

function getNthFiboBetter(n, lastlast, last){
  if(n === 0){
    return lastlast;
  }
  if(n === 1){
    return last;
  }
  return getNthFiboBetter(n-1, last, lastlast+last)
}

function pascalTriangle(row, col){
  if(col === 0){
    return 1;
  }
  
  if(row === 0){
    return 0;
  }
  
  return pascalTriangle(row-1, col) + pascalTriangle(row-1, col-1);
}

console.log(pascalTriangle(5, 2));

// 재귀 알고리즘은 점화식을 통해서 분석한다. 

function base10ToString(n){
  let binaryString = "";
  function base10ToStringHelper(n){
    if(n < 2) {
      binaryString += n;
      return;
    }
    
    base10ToStringHelper(Math.floor(n / 2)); // 나누는게 다끝나고 나서 나머지합산이 처리된다
    base10ToStringHelper(n % 2);
  }
  base10ToStringHelper(n);
  
  return binaryString;
}

console.log(base10ToString(232));

// 배열의 모든 순열 출력하기 
function swap(strArr, index1, index2){
  let temp = strArr[index1];
  strArr[index1] = strArr[index2];
  strArr[index2] = temp;
}

function permute(strArr, begin, end){
  if(begin === end){
    console.log(strArr);
    return;
  }
  
  for(let i = begin; i < end + 1; i++){
    swap(strArr, begin, i);
    permute(strArr, begin+1, end);
    swap(strArr, begin, i);
  }
}

function permuteArray(strArr){
  permute(strArr, 0, strArr.length - 1);
}

// permuteArray(["A", "B", "C", "D"]);

// 객체 펼치기
let dic = {
  "key1": "1", 
  "key2": {
    "a": "2", 
    "b": "3", 
    "c": {
      "d": "3", 
      "e": "1"
    }
  }
}

// 문제를 쪼개다가, 입력이 객체가 아닐때 종료한다
function flattenDictionary(dictionary){
  let flattenedDictionary = {};
  function flattenDictionaryHelper(dictionary, propName){
    if(typeof dictionary !== 'object'){
      flattenedDictionary[propName] = dictionary;
      return;
    }
    
    for(const [key, value] of Object.entries(dictionary)){
      if(propName === ""){
        flattenDictionaryHelper(dictionary[key], propName + key);
      }else{
        flattenDictionaryHelper(dictionary[key], propName + "." + key);
      }
    }
  }
  
  flattenDictionaryHelper(dictionary, "");
  return flattenedDictionary;
}


console.log(flattenDictionary(dic));


function isPalindromeRecursive(word){
  return isPalindromeHelper(word, 0, word.length-1);
}

function isPalindromeHelper(word, beginPos, endPos){
  if(beginPos >= endPos) return true;
  
  if(word.charAt(beginPos) !== word.charAt(endPos)){
    return false;
  }
  
  return isPalindromeHelper(word, beginPos+1, endPos-1);
}

isPalindromeRecursive("hi");

// 9장 집합
function intersectSets(setA, setB){
  const intersection = new Set();
  for(let elem of setB){
    if(setA.has(elem)){
      intersection.add(elem);
    }
  }
  return intersection;
}

const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 3]);

console.log(intersectSets(setA, setB));

function isSuperset(setA, subset){
  for(let elem of subset){
    if(!setA.has(elem)){
      return false;
    }
  }
  return true;
}

let setAA = new Set([1, 2, 3, 4]);
let setBB = new Set([2, 3]);
let setC = new Set([5]);

console.log(isSuperset(setAA, setBB));
console.log(isSuperset(setAA, setC));

function unionSet(setA, setB){
  const union = new Set(setA);
  for(let elem of setB){
    union.add(elem);
  }
  
  return union;
}

// console.log(unionSet(setAA, setBB))
// console.log(unionSet(setAA, setC))
// console.log(unionSet(setBB, setC))

function differenceSet(setA, setB){
  const difference = new Set(setA);
  for(let elem of setB){
   difference.delete(elem);
  }
  
  return difference;
}

console.log(differenceSet(setAA, setBB))
console.log(differenceSet(setAA, setC))
console.log(differenceSet(setBB, setC))

function checkDuplicates(arr){
  const mySet = new Set(arr);
  return mySet.size < arr.length;
}

console.log(checkDuplicates([1,2,3,4,5,6]));
console.log(checkDuplicates([1,1,2,3,4,5,6]))

function uniqueList(arr1, arr2){
  const mySet = new Set(arr1.concat(arr2));
  return Array.from(mySet);
}

uniqueList([1,1,2,2], [2,3,4,5]);

// 10장 검색과 정렬

function binarySearch(array, n){
  let lowIndex = 0, highIndex = array.length - 1;
  
  while(lowIndex <= highIndex){
    let midIndex = Math.floor((highIndex + lowIndex) / 2);
    
    if(array[midIndex] === n){
      return midIndex;
    }
    
    if(n > array[midIndex]){
      lowIndex = midIndex + 1;
      continue;
    }
    
    highIndex = midIndex - 1;
  }
  
  return -1;
}

console.log(binarySearch([1,2,3,4], 4));
console.log(binarySearch([1,2,3,4], 5));

// function swap(strArr, index1, index2){
//   let temp = strArr[index1];
//   strArr[index1] = strArr[index2];
//   strArr[index2] = temp;
// }

// bubble sort
function bubbleSort(array){
  // i번째까지 체크(매 루프마다 끝나는데가 하나씩 준다
  for(let i = array.length - 1; i > 0; i--){
    for(let j = 0; j < i; j++){
      if(array[j] > array[j+1]){
        swap(array, j, j+1);
      }
    }
  }
  return array;
}

console.log(bubbleSort([6, 1, 2, 3, 4, 5]));

function selectionSort(items){
  let len = items.length;
  let min = 0;
  
  for(let i = 0; i < len; i++){
    min = i; // 항상 제일앞이 최솟값이라고치고, 이 위치에다가 가져온다. 
    for(let j = i+1; j < len; j++){
      if(items[j] < items[min]){
        min = j;
      }
    }
    if(i !== min){
      swap(items, i, min);
    }
  }
  
  return items;
}

console.log(selectionSort([6, 1, 2, 3, 4, 5]));

function insertSort(items){
  let len = items.length; // 배열의 항목수
  let value = 0; // 현재 비교중인 값
  // let i = 0; // 정렬되지 않은 부분의 인덱스
  // let j = 0; // 정렬된 부분까지의 인덱스
  
  for(let i = 0; i < len; i++){
    value = items[i]; // value는 현재선택된값
    
    let j = i-1;
    while(j >= 0 && items[j] > value){
      // value가 들어갈자리를 계속 한칸씩 밀어준다
      items[j+1] = items[j];
      j--;
    }
    items[j+1] = value;
  }
  return items;
}

console.log(insertSort([6, 1, 2, 3, 4, 5]));

function quickSort(items){
  return quickSortHelper(items, 0, items.length - 1);
}

function quickSortHelper(items, left, right){
  if(items.length > 1){
    let index = partition(items, left, right); // 쪼갠다  
    if(left < index - 1){
      quickSortHelper(items, left, index-1);
    }
    if(index < right){ // 계속 pivot기준도 어딘가에 포함을 시켜준다. 
      quickSortHelper(items, index, right)
    }
  }
  return items;
}

function partition(array, left, right){
  let pivot = array[Math.floor((left+right) / 2)];
 
  while(left <= right){
    while(pivot > array[left]){
      left++; // pivot보다 큰데서 멈춘다
    }
    
    while(pivot < array[right]){
      right--; // pivot보다 작은데서 멈춘다
    }
    
    if(left <= right){
      let temp = array[left];
      array[left] = array[right];
      array[right] = temp;
      left++;
      right--;
    }
  }
  return left;
}

console.log("quick", quickSort([6, 1, 3, 2, 5, 4]));
console.log(quickSort([6, 1, 23, 4, 2, 3]));

// quickSelect: 정렬되지 않은 목록에서 k번째로 작은 항목을 찾는 선택 알고리즘
// quick소트처럼 하는데 반쪽씩만 재귀적으로 수행한다. 
const array = [1, 3, 3, -2, 3, 14, 7, 8, 1, 2, 2];

function quickSelectInPlace(A, l, h, k){
  const p = partition(A, l, h);
  if(p === (k-1)){
    return A[p];
  }
  if(p > k-1){
    // 앞에
    return quickSelectInPlace(A, l, p-1, k);
  }else{
    // 뒤에
    return quickSelectInPlace(A, p+1, h, k);
  }
}

quickSelectInPlace(array, 0, array.length-1, 5);
quickSelectInPlace(array, 0, array.length-1, 10);

// merge소트
function merge(leftA, rightA){
  const results = [];
  let leftIndex = 0, rightIndex = 0;
  
  while(leftIndex < leftA.length && rightIndex < rightA.length){
    if(leftA[leftIndex] < rightA[rightIndex]){
      results.push(leftA[leftIndex++]);
    }else{
      results.push(rightA[rightIndex++]);
    }
  }
  
  let leftRemains = leftA.slice(leftIndex), 
      rightRemains = rightA.slice(rightIndex);
  return results.concat(leftRemains).concat(rightRemains);
}

function mergeSort(array){
  if(array.length < 2){
    return array;
  }
  
  let midpoint = Math.floor((array.length)/2),
  leftArray = array.slice(0, midpoint),
  rightArray = array.slice(midpoint);
  
  return merge(mergeSort(leftArray), mergeSort(rightArray));
}

console.log(mergeSort([6, 1, 23, 4, 2, 3]));


// 계수 정렬
function countSort(array){
  const hash = {}, countArr = [];
  
  for(let i = 0; i < array.length; i++){
    if(!hash[array[i]]){
      hash[array[i]] = 1;
    }else{
      hash[array[i]]++;
    }
  }
  
  for(let key in hash){
    for(let i = 0; i < hash[key]; i++){
      countArr.push(parseInt(key));
    }
  }
  
  return countArr;
}

countSort([6,1,23,2,3,2,1,2,2,3,3,1,123,123,4,2,3]);

 

정렬은 어떻게 할때마다 조금씩 까먹는건지, 아주 놀라울따름... 이런 자료구조들을 얼른 좀 더 잘다룰수 있길.