[algorithm] 알고리즘의 시간 복잡성을 찾는 방법

질문

알고리즘의 시간 복잡성을 찾는 방법은 무엇입니까?

SO에 질문을 게시하기 전에 무엇을 했습니까?

나는 이것 , 이것 과 다른 많은 링크를 겪었다.

그러나 시간 복잡성을 계산하는 방법에 대한 명확하고 직접적인 설명을 찾을 수있는 곳은 없습니다.

내가 뭘 알 겠어 ?

아래 코드와 같이 간단한 코드를 말하십시오.

char h = 'y'; // This will be executed 1 time
int abc = 0; // This will be executed 1 time

아래와 같은 루프를 말하십시오.

for (int i = 0; i < N; i++) {
    Console.Write('Hello World !');
}

int i = 0; 이것은 한 번만 실행됩니다 . 시간은 실제로 i=0선언이 아닌 계산됩니다 .

i <N; N + 1 번 실행됩니다

i ++; 이것은 N 번 실행 됩니다

따라서이 루프에 필요한 작업 수는

{1+ (N + 1) + N} = 2N + 2

참고 : 시간 복잡도 계산에 대한 이해가 확실하지 않기 때문에 여전히 잘못되었을 수 있습니다.

내가 알고 싶은 것?

좋아,이 작은 기본 계산은 내가 알고 있다고 생각하지만, 대부분의 경우 시간 복잡도를

O (N), O (N2), O (로그 N), O (N!) …. 많은 다른 ,

누구나 알고리즘의 시간 복잡성을 계산하는 방법을 이해하도록 도울 수 있습니까? 나는 이것을 알고 싶어하는 초보자가 많이 있다고 확신합니다.



답변

알고리즘의 시간 복잡성을 찾는 방법

입력 크기의 함수로 실행할 기계 명령어 수를 더한 다음 식을 가장 큰 (N이 매우 큰 경우) 용어로 단순화하고 단순화 상수를 포함 할 수 있습니다.

예를 들어 2N + 2기계 명령어를 단순화하여이를 간단히 설명 하는 방법을 살펴 보겠습니다 O(N).

왜 두 개를 제거 2합니까?

N이 커짐에 따라 알고리즘의 성능에 관심이 있습니다.

2N과 2라는 두 용어를 고려하십시오.

N이 커짐에 따라이 두 항의 상대적 영향은 무엇입니까? N이 백만이라고 가정합니다.

그런 다음 첫 번째 용어는 2 백만이고 두 번째 용어는 2입니다.

이러한 이유로 우리는 큰 N에 대해 가장 큰 항을 제외한 모든 항을 제거합니다.

이제 우리는에서 2N + 2로 이동했습니다 2N.

전통적으로 우리는 일정한 요소까지만 성능에 관심이 있습니다.

이것은 N이 클 때 성능에 일정한 배수 차이가 있는지 실제로 신경 쓰지 않는다는 것을 의미합니다. 어쨌든 2N의 단위는 처음부터 잘 정의되어 있지 않습니다. 따라서 가장 간단한 표현을 얻기 위해 상수 인자를 곱하거나 나눌 수 있습니다.

그래서 2N그냥 N됩니다.


답변

이것은 훌륭한 기사입니다 :
http://www.daniweb.com/software-development/computer-science/threads/13488/time-complexity-of-algorithm

아래 답변이 위에서 복사되었습니다 (우수한 링크가 파열 된 경우)

시간 복잡성을 계산하기위한 가장 일반적인 지표는 Big O 표기법입니다. 이렇게하면 N이 무한대에 가까워 질 때 N과 관련하여 실행 시간을 추정 할 수 있도록 모든 상수 요소가 제거됩니다. 일반적으로 다음과 같이 생각할 수 있습니다.

statement;

일정하다. 문의 실행 시간은 N과 관련하여 변경되지 않습니다.

for ( i = 0; i < N; i++ )
     statement;

선형입니다. 루프의 작동 시간은 N에 정비례합니다. N이 두 배가되면 작동 시간도 증가합니다.

for ( i = 0; i < N; i++ ) {
  for ( j = 0; j < N; j++ )
    statement;
}

이차입니다. 두 루프의 실행 시간은 N의 제곱에 비례합니다. N이 두 배가되면 실행 시간이 N * N 증가합니다.

while ( low <= high ) {
  mid = ( low + high ) / 2;
  if ( target < list[mid] )
    high = mid - 1;
  else if ( target > list[mid] )
    low = mid + 1;
  else break;
}

