Computer Science/Data Structure

[Data structures] section2: λΉ…μ˜€ ν‘œκΈ°λ²• (Big O Notation)

yuri lee 2023. 1. 25. 23:38
λ°˜μ‘ν˜•

4. λΉ…μ˜€ (BIG O) μ†Œκ°œ

Objectives

  • Big O ν‘œκΈ°λ²•μ˜ ν•„μš”μ„±
  • Big O κ°€ 무엇인지
  • Big O κ°„λ‹¨ν•˜κ²Œ ν‘œν˜„ν•˜λŠ” 법
  • μ‹œκ°„ λ³΅μž‘μ„±κ³Ό 곡간 λ³΅μž‘μ„± μ •μ˜
  • Big O ν‘œκΈ°λ²•μ„ μ‚¬μš©ν•˜μ—¬ μ—¬λŸ¬ μ•Œκ³ λ¦¬μ¦˜ ν‰κ°€ν•˜κΈ°
  • 둜그 (logarithm)이 무엇인지 

What's the idea here? 

"Write a function that accepts a string input and returns a reversed copy"

μ œλŒ€λ‘œ μž‘λ™ν•˜κΈ°λ§Œ ν•œλ‹€λ©΄ 그것 λ§ŒμœΌλ‘œλ„ μΆ©λΆ„ν•˜μ§€ μ•Šμ€κ°€? 

 

Who Cares? 

  • μ½”λ“œμ˜ μ„±λŠ₯을 μ–˜κΈ°ν•  λ•Œ μ •ν™•ν•œ μ „λ¬Έ μš©μ–΄λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.
  • μ—¬λŸ¬ μ ‘κ·Όλ²•μ˜ μž₯단점을 μ–˜κΈ°ν• λ•Œλ„ μœ μš©ν•©λ‹ˆλ‹€. κ°€μž₯ 쒋은 해결책을 μ°ΎλŠ” 것이 κ·Έλ ‡κ²Œ λ»”ν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. ν•œ 해결책에 정말 μ’‹κ³  또 ν•˜λ‚˜λŠ” 엉망인 κ²½μš°κ°€ λ§Žμ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.
  • μ½”λ“œλ₯Ό λ””λ²„κ·Έν• λ•Œ μ½”λ“œλ₯Ό 느리게 λ§Œλ“œλŠ” 것은 이해 ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€. μ—λŸ¬λ§Œμ„ μ°ΎλŠ” 것이 μ•„λ‹ˆλΌ, μ½”λ“œκ°€ μž‘λ™μ„ ν•˜μ§€λ§Œ 생각보닀 더 였랜 μ‹œκ°„μ΄ κ±Έλ¦¬κ±°λ‚˜, λΈŒλΌμš°μ €μ—μ„œ νŽ‘μ…˜μ„ μ‹€ν–‰ν–ˆμ„λ•Œ 컴퓨터가 λž™κ±Έλ¦°λ‹€κ³  생각해 λ³΄μ„Έμš”. 이 μ„Ήμ…˜μ—μ„œ μ–ΈκΈ‰ ν•  것듀에 λŒ€ν•΄μ„œ μ΄ν•΄ν•˜λŠ” 것이 도움이 λ©λ‹ˆλ‹€. λΉ…μ˜€λ₯Ό μ΄ν•΄ν•˜λ©΄ μ–΄λ””μ„œ λ¬Έμ œκ°€ λ‚˜νƒ€λ‚˜λŠ”μ§€ μ°ΎκΈ° μ‰¬μšΈ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ©΄μ ‘μ—μ„œ 자주 λ‚˜μ˜€λŠ” λ‚΄μš©μ΄κΈ° λ•Œλ¬Έμ— μ•„λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€. 

 

5. μ½”λ“œ μ‹œκ°„ 재기 

function addUpTo(n) {
    let total = 0;
    for (let i = 1; i<= n; i++) {
        total += i
    }
    return total
}

//console.log(addUpTo(6))

var t1 = performance.now()
addUpTo(100000000)
var t2 = performance.now()
console.log(`Time Elapsed: ${(t2 - t1) / 1000} seconds`) // Time Elapsed: 0.15639999997615814 seconds
function addUpTo(n) {
    return n * (n + 1) / 2
}


//console.log(addUpTo(6))
var t1 = performance.now()
addUpTo(100000000)
var t2 = performance.now()
console.log(`Time Elapsed: ${(t2 - t1) / 1000} seconds`) // Time Elapsed: 0.00009999996423721313 seconds

What does better mean?

Faster? Less memory-intensive? More readable? 

 

