[algorithm] 더 낮은 것보다 더 큰 big-O 시간 복잡성 알고리즘을 선호하는 경우가 있습니까?

O(log n)시간 복잡성보다 시간 복잡성을 선호하는 경우가 O(1)있습니까? 또는 O(n)O(log n)?

예가 있습니까?



답변

낮은 O보다 복잡한 O 시간 복잡성을 가진 알고리즘을 선호하는 데는 여러 가지 이유가있을 수 있습니다.

  • 대부분의 경우 Big-O 복잡성이 낮 으면 달성하기 어렵고 숙련 된 구현, 많은 지식 및 많은 테스트가 필요합니다.
  • big-O는 상수에 대한 세부 사항을 숨 깁니다. 수행하는 알고리즘은 ( vs ) 10^5보다 big-O 관점에서 더 좋지만 가장 합리적인 경우 첫 번째 알고리즘 이 더 잘 수행됩니다. 예를 들어 행렬 곱셈의 가장 복잡한 점 은 상수가 너무 커서 (내 지식으로는) 계산 라이브러리에서 사용하지 않습니다.1/10^5 * log(n)O(1)O(log(n)nO(n^2.373)
  • big-O는 큰 것을 계산할 때 의미가 있습니다. 세 개의 숫자 배열을 정렬 해야하는 경우 사용 O(n*log(n))또는 O(n^2)알고리즘 여부는 거의 중요하지 않습니다 .
  • 때때로 소문자 시간 복잡성의 이점은 실제로 무시할 수 있습니다. 예를 들어, 데이터 구조 탱고 트리는O(log log N) 항목을 찾기에 시간 복잡성을 제공 하지만,에서 동일한 것을 찾는 이진 트리도 있습니다 O(log n). 엄청난 n = 10^20차이 의 경우 에도 무시할 수 있습니다.
  • 시간의 복잡성이 전부는 아닙니다. 실행되고 메모리 O(n^2)가 필요한 알고리즘을 상상해보십시오 O(n^2). n이 실제로 크지 않은 경우 O(n^3)시간과 O(1)공간에 걸쳐 바람직 할 수 있습니다 . 문제는 오랫동안 기다릴 수 있지만 알고리즘과 함께 사용할 RAM을 충분히 찾을 수 있다는 것입니다.
  • 병렬화는 분산 된 세계에서 좋은 기능입니다. 쉽게 병렬화 할 수있는 알고리즘이 있으며 전혀 병렬화되지 않는 알고리즘이 있습니다. 때로는 약간 더 복잡한 하나의 컴퓨터를 사용하는 것보다 복잡도가 높은 1000 개의 상용 컴퓨터에서 알고리즘을 실행하는 것이 좋습니다.
  • 일부 장소 (보안)에서는 복잡성이 요구 될 수 있습니다. 누구도 굉장히 빨리 해시 할 수있는 해시 알고리즘을 원하지 않습니다.
  • 이것은 복잡성 전환과 관련이 없지만 일부 보안 기능은 타이밍 공격방지 하는 방식으로 작성되어야합니다 . 그것들은 대부분 같은 복잡성 클래스에 머물러 있지만 무언가를하기 위해서는 항상 더 나쁜 경우가되도록 수정됩니다. 한 예는 문자열이 같은지 비교하는 것입니다. 대부분의 응용 프로그램에서 첫 번째 바이트가 다르면 빠르게 중단되는 것이 합리적이지만 보안 상 끝까지 나쁜 소식을 전할 때까지 기다리게됩니다.
  • 누군가는 복잡성이 낮은 알고리즘에 대해 특허를 받았으며 회사가 돈을 지불하는 것보다 더 높은 복잡성을 사용하는 것이 더 경제적입니다.
  • 일부 알고리즘은 특정 상황에 잘 적응합니다. 예를 들어 삽입 정렬의 평균 복잡도는 O(n^2)퀵 정렬 또는 병합 정렬보다 나쁘지만 온라인 알고리즘 으로 대부분의 다른 알고리즘 만 효율적으로 작동 할 수있는 경우 사용자 입력으로 수신되는 값 목록을 효율적으로 정렬 할 수 있습니다 전체 값 목록에서.

답변

숨겨진 상수는 항상 있으며 O (log n ) 알고리즘 에서 낮을 수 있습니다 . 따라서 실제 데이터에 대해 실제로 더 빠르게 작동 할 수 있습니다.

공간 문제도 있습니다 (예 : 토스터에서 실행).

개발자 시간 문제도 있습니다. O (log n )는 구현 및 확인이 1000 배 더 쉽습니다.


답변

아무도 메모리 바인딩 응용 프로그램을 아직 언급하지 않은 것에 놀랐습니다.

복잡성으로 인해 (즉, O (1) < O (log n )) 또는 복잡성 앞에서 상수가 더 작기 때문에 (즉, 2 n 2 <6 n 2 ) 부동 소수점 연산이 적은 알고리즘이있을 수 있습니다. . 그럼에도 불구하고, 낮은 FLOP 알고리즘이 메모리에 더 많은 경우 FLOP가 더 높은 알고리즘을 선호 할 수 있습니다.

“메모리 바운드”의 의미는 항상 캐시에서 벗어난 데이터에 액세스한다는 것입니다. 이 데이터를 가져 오려면 작업을 수행하기 전에 실제 메모리 공간에서 캐시로 메모리를 가져와야합니다. 이 페치 단계는 종종 작업 자체보다 훨씬 느립니다.

따라서 알고리즘에 더 많은 연산이 필요한 경우 (이러한 연산이 이미 캐시에있는 데이터에서 수행되므로 페치가 필요하지 않음) 더 적은 연산으로 알고리즘의 성능을 여전히 능가합니다 (실제로 수행해야 함) 실제 월 시간 측면에서-캐시 데이터 (따라서 페치 필요).


답변

데이터 보안이 중요한 상황에서,보다 복잡한 알고리즘이 타이밍 공격에 대해 더 나은 내성을 가지면 덜 복잡한 알고리즘보다 더 복잡한 알고리즘이 바람직 할 수 있습니다 .


답변

Alistra는 그것을 못 박았지만 어떤 예도 제공하지 않아서 그렇게 할 것입니다.

상점에서 판매하는 것에 대한 10,000 개의 UPC 코드 목록이 있습니다. 10 자리 UPC, 가격 (정액 단위 가격)의 정수, 영수증의 설명 문자 30 자

O (log N) 접근 방식 : 정렬 된 목록이 있습니다. ASCII 인 경우 44 바이트, 유니 코드 인 경우 84 바이트 또는 UPC를 int64로 취급하면 42 및 72 바이트가됩니다. 10,000 개 레코드-가장 높은 경우 메가 바이트 단위의 스토리지에서 비트를보고 있습니다.

O (1) 접근 방식 : UPC를 저장하지 말고 대신 UPC를 배열의 항목으로 사용하십시오. 가장 낮은 경우에는 테라 바이트 급 스토리지의 거의 3 분의 1을보고 있습니다.

사용하는 방법은 하드웨어에 따라 다릅니다. 대부분의 합리적인 최신 구성에서는 log N 접근 방식을 사용합니다. RAM이 매우 짧은 환경에서 대량 저장 공간이 충분한 환경에서 실행하는 경우 두 번째 접근 방식이 정답이라고 생각할 수 있습니다. 디스크에서 테라 바이트의 3 분의 1은 별다른 문제가되지 않으므로 디스크의 한 프로브에서 데이터를 얻는 것이 가치가 있습니다. 간단한 이진법은 평균 13이 걸립니다. (단, 키를 클러스터링하면 보장 된 3 회 읽기로이를 얻을 수 있으며 실제로 첫 번째 키를 캐시 할 수 있습니다.)


답변

빨강 검정 나무를 고려하십시오. 의 액세스, 검색, 삽입 및 삭제 권한이 있습니다 O(log n). 액세스 권한이 O(1)있고 나머지 작업은 O(n)입니다.

따라서 우리가 액세스하는 것보다 더 자주 삽입, 삭제 또는 검색하는 응용 프로그램과이 두 구조 중 하나만 선택하면 빨강-검정 트리를 선호합니다. 이 경우, 레드-블랙 트리의 더 번거로운 O(log n)액세스 시간을 선호한다고 말할 수 있습니다 .

왜? 액세스가 우리의 주요 관심사가 아니기 때문입니다. 우리는 트레이드 오프를하고 있습니다 : 어플리케이션의 성능은 이것 이외의 다른 요소에 의해 더 큰 영향을받습니다. 다른 알고리즘을 최적화하여 큰 이익을 얻으므로이 특정 알고리즘의 성능이 저하됩니다.

따라서 귀하의 질문에 대한 대답은 간단합니다 : 알고리즘의 성장률이 우리가 최적화하고 싶지 않은 경우, 다른 것을 최적화하고 싶을 때. 다른 모든 답변은 특별한 경우입니다. 때로는 다른 작업의 런타임을 최적화합니다. 때때로 우리는 메모리를 최적화합니다. 때로는 보안을 위해 최적화합니다. 때때로 우리는 유지 관리 성을 최적화합니다. 때때로 우리는 개발 시간을 최적화합니다. 알고리즘의 성장률이 런타임에 가장 큰 영향을 미치지 않는다는 것을 알면 무시할 수있는 상수가 낮더라도 런타임에 최적화됩니다. (데이터 세트가이 범위를 벗어난 경우 결국에는 상수를 지배하기 때문에 알고리즘의 성장 속도에 맞게 최적화합니다.) 비용이 많이 들고 대부분의 경우 더 높은 성장 속도의 비용을 다른 것을 최적화하는 알고리즘.


답변

예.

실제로는 짧은 문자열 키와 긴 문자열 키를 사용하여 테이블 조회를 수행하는 몇 가지 테스트를 실행했습니다.

우리는 사용 std::map하는 std::unordered_map해시와 그 샘플을 최대 10 문자열의 길이 배 (이 괜찮은 그래서 우리의 키, GUID 같은 경향), 및 샘플 모든 문자 (이론적으로는 충돌을 감소)하는 해시, 우리가 ==비교를 수행하는 정렬되지 않은 벡터 와 해시를 저장하는 정렬되지 않은 벡터 (해시를 비교하는 경우)를 먼저 비교 한 다음 문자를 비교하십시오.

이 알고리즘의 범위는 O(1)(정렬되지 않은 맵)에서 O(n)(선형 검색)까지입니다.

적당한 크기의 N의 경우, O (n)이 O (1)을 이겼습니다. 노드 기반 컨테이너는 컴퓨터가 메모리를 더 많이 뛰어 넘어야했지만 선형 기반 컨테이너는 그렇지 않았기 때문이라고 생각합니다.

O(lg n)둘 사이에 존재합니다. 어떻게했는지 기억이 나지 않습니다.

성능 차이는 그다지 크지 않았으며 더 큰 데이터 세트에서 해시 기반의 성능이 훨씬 우수했습니다. 그래서 우리는 해시 기반의 순서없는 맵을 고수했습니다.

실제로 합리적인 크기의 n에 대해서는 O(lg n)입니다 O(1). 컴퓨터에 테이블에 40 억 개의 항목 만있는 공간이 있으면으로 표시 O(lg n)됩니다 32. (lg (2 ^ 32) = 32) (컴퓨터 과학에서 lg는 로그 기반 2의 속기입니다).

실제로, lg (n) 알고리즘은 로그 성장 인자 때문에가 아니라 lg (n) 부분이 일반적으로 알고리즘에 일정한 수준의 복잡성이 있다는 것을 의미하기 때문에 O (1) 알고리즘보다 느리며, 복잡성은 lg (n) 항의 “성장”중 하나보다 큰 상수 계수.

그러나 해시 매핑과 같은 복잡한 O (1) 알고리즘은 유사하거나 더 큰 상수를 쉽게 가질 수 있습니다.