로그입니다. 알고리즘의 실행 시간은 N을 2로 나눌 수있는 횟수에 비례합니다. 이는 알고리즘이 작업 영역을 각 반복마다 절반으로 나누기 때문입니다.

void quicksort ( int list[], int left, int right )
{
  int pivot = partition ( list, left, right );
  quicksort ( list, left, pivot - 1 );
  quicksort ( list, pivot + 1, right );
}

N * log (N)입니다. 실행 시간은 로그인 N 루프 (반복 또는 재귀)로 구성되므로 알고리즘은 선형 및 로그의 조합입니다.

일반적으로 한 차원의 모든 항목으로 작업을 수행하는 것은 선형이고, 두 차원의 모든 항목으로 작업을 수행하는 것은 2 차적이며 작업 영역을 반으로 나누는 것이 로그입니다. 3 차, 지수 및 제곱근과 같은 다른 Big O 측정 값이 있지만 거의 공통적이지 않습니다. 큰 O 표기법은 측정 값이있는 O ( <type> )위치 로 설명됩니다 <type>. 퀵 정렬 알고리즘은로 설명됩니다 O ( N * log ( N ) ).

이 중 어느 것도 최고, 평균 및 최악의 경우를 고려하지 않았습니다. 각각 고유 한 Big O 표기법이 있습니다. 또한 이것은 매우 간단한 설명입니다. Big O가 가장 일반적이지만 내가 보여준 것보다 더 복잡합니다. 큰 오메가, 작은 o 및 큰 세타와 같은 다른 표기법도 있습니다. 아마도 알고리즘 분석 과정 밖에서 그것들을 만나지 못할 것입니다. 😉


답변

여기에서 가져온 것- 알고리즘의 시간 복잡성 소개

1. 소개

컴퓨터 과학에서 알고리즘의 시간 복잡도는 알고리즘이 입력을 나타내는 문자열 길이의 함수로 실행하는 데 걸리는 시간을 수량화합니다.

2. 큰 O 표기법

알고리즘의 시간 복잡도는 일반적으로 계수 및 하위 차수를 제외하는 큰 O 표기법을 사용하여 표현됩니다. 이러한 방식으로 표현 될 때, 시간 복잡도는 무의식적으로, 즉 입력 크기가 무한대로 간다고한다.

예를 들어, 크기 n의 모든 입력에서 알고리즘에 필요한 시간이 최대 5n 3 + 3n 인 경우 점근 적 시간 복잡도는 O (n 3 )입니다. 나중에 더 자세히.

몇 가지 예 :

  • 1 = O (n)
  • n = O (n 2 )
  • 로그 (n) = O (n)
  • 2n + 1 = O (n)

3. O (1) 일정 시간 :

알고리즘은 입력 크기에 관계없이 동일한 시간이 필요한 경우 일정한 시간에 실행된다고합니다.

예 :

  • 배열 : 모든 요소에 액세스
  • 고정 크기 스택 : 푸시 및 팝 방법
  • 고정 크기 대기열 : 대기열 및 대기열에서 제외 방법

4. O (n) 선형 시간

알고리즘은 시간 실행이 입력 크기에 직접 비례하는 경우 선형 시간으로 실행된다고합니다. 즉, 입력 크기가 증가함에 따라 시간이 선형으로 증가합니다.

다음 예제를 고려하십시오. 아래에서 요소를 선형으로 검색하는 경우 시간 복잡성이 O (n)입니다.

int find = 66;
var numbers = new int[] { 33, 435, 36, 37, 43, 45, 66, 656, 2232 };
for (int i = 0; i < numbers.Length - 1; i++)
{
    if(find == numbers[i])
    {
        return;
    }
}

더 많은 예 :

  • 배열 : 선형 검색, 이송, 최소 찾기 등
  • ArrayList : 메소드 포함
  • 큐 : 메소드 포함

5. O (log n) 로그 시간 :

알고리즘의 시간 실행이 입력 크기의 로그에 비례하면 알고리즘은 로그 시간으로 실행됩니다.

예 : 이진 검색

“20 개의 질문”게임을 상기하십시오. 과제는 간격으로 숨겨진 숫자의 값을 추측하는 것입니다. 추측 할 때마다 추측이 너무 높거나 낮은 지 알려줍니다. 20 개의 질문 게임은 추측 횟수를 사용하여 구간 크기를 절반으로 줄이는 전략을 의미합니다. 이진 검색으로 알려진 일반적인 문제 해결 방법의 예입니다.