μš°μ„  κΈ°κΈ°λ§ˆλ‹€ λ‹€λ₯Έ λ°©μ‹μœΌλ‘œ μ‹œκ°„μ„ κΈ°λ‘ν•©λ‹ˆλ‹€.  κΈ°κΈ° 사양에 따라 λ‹€λ₯Ό μˆ˜λ„ 있고 κ·Έ 기계 무엇이 μ‹€ν–‰ 되고 μžˆλŠ”μ§€ 에 λ”°λΌμ„œ λ‹€λ₯Ό μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. λ¬Όλ‘  κ·Έλ ‡λ‹€κ³  ν•΄μ„œ κ°‘μžκΈ° 거꾸둜 첫 번째 ν•΄κ²° 법이 두 번째 갈 것 보닀 더 λΉ λ₯΄κ²Œ λ‚˜μ˜¬ μˆ˜λ„ μžˆλ‹€λŠ” 것은 μ•„λ‹™λ‹ˆλ‹€. ν•˜μ§€λ§Œ 차이가 λ‹¬λΌμ§ˆ 수 있고 μ±…μ •λœ μ‹œκ°„λ“€μ΄ λ‹¬λΌμ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€. μ–Έμ œλ‚˜ λ‹€λ₯Έ μ‹œκ°„μ΄ 기둝 될 κ²ƒμž…λ‹ˆλ‹€.  λ˜‘같은 기계가 λ‹€λ₯Έ μ‹œκ°„μ„ 기둝 ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. λΈŒλΌμš°μ € μ—μ„œ λ˜‘κ°™μ€ μ½”λ“œ, 첫 번째 μ½”λ“œμ—μ„œ μ‘°κΈˆμ”© λ‹€λ₯Έ μ‹œκ°„μ΄ 기둝 λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 큰 λ¬Έμ œλŠ” μ•„λ‹ˆμ§€λ§Œ μ •ν™•ν•˜μ§€ μ•Šλ‹€λŠ” 것을 보여 μ£Όκ³  μžˆμŠ΅λ‹ˆλ‹€. κ·Έλ ‡κ²Œ λ•Œλ¬Έμ— μ™„μ „νžˆ 믿을 μˆ˜κ°€ μ—†λ‹€λŠ” 것이죠.

 

μ„Έλ²ˆμ§ΈλŠ” λΉ λ₯Έ μ•Œκ³ λ¦¬μ¦˜μ—μ„œλŠ” 정말 짧은 μ‹œκ°„ μ•ˆμ— λͺ¨λ“  것이 처리 λœλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. 이런 κ²½μš°μ—λŠ” 속도 μΈ‘μ • 정확도가 μΆ©λΆ„ν•˜μ§€ μ•Šμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. 정말 λΉ λ₯Έ μ•Œκ³ λ¦¬μ¦˜μ΄ μ„Έλ„€κ°œ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ κ·Έμ€‘μ—μ„œ κ°€μž₯ λΉ λ₯΄κ³  κ°€μž₯ 효율적인 μ½”λ“œκ°€ μžˆμ„ κ²ƒμž…λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ €ν¬μ˜ 타이밍 function이 그런 μž‘μ€ 차이λ₯Ό μΈ‘μ •ν•˜κΈ° νž˜λ“€λ‹€λ©΄ μ•„λ¬΄λŸ° 도움이 λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

 

μ½”λ“œλ₯Ό μ‚΄νŽ΄ λ³΄λ©΄μ„œ μ‹œκ°„μ„ μΈ‘μ • ν•˜μ§€ μ•Šκ³  μ–΄λŠ μ½”λ“œκ°€ 더 쒋은지 μ–΄λ–»κ²Œ 평가할 수 μžˆμ„κΉŒμš”? μ •ν™•νžˆ λ§μ”€λ“œλ¦¬λ©΄ μ½”λ“œκ°€ μ‹€ν–‰ λ˜λŠ” μ‹œκ°„μ„ μΈ‘μ • ν•˜λŠ” 것이 λ‚˜μ˜λ‹€λŠ” 것은 μ•„λ‹ˆμ§€λ§Œ, 이런 μ‹μœΌλ‘œ μ½”λ“œλ₯Ό 파일 μ•ˆμ— λ§Œλ“€κ³  μ‹œκ°„μ„ μΈ‘μ • ν•˜λŠ” 방법 외에 더 쒋은 방법이 있으면 더 쒋을 κ²ƒμ΄λΌλŠ” κ²λ‹ˆλ‹€. 저희 μ½”λ“œκ°€ ν•œ μ‹œκ°„μ΄ 걸리고 λ‹€λ₯Έ 버전이 λ„€ μ‹œκ°„μ΄ κ±Έλ¦°λ‹€κ³  생각해 λ³΄μ„Έμš”. μ–΄λ–€ 게 더 λΉ λ₯Έμ§€ μ•ŒκΈ° μœ„ν•΄μ„œ ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰ ν•˜κΈ°λŠ” μ‹«κ±°λ“ μš”. μ΄λ ‡κ²Œ ν•˜μ§€ μ•Šμ•„λ„ μ½”λ“œλ₯Ό 비ꡐ ν•˜λŠ” νŠΉμ •ν•œ 값이 μžˆμ—ˆμœΌλ©΄ μ’‹κ² λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. μ΄λŸ΄λ•Œ λΉ…μ˜€ ν‘œκΈ°λ²•μ΄ μœ μš©ν•œ κ²ƒμž…λ‹ˆλ‹€. 

 

