Javascript/자료구조&알고리즘

[자료구조&알고리즘]배열과 오브젝트 성능 평가 (Big O)

이지영 2022. 6. 30. 11:32

 

Javascript에서 objects keys-values쌍은 index가 따로 없기 때문에 삽입, 제거, 탐색, 접근 등의 작업에 드는 시간이 arrays와 다르다.

예를 들어 arrays의 경우, 끝부분이 아닌 곳에 element가 삽입 혹은 제거되면
그 뒤의 모든 elments index가 한 칸 씩 뒤로밀려 재배열되기 때문에 선형 시간(O(n))이 걸리는 데에 반해,
objects keys-values쌍은 index가 따로 없기 때문에, 즉 순서 자체가 없기 때문에
arrays와 달리 같은 작업을 처리하는 데에 상수 시간(O(1))이 걸린다.
다만 value를 찾아야 하는 작업은 모든 keys를 확인해야하기 때문에 선형 시간이 걸린다.

object methods를 사용할 때에 각 method의 시간 복잡도를 파악해두면 좀 더 효율적인 알고리즘을 작성할 수 있다.

객체(Objects)

  • 객체는 순서가 없지만 key와 value을 사용해 빠르다는 장점이 있다.
  • Big O로 보는 성능은 다음과 같다.
    • 삽입(Insertion) ⇒ O(1)
    • 삭제(Removal) ⇒ O(1)
    • 검색(Searching) ⇒ O(N)
    • 접근(Access) ⇒ O(1)

객체 순회하기

  • 객체의 요소는 인덱스(순서)가 없다. 객체의 값은 키를 통해서만 접근이 가능하다.
  • 하지만 순회 가능하다!

 Object.keys()

  • 객체의 키 목록을 배열로 리턴한다.
  • 객체 내장 메서드가 아니고, 객체 생성자인 Object 가 직접 가지고 있는 메서드이다. 
const obj = {
  name: 'melon',
  weight: 4350,
  price: 16500,
  isFresh: true
}

Object.keys(obj) // ['name', 'weight', 'price', 'isFresh']
  • Object.keys() 가 리턴하는 값이 배열이기 때문에 이제는 반복문을 사용할 수 있다.
const keys = Object.keys(obj) // ['name', 'weight', 'price', 'isFresh']

for (let i = 0; i < keys.length; i++) {
  const key = keys[i] // 각각의 키
  const value = obj[key] // 각각의 키에 해당하는 각각의 값

  console.log(value)
}

 

Object.entries() 

  • ES6 에서 객체의 value 값을 배열로 반환하는 Object.values() 와 객체의 key, value 값을 배열로 반환하는 Object.entries() 가 추가되었다.
const values = Object.values(obj)
// values === ['melon', 4350, 16500, true]

const entries = Object.entries(obj)

/*
entries === [
  ['name', 'melon'],
  ['weight', 4350],
  ['price', 16500],
  ['isFresh', true]
]
*/
let obj = {
  name: "kim",
  age: 30,
  height: 172,
};
 
console.log(Object.keys(obj)); //[ 'name', 'age', 'height' ]
console.log(Object.values(obj)); //[ 'kim', 30, 172 ]
console.log(Object.entries(obj)); //[ [ 'name', 'kim' ], [ 'age', 30 ], [ 'height', 172 ] ]
console.log(obj.hasOwnProperty("height")); //true

 

  • 순서가 정해져 있어 객체보다 시간이 좀 더 오래 걸린다.
  • 정렬될 필요가 있는 데이터, 정렬되어 있는 데이터를 보관하는데 유리하다
  • 배열 시작에서 작업을 하는것이 끝에서 하는것보다 더 느리다
  • 배열 연산의 Big O Notation
    삽입 - 맨 앞일 때 : O(N), 맨 뒤일 때 O(1)
    삭제 - 먠 앞일 때 : O(N), 맨 뒤일 때 O(1)
    접근 - O(1)
    탐색 - O(N)

배열 메소드의 Big O Notation

  • push - O(1)
  • pop - O(1)
  • shift - O(N)
  • unshift -O(N)                                                                                                                                                                  =>push와 pop이 shift와 unshift 작업보다 빠름(비어 있는 배열일때 제외)
  • concat - O(N + M) = O(N) : 여러 배열을 합쳐주는데 결합할 배열이 커질수록 끝에 붙일 배열의 크기만큼 시간도 그만큼 늘어날것
  • slice - O(N) : 배열의 전체 혹은 일부를 복사함, 얼마나 복사할지에 따라 다름 = 배열의 길이에 따라 다름
  • splice -O(N) : 인수가 2개일 때에는 삭제, 3개 이상일 때에는 추가
  • sort - O(N * logN)
  • 고차함수(forEach/map/filter/reduce/etc. - O(N)

=>배열의 기본적인 연산, 메소드들은 보통 O(N)이다.
접근, pop, push은 인덱스를 사용해서 접근하는 것과 똑같고 상수 시간걸림 빠름

 

총정리

객체는 거의 모든것을 더 빠르게 하지만 , 정렬되어 있지 않고

배열은 정렬 되어 있지만 ,끝에 추가하고 제거하는 작업이 느림 시작에 넣거나 빼면 처음부터 끝까지 영향을 받으면서 전부 인덱스를 다시 정리해야함