6. O (n 2 ) 2 차 시간

시간 실행이 입력 크기의 제곱에 비례하면 알고리즘은 2 차 시간으로 실행된다고합니다.

예 :

7. 유용한 링크들


답변

이 질문에 대한 좋은 답변이 있지만. 의 몇 가지 예와 함께 여기에 다른 답변을 드리겠습니다 loop.

  • O (n) : 루프 변수가 일정량 증가 / 감소되면 루프의 시간 복잡도는 O (n) 으로 간주됩니다 . 예를 들어 다음 함수는 시간 복잡도 가 O (n) 입니다.

    // Here c is a positive integer constant
    for (int i = 1; i <= n; i += c) {
        // some O(1) expressions
    }
    
    for (int i = n; i > 0; i -= c) {
        // some O(1) expressions
    }
    
  • O (n ^ c) : 중첩 루프의 시간 복잡도는 가장 안쪽 명령문이 실행 된 횟수와 같습니다. 예를 들어 다음 샘플 루프의 시간 복잡도 는 O (n ^ 2)입니다.

    for (int i = 1; i <=n; i += c) {
       for (int j = 1; j <=n; j += c) {
          // some O(1) expressions
       }
    }
    
    for (int i = n; i > 0; i += c) {
       for (int j = i+1; j <=n; j += c) {
          // some O(1) expressions
    }
    

    예를 들어 선택 정렬 및 삽입 정렬의 시간 복잡도 는 O (n ^ 2) 입니다.

  • 루프 변수가 일정한 양으로 나누어 지거나 곱 하면 루프의 O (Logn) 시간 복잡도는 O (Logn) 로 간주됩니다 .

    for (int i = 1; i <=n; i *= c) {
       // some O(1) expressions
    }
    for (int i = n; i > 0; i /= c) {
       // some O(1) expressions
    }
    

    예를 들어 이진 검색에는 O (Logn) 시간 복잡성이 있습니다.

  • 루프 변수가 일정한 양만큼 기하 급수적으로 감소 / 증가되는 경우 루프의 O (LogLogn) 시간 복잡도는 O (LogLogn) 로 간주됩니다 .

    // Here c is a constant greater than 1
    for (int i = 2; i <=n; i = pow(i, c)) {
       // some O(1) expressions
    }
    //Here fun is sqrt or cuberoot or any other constant root
    for (int i = n; i > 0; i = fun(i)) {
       // some O(1) expressions
    }
    

시간 복잡도 분석의 한 예

int fun(int n)
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j < n; j += i)
        {
            // Some O(1) task
        }
    }
}

분석 :


For i = 1, the inner loop is executed n times.
For i = 2, the inner loop is executed approximately n/2 times.
For i = 3, the inner loop is executed approximately n/3 times.
For i = 4, the inner loop is executed approximately n/4 times.
…………………………………………………….
For i = n, the inner loop is executed approximately n/n times.

따라서 위 알고리즘의 총 시간 복잡도 (n + n/2 + n/3 + … + n/n)n * (1/1 + 1/2 + 1/3 + … + 1/n)

시리즈에서 중요한 것은 O (Logn)(1/1 + 1/2 + 1/3 + … + 1/n) 과 같습니다 . 따라서 위 코드의 시간 복잡도는 O (nLogn) 입니다.


참고 :
1
2
3


답변

예제의 시간 복잡성

1-기본 연산 (산술, 비교, 배열 요소 액세스, 할당) : 실행 시간은 항상 일정합니다 O (1)

예 :

read(x)                               // O(1)
a = 10;                               // O(1)
a = 1.000.000.000.000.000.000         // O(1)

2-then else statement : 둘 이상의 가능한 명령문에서 최대 실행 시간 만 가져옵니다.

예:

age = read(x)                               // (1+1) = 2
if age < 17 then begin                      // 1
      status = "Not allowed!";              // 1
end else begin
      status = "Welcome! Please come in";   // 1
      visitors = visitors + 1;              // 1+1 = 2
end;

따라서 위의 의사 코드의 복잡성은 T (n) = 2 + 1 + max (1, 1 + 2) = 6입니다. 따라서 큰 오는 여전히 상수 T (n) = O (1)입니다.