6.  μ—°μ‚° 갯수 μ„ΈκΈ° 

Counting Operations

function addUpTo(n) {
	return n * (n + 1) / 2
}

1 mutiplication, 1 addition, 1 ivision / 3 simple operations, regardless of the size of n / N이 크든 μž‘λ“ , N의 κ°’κ³ΌλŠ” 상관없이 연산이 3번 이루어지고 μžˆμŠ΅λ‹ˆλ‹€.  

 

function addUpTo(n) {
    let total = 0; (1 assignment)
    for (let i = 1 (1 assignment) ; i <= (n comparisons) n; i++ (n additions and n assignments))) {
    	total += i; (n additions, n assignments)
    }
    return total;
}

λ‹€μŒμ˜ ν˜•μ‹μœΌλ‘œ λͺ¨λ“  연산을 μ„ΈλŠ” 것은 쉽지 μ•ŠμŠ΅λ‹ˆλ‹€.  5N + 2 / N이 10개라면, μ—°μ‚° 50κ°œμ— 루프 밖에 μžˆλŠ” 2개λ₯Ό λ”ν•˜λ―€λ‘œ 52κ°œκ°€ λ©λ‹ˆλ‹€. 5n + 2이든지, 3n 든지 50n 이든지 상관 μ—†μŠ΅λ‹ˆλ‹€. μ€‘μš”ν•œ 것은 전체적인 μΆ”μ„Έλ₯Ό λ³΄λŠ” κ²ƒμž…λ‹ˆλ‹€. 

 

7. μ‹œκ°„ λ³΅μž‘λ„ μ‹œκ°ν™”ν•˜κΈ° 

N이 컀질수둝 κ±Έλ¦¬λŠ” μ‹œκ°„μ΄ λΉ„λ‘€ν•˜κ²Œ λŠ˜μ–΄λ‚˜κ³  μžˆμŠ΅λ‹ˆλ‹€. (5N + 2)

https://rithmschool.github.io/function-timer-demo/

 

8. λΉ…μ˜€μ— λŒ€ν•œ 곡식 μ†Œκ°œ 

Big O Notation is a way to formalize fuzzy(흐린, λŒ€λž΅μ ) counting. It allows us to talk formally about how the runtime of an algorithm grows as the inputs grow

 

Example

function countUpAndDown(n) {
  console.log("Going up!");
  for (var i = 0; i < n; i++) {
    console.log(i);
  }
  console.log("At the top!\nGoing down...");
  for (var j = n - 1; j >= 0; j--) {
    console.log(j);
  }
  console.log("Back down. Bye!");
}

→ O(n)

 

function printAllPairs(n) {
  for (var i = 0; i < n; i++) {
    for (var j = 0; j < n; j++) {
      console.log(i, j);
    }
  }
}

→ O(n * n), n이 컀질수둝 μ‹€ν–‰ μ‹œκ°„μ΄ n제곱의 κ°’μœΌλ‘œ λŠ˜μ–΄λ‚œλ‹€λŠ” λœ»μž…λ‹ˆλ‹€. 

 

9. λΉ…μ˜€ ν‘œν˜„μ‹μ˜ λ‹¨μˆœν™”ν•˜κΈ° (Simplifying Big O Expressions)

μƒμˆ˜λŠ” μ€‘μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. Constants Don't Matter 

  • O(2n) → O(n)
  • O(500) → O(1)
  • O(13n^2) → O(n^2)

 

Smaller Terms Don't Matter

  • O(n + 10) →  O(n)
  • O(1000n + 50) →  O(n)
  • O(n^2 + 5n + 8) → O(n^2)

 

Big O SHORTHANDS

1. Arithmetic operations are constant μ‚°μˆ˜λŠ” μƒμˆ˜μž…λ‹ˆλ‹€. (λ§μ…ˆ, λΊ„μ…ˆ, κ³±μ…ˆ, λ‚˜λˆ—μ…ˆμ„ ν¬ν•¨ν•©λ‹ˆλ‹€)

2. Variable assignment is constant. (x = 1000을 μ²˜λ¦¬ν•˜λŠ” 것과 x = 20000을 ν•˜λ“  100λ§Œμ„ μ²˜λ¦¬ν•˜λŠ” 것은 λΉ„μŠ·ν•œ μ‹œκ°„μ΄ κ±Έλ¦½λ‹ˆλ‹€)

3. Accessing elements in an array (by index) or object (by key) is constant. (인덱슀λ₯Ό μ‚¬μš©ν•΄μ„œ λ°°μ—΄ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό μ ‘κ·Όν•˜λŠ” 것, λ°°μ—΄μ—μ„œ 첫번째 μ•„μ΄ν…œμ„ μ°Ύλ˜μ§€, 10번째 μ•„μ΄ν…œμ„ μ°Ύλ˜μ§€ 인덱슀λ₯Ό μ‚¬μš©ν•˜λ©΄ λ˜‘κ°™μ€ μ‹œκ°„μ΄ κ±Έλ¦½λ‹ˆλ‹€.)

4. In a loop, the complexity is the length of the loop times the complexity of whatever happens inside of the loop

 

A Couple More Examples

function logAtLeast5(n) {
	for (var i = 1 ; i <= Math.max(5,n); i++) {
    	console.log(i)
    }
}

→ O(n)

 

function logAtMost5(n) {
	for (var i = 1 ; i <= Math.min(5,n); i++) {
    	console.log(i)
    }
}

 → O(1), 5λ₯Ό λ„˜μ§€ μ•Šμ„ κ²ƒμ΄λ―€λ‘œ n이 컀질수둝 λΉ…μ˜€λŠ” μƒμˆ˜λΌκ³  λ‹¨μˆœν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€. <O(5)λŒ€μ‹  O(1)> 5보닀 크면 무쑰건 MIN 더 μž‘μ€ 5λ₯Ό 선택할 것이기 λ•Œλ¬Έμž…λ‹ˆλ‹€. n이 1000이더라도 루프가 5번만 λ°˜λ³΅λ©λ‹ˆλ‹€. n이 100λ§Œμ΄λ”λΌλ„ 루프가 5번만 λ°˜λ³΅λ©λ‹ˆλ‹€. 

 

 

ν€΄μ¦ˆ 1: λΉ…μ˜€ (BIG O) μ‹œκ°„ λ³΅μž‘λ„ ν€΄μ¦ˆ

0(n + n + n + n) → 0(n)

 

ν€΄μ¦ˆ 2: λΉ…μ˜€ (BIG O) μ‹œκ°„ λ³΅μž‘λ„ ν€΄μ¦ˆ

function onlyElementsAtEvenIndex(array) {
    var newArray = Array(Math.ceil(array.length / 2));
    for (var i = 0; i < array.length; i++) {
        if (i % 2 === 0) {
            newArray[i / 2] = array[i];
        }
    }
    return newArray;
}

→ 0(n) / for loop μ—¬μ„œ...

 

function subtotals(array) {
    var subtotalArray = Array(array.length);
    for (var i = 0; i < array.length; i++) {
        var subtotal = 0;
        for (var j = 0; j <= i; j++) {
            subtotal += array[j];
        }
        subtotalArray[i] = subtotal;
    }
    return subtotalArray;
}

 → 0(n^2)

 

10.  곡간 λ³΅μž‘λ„ (Space Complexity)

auxiliary space complexity : μž…λ ₯λ˜λŠ” 것을 μ œμ™Έν•˜κ³  μ•Œκ³ λ¦¬μ¦˜ μžμ²΄κ°€ ν•„μš”λ‘œ ν•˜λŠ” 곡간을 μ˜λ―Έν•©λ‹ˆλ‹€. μ€‘μš”ν•œ 것은 μ•Œκ³ λ¦¬μ¦˜ μžμ²΄μž…λ‹ˆλ‹€. μž…λ ₯보닀도 μ•Œκ³ λ¦¬μ¦˜ μžμ²΄κ°€ μ–΄λ–€ 영ν–₯을 μ£ΌλŠ”μ§€ μžμ„Ένžˆ 봐야 ν•©λ‹ˆλ‹€. 곡간 λ³΅μž‘λ„λΌκ³  λ§ν•˜λŠ” 것은 사싀상 보쑰 곡간 λ³΅μž‘λ„λ₯Ό λ§ν•œλ‹€κ³  보면 λ©λ‹ˆλ‹€. 

 