3-반복 (for, while, repeat) :이 명령문의 실행 시간은 반복 횟수에 해당 반복 내의 조작 수를 곱한 것입니다.

예:

total = 0;                                  // 1
for i = 1 to n do begin                     // (1+1)*n = 2n
      total = total + i;                    // (1+1)*n = 2n
end;
writeln(total);                             // 1

따라서 복잡도는 T (n) = 1 + 4n + 1 = 4n + 2입니다. 따라서 T (n) = O (n)입니다.

4-중첩 루프 (루핑 내부 루핑) : 기본 루핑 내부에 하나 이상의 루핑이 있으므로이 명령문의 실행 시간은 O (n ^ 2) 또는 O (n ^ 3)을 사용했습니다.

예:

for i = 1 to n do begin                     // (1+1)*n  = 2n
   for j = 1 to n do begin                  // (1+1)n*n = 2n^2
       x = x + 1;                           // (1+1)n*n = 2n^2
       print(x);                            // (n*n)    = n^2
   end;
end;

일반적인 러닝 타임

알고리즘을 분석 할 때 몇 가지 일반적인 실행 시간이 있습니다.

  1. O (1) – 상수 시간 상수 시간은 실행 시간이 일정 함을 의미 하며 입력 크기의 영향을받지 않습니다 .

  2. O (n) – 선형 시간 알고리즘이 n 개의 입력 크기를 허용하면 n 개의 연산도 수행합니다.

  3. O (log n) – 실행 시간 O (log n)이있는 로그 시간 알고리즘이 O (n)보다 약간 빠릅니다. 일반적으로 알고리즘은 문제를 동일한 크기의 하위 문제로 나눕니다. 예 : 이진 검색 알고리즘, 이진 변환 알고리즘

  4. O (n log n) – Linearithmic Time이 실행 시간은 종종 문제를 하위 문제로 재귀 적으로 나누고 n 번으로 병합하는 “분할 및 정복 알고리즘”에서 찾을 수 있습니다. 예 : 병합 정렬 알고리즘

  5. O (n 2 ) – 2 차 시간 모양 버블 정렬 알고리즘!

  6. O (n 3 ) – 입방 시간 O (n 2 ) 와 동일한 원리를 갖습니다 .

  7. O (2 n ) – 지수 시간 n이 1000.000이면 입력이 커질수록 T (n)은 21000.000이됩니다. Brute Force 알고리즘에는이 실행 시간이 있습니다.

  8. O (n!) – 팩토리얼 타임 가장 느린 !!! 예 : 출장 판매원 문제 (TSP)

이 기사 에서 발췌 . 잘 설명해야합니다.


답변

코드를 분석 할 때는 모든 작업 / 인식 시간 복잡성을 계산하여 한 줄씩 분석해야하며, 결국 전체 그림을 얻기 위해 코드를 합산해야합니다.

예를 들어 선형 복잡도를 가진 간단한 루프를 하나 만들 수 있지만 나중에 같은 프로그램에서 3 루프를 갖는 3 차 루프를 가질 수 있으므로 프로그램은 3 차 복잡성 을 갖습니다 . 성장의 기능 순서가 바로 여기에 있습니다.

알고리즘의 시간 복잡성에 대한 가능성을 살펴보면 위에서 언급 한 성장 순서를 볼 수 있습니다.

  • 일정 시간이 성장의 순서가1예를 들어, :a = b + c.

  • 대수 시간 은 성장 순서가LogN있습니다. 일반적으로 무언가를 반으로 나누거나 (이진 검색, 나무, 심지어 루프) 같은 방식으로 무언가를 곱할 때 발생합니다.

  • 선형 , 성장 순서는N예를 들어

    int p = 0;
    for (int i = 1; i < N; i++)
      p = p + 2;
    
  • Linearithmic , 성장 순서는n*logN일반적으로 나누기 및 정복 알고리즘에서 발생합니다.

  • 입방 , 성장 순서N^3, 고전적인 예는 모든 트리플렛을 확인하는 트리플 루프입니다.

    int x = 0;
    for (int i = 0; i < N; i++)
       for (int j = 0; j < N; j++)
          for (int k = 0; k < N; k++)
              x = x + 2
    
  • 지수 , 성장 순서는2^N일반적으로 전체 세트를 수행 할 때 발생합니다 (예 : 일부 세트의 서브 세트 확인).


답변