Rules Of Thumb 

- booleans, numbers, undefined, null) : λΆˆλ³€ 곡간, μˆ«μžκ°€ 1이든 1000이든 μƒκ΄€μ—†μŒ

- Strings : O(n) 문자 길이가 50이라면 길이가 1인 λ¬Έμžμ—΄λ³΄λ‹€ 50λ°° 더 λ§Žμ€ 곡간을 차지함 

- Reference types (arrays, objects) : O(n), λ°°μ—΄μ˜ 길이 4, 2λ₯Ό 비ꡐ할 λ•Œ κΈ΄ 배열은 2인 배열보닀 2λ°° 더 λ§Žμ€ 곡간 차지함. 

 

function sum(arr) {
    let total = 0; // one number
    for (let i = 0; i < arr.length; i++) { // another number
        total += arr[i];
    }
    return total;
}

// O(1) space! 


function double(arr) {
    let newArr = []
    for (let i = 0; i < arr.length; i++) {
        newArr.push(2 * arr[i])
    }
    return newArr // n numbers
}

// μƒˆλ‘œμš΄ 배열을 λ§Œλ“¦. λ°°μ—΄μ˜ 크기가 λŠ˜μ–΄λ‚˜μ„œ λ¬΄ν•œλŒ€μ— κ°€κΉŒμ›Œμ§ˆμˆ˜λ‘ 곡간 λ³΅μž‘λ„κ°€ μ–΄λ–»κ²Œ λ˜λ‚˜μš”? 
// μž…λ ₯된 λ°°μ—΄μ˜ 길이가 50이면 그만큼, 100이면 그만큼 λ¦¬ν„΄ν•˜κ²Œ λœλ‹€. 차지 ν•˜λŠ” 곡간은 μž…λ ₯ 된 λ°°μ—΄μ˜ 크기와 λΉ„λ‘€ν•΄μ„œ μ»€μ§€κ²Œ λ©λ‹ˆλ‹€.

 

ν€΄μ¦ˆ 3: λΉ…μ˜€ (BIG O) μ‹œκ°„ λ³΅μž‘λ„ ν€΄μ¦ˆ

function logUpTo(n) {
    for (var i = 1; i <= n; i++) {
        console.log(i);
    }
}

 → 0(1)

function logAtMost10(n) {
    for (var i = 1; i <= Math.min(n, 10); i++) {
        console.log(i);
    }
}

 → 0(1)

function onlyElementsAtEvenIndex(array) {
    var newArray = Array(Math.ceil(array.length / 2));
    for (var i = 0; i < array.length; i++) {
        if (i % 2 === 0) {
            newArray[i / 2] = array[i];
        }
    }
    return newArray;
}

 → 0(n)

 

11. λ‘œκ·Έμ™€ μ„Ήμ…˜ μš”μ•½

λΉ…μ˜€ ν‘œκΈ°λ“€ μ€‘μ—μ„œ 더 μ–΄λ ΅κ±°λ‚˜ ν”ν•˜μ§€ μ•Šμ€ μˆ˜ν•™ κ°œλ…λ“€μ΄ ν¬ν•¨λ˜μ–΄ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€. (ν”ν•œ ν‘œκΈ°λ²• : O(1), O(n), O(n^2)) κ·Έ 쀑 자주 λ‚˜μ˜€λŠ” κ°œλ…μ΄ λ‘œκ·Έμž…λ‹ˆλ‹€. 

 

Wait, what's a log agin?

λ‘œκ·Έν•¨μˆ˜λŠ” μ§€μˆ˜ν•¨μˆ˜μ˜ μ—­ν™˜μž…λ‹ˆλ‹€. λ‚˜λˆ—μ…ˆκ³Ό κ³±μ…ˆμ΄ 짝인 κ²ƒμ²˜λŸΌ λ‘œκ·Έν•¨μˆ˜μ™€ μ§€μˆ˜ν•¨μˆ˜λŠ” 짝이닀. 

 

log2(8) = 3 <-> 2^3 - 8

2의 λͺ‡μŠΉμ˜ 값이 88이 λ˜λ‚˜μš”?

 


https://www.udemy.com/course/best-javascript-data-structures/

λ°˜μ‘ν˜•

'Computer Science > Data Structure' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[Data structures] section1: μ†Œκ°œ  (0) 2023.01.09