느슨하게 말하면, 시간 복잡도는 입력 크기가 증가함에 따라 알고리즘의 작업 수 또는 런타임이 어떻게 증가 하는지를 요약하는 방법입니다.

인생의 대부분의 것들과 마찬가지로, 칵테일 파티는 우리가 이해하는 데 도움이 될 수 있습니다.

의 위에)

파티에 도착하면 모든 사람의 손을 흔들어야합니다 (모든 항목에 대해 작업 수행). 참석자의 수가 N증가함에 따라 모든 사람의 손을 흔드는 데 걸리는 시간 / 작업이로 증가합니다 O(N).

O(N)그렇지 cN않습니까?

사람들과 악수하는 데 걸리는 시간에는 차이가 있습니다. 이것을 평균화하여 상수로 캡처 할 수 c있습니다. 그러나 여기서 모든 사람과 악수하는 기본적인 작업 은 O(N)무엇이든간에 항상 비례합니다 c. 우리가 칵테일 파티에 가야하는지에 대해 토론 할 때, 우리는 종종 그 모임이 어떻게 보이는지에 대한 세부적인 내용보다 모든 사람을 만나야한다는 사실에 더 관심이 있습니다.

O (N ^ 2)

칵테일 파티의 호스트는 모든 사람들이 다른 사람들을 만나는 어리석은 게임을 원합니다. 따라서 N-1다른 사람을 만나야 합니다. 다음 사람이 이미 당신을 만났기 N-2때문에 사람들을 만나야합니다 . 이 시리즈의 합은입니다 x^2/2+x/2. 참석자의 수가 증가함에 따라이 x^2용어는 빠르게 커지 므로 다른 모든 것을 삭제합니다.

O (N ^ 3)

다른 모든 사람을 만나야하며, 각 회의 중에는 회의실에있는 다른 모든 사람에 대해 이야기해야합니다.

O (1)

호스트는 무언가를 발표하려고합니다. 그들은 와인 글라스를 딩하고 큰 소리로 말합니다. 모두가들을 수 있습니다. 참석자가 몇 명인지는 중요하지 않습니다.이 작업은 항상 같은 시간이 걸립니다.

O (로그 N)

호스트는 모든 사람을 알파벳 순서로 테이블에 배치했습니다. 댄은 어디에 있습니까? 당신은 그가 아담과 맨디 사이에 있어야한다고 생각합니다 (분명히 맨디와 잭 사이는 아닙니다!). 그는 조지와 맨디 사이에 있습니까? 아담과 프레드 사이, 신디와 프레드 사이에 있어야합니다. 그리고 … 우리는 세트의 절반과 그 세트의 절반을 보면서 Dan을 효율적으로 찾을 수 있습니다. 궁극적으로 O (log_2 N) 개인을 봅니다.

O (N 로그 N)

위의 알고리즘을 사용하여 테이블에서 앉을 위치를 찾을 수 있습니다. 많은 사람들이 한 번에 하나씩 테이블에 와서 모두이 작업을 수행하면 O (N log N) 시간이 걸립니다. 항목을 비교해야 할 때 모음을 정렬하는 데 걸리는 시간입니다.

최고 / 최악의 사례

당신은 파티에 도착하고 이니 고를 찾아야합니다-얼마나 오래 걸립니까? 도착 시간에 따라 다릅니다. 모두가 밀링 작업을하는 경우 최악의 상황을 경험 한 경우 O(N)시간 이 걸립니다 . 그러나 모든 사람이 테이블에 앉으면 O(log N)시간 이 걸립니다 . 또는 호스트의 와인 글라스 소리를 활용할 수 있으며 O(1)시간 이 걸립니다 .

호스트를 사용할 수 없다고 가정하면 Inigo 찾기 알고리즘 에 도착한 당사자의 상태에 따라 O(log N)하한과 상한 이 있다고 말할 수 있습니다 O(N).

우주 및 커뮤니케이션

알고리즘이 공간 또는 통신을 사용하는 방법을 이해하는 데 동일한 아이디어를 적용 할 수 있습니다.

Knuth는 전자의 “곡의 복잡성” 에 관한 멋진 논문을 썼습니다 .

정리 2 : 복잡도 O (1)의 노래는 임의로 긴 곡이 있습니다.

증거 : (케이시와 선샤인 밴드로 인해). (15)에 의해 정의 된 노래 Sk를 고려하지만

V_k = 'That's the way,' U 'I like it, ' U
U   = 'uh huh,' 'uh huh'

모든 k.