2016-12-11 3 views
2

나는이 algorithm의 시간 복잡도를 찾으려고합니다.반복 알고리즘의 시간 복잡도

반복 : 알고리즘은 주어진 비트 - 스트링으로부터 주어진 해밍 거리 내의 모든 비트 - 스트링을 생성합니다. 모든 증가 시퀀스 0 <= a[0] < ... < a[dist-1] < strlen(num)을 생성하고 해당 인덱스의 비트를 되돌립니다.

벡터 a은 어떤 비트가 반전되어야하는지에 대한 색인을 유지해야합니다. 따라서 a에 현재 색인 i이 포함되어 있으면 0 대신 1을 인쇄하고 그 반대로 인쇄합니다. 그렇지 않으면 아래와 같이 비트를 인쇄합니다 (else-part 참조).

// e.g. hamming("0000", 2); 
void hamming(const char* num, size_t dist) { 
    assert(dist > 0); 
    vector<int> a(dist); 
    size_t k = 0, n = strlen(num); 
    a[k] = -1; 
    while (true) 
     if (++a[k] >= n) 
      if (k == 0) 
       return; 
      else { 
       --k; 
       continue; 
      } 
     else 
      if (k == dist - 1) { 
       // this is an O(n) operation and will be called 
       // (n choose dist) times, in total. 
       print(num, a); 
      } 
      else { 
       a[k+1] = a[k]; 
       ++k; 
      } 
} 

이 알고리즘의 시간 복잡도는 얼마입니까?


내 시도는 말한다 :

DIST * n 개의 +는 (N t 선택) * N + 2

그러나 이것은 사실이없는 것, 모든, 다음 예를 고려 with dist = 2 :

len = 3, (3 choose 2) = 3 * O(n), 10 while iterations 
len = 4, (4 choose 2) = 6 * O(n), 15 while iterations 
len = 5, (5 choose 2) = 9 * O(n), 21 while iterations 
len = 6, (6 choose 2) = 15 * O(n), 28 while iterations 

다음은 두 가지 대표적인 실행입니다 (sta에서 인쇄 될 예정 임). 루프 RT)

000, len = 3 
k = 0, total_iter = 1 
vector a = -1 0 
k = 1, total_iter = 2 
vector a = 0 0 
Paid O(n) 
k = 1, total_iter = 3 
vector a = 0 1 
Paid O(n) 
k = 1, total_iter = 4 
vector a = 0 2 
k = 0, total_iter = 5 
vector a = 0 3 
k = 1, total_iter = 6 
vector a = 1 1 
Paid O(n) 
k = 1, total_iter = 7 
vector a = 1 2 
k = 0, total_iter = 8 
vector a = 1 3 
k = 1, total_iter = 9 
vector a = 2 2 
k = 0, total_iter = 10 
vector a = 2 3 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
[email protected]:~/Desktop/generate_bitStrings_HammDistanceT$ ./iter 
0000, len = 4 
k = 0, total_iter = 1 
vector a = -1 0 
k = 1, total_iter = 2 
vector a = 0 0 
Paid O(n) 
k = 1, total_iter = 3 
vector a = 0 1 
Paid O(n) 
k = 1, total_iter = 4 
vector a = 0 2 
Paid O(n) 
k = 1, total_iter = 5 
vector a = 0 3 
k = 0, total_iter = 6 
vector a = 0 4 
k = 1, total_iter = 7 
vector a = 1 1 
Paid O(n) 
k = 1, total_iter = 8 
vector a = 1 2 
Paid O(n) 
k = 1, total_iter = 9 
vector a = 1 3 
k = 0, total_iter = 10 
vector a = 1 4 
k = 1, total_iter = 11 
vector a = 2 2 
Paid O(n) 
k = 1, total_iter = 12 
vector a = 2 3 
k = 0, total_iter = 13 
vector a = 2 4 
k = 1, total_iter = 14 
vector a = 3 3 
k = 0, total_iter = 15 
vector a = 3 4 

답변

2

을 얻을, 당신은 a의 초기화를 계산하면 다른 두 가지 (또는 세 가지를하고 있다는 논증이다). 이것이 복잡도 계산에 어려움을주고 있으며, 효율성이 떨어집니다. 추상에서

가 점진적으로 현재의에서 인덱스의 다음 세트를 계산하기 위해, 아이디어가 그것을 증가하고 a[i]+1, a[i]+2에 다음 인덱스를 설정, n-dist+i 이하의 마지막 인덱스, i을 찾는 것입니다, 등등.

예를 들어, DIST = 5, N = 11 및 인덱스 인 경우 :

0, 3, 5, 9, 10 

이어서 5는 (n-dist+i보다 마지막 값 이하 n-dist 6이고, 10 = 6 + 4, 9 때문에 = 6 + 3, 그러나 5 < 6 + 2). , k=4

0, 3, 5, 9, 10 
  • a[k] + 1는 11 가정,

    0, 3, 6, 7, 8 
    

    지금 당신의 코드를 실행하는 방법을 고려하십시오

    그래서 우리는 5 증가 및 인덱스의 집합을 얻기 위해 다음 정수를 설정 따라서 k은 3이된다.

  • ++a[k]은 10이므로,그래서 k
  • ++a[k] 2. 6 그래서 a[k+1] 6되고, k 3된다되고, 98,10가되고, k 4.
  • ++a[k]는 11가되고, 그래서 k
  • ++a[k] 3. 11된다.
  • ++a[k] 7, 그래서 a[k+1] 7이되고, k 4.
  • ++a[k]이 8되고, 우리는 print 함수를 호출하는 것을 계속한다.

이 코드는 올바르지 만 k가 앞뒤로 현창하기 때문에 그것이 더 높은 지수에서 오버 플로우를 발생시키지 않고 증가 될 수있는 가장 높은 지수를 찾고있어 효율적 아니다. 실제로 가장 높은 인덱스가 j이면 끝점에서 코드는 while 루프의 비선형 반복을 사용합니다. n의 다른 값에 대해 n==dist 일 때 while 루프의 반복 횟수를 추적하면 쉽게 직접이를 증명할 수 있습니다. 정확히 한 줄의 출력이 있지만 반복 횟수가 O (2^n) 증가하는 것을 볼 수 있습니다 (사실 2^(n + 1) -2 반복).

이 스 캐터링은 코드를 불필요하게 비효율적으로 만들고 분석하기도 어렵습니다.

대신 더 직접적인 방법으로 코드를 작성할 수 있습니다 :

void hamming2(const char* num, size_t dist) { 
    int a[dist]; 
    for (int i = 0; i < dist; i++) { 
     a[i] = i; 
    } 
    size_t n = strlen(num); 
    while (true) { 
     print(num, a); 
     int i; 
     for (i = dist - 1; i >= 0; i--) { 
      if (a[i] < n - dist + i) break; 
     } 
     if (i < 0) return; 
     a[i]++; 
     for (int j = i+1; j<dist; j++) a[j] = a[i] + j - i; 
    } 
} 

이제 while 루프를 통해 때마다 인덱스의 새로운 세트를 생성합니다. 반복 당 정확한 비용은 간단하지 않지만 print이 O (n)이고 while 루프의 나머지 코드가 최악 O (dist) 일 때 전체 비용은 O (N_INCR_SEQ (n, dist) * n)입니다. 여기서 N_INCR_SEQ (n, dist)는 길이가 dist 인 자연수가 증가하는 시퀀스의 수인 < n입니다. 댓글에있는 누군가가이 공식을 제공하는 링크를 제공합니다.

+1

+1. Re : "N_INCR_SEQ (n, dist)는 자연수의 증가 시퀀스의 길이입니다. ruakh

+1

덧붙여 말하자면, 분석의 한 의미는'if (++ a [k]> = n)'행을'if (++ a [k] = n)'행으로 변경하여 OP가 코드의 성능을 최소한으로 수정할 수 있다는 것입니다. > n - dist + k)'를 선택하십시오. 그러면 불필요한/비생산적인 앞뒤 패스가 모두 제거됩니다. – ruakh

+0

실제로 @ruakh,하지만 나는 Paul의 코드가 더 마음에 든다. 내 젊은 눈보다 우아 해 보인다! O ((n choose dist) * n)의 전체 시간 복잡도 ... – gsamaras

1

통지, 그 길이를 나타낸다 nt 필요한 거리 1n 사이 t 정수의 증가, 음이 아닌 일련의 개수를 나타낸다 (또는하여 주어진 인덱스 양식은 0n-1 사이이며 실제로는 n choose t입니다. t 개의 고유 색인을 선택합니다.

문제는 그 시리즈의 당신의 세대 발생

- 첫째, 길이 4의 경우, 예를 들어 그 통지, 당신은 실제로 이상의 5 가지 지표, 0

-Secondly 4로 이동 동일한 지표 (t=2, 그 경우 0 0, 1 1, 2 2의 경우 등)를 사용하여 계정 시리즈를 사용하고 있으며 일반적으로 시리즈가 증가하는 대신 시리즈가 아닌 시리즈를 거치게됩니다.

프로그램의 TC를 계산할 때는이를 고려해야합니다.

힌트 : 일련의 우주에서 일부 방정식에 대한 정수 해답의 우주에 일대일 대응을 시도하십시오. 이 https://math.stackexchange.com/questions/432496/number-of-non-decreasing-sequences-of-length-m


최종 솔루션 (n+t-1) choose (t)이지만, 하나 당신 루프 때문에 그 실제로 프로그램에서, ((n+1)+t-1) choose (t)을 첫 번째 글 머리 기호를 알아 차리지 : 당신이 직접 솔루션을 필요로하는 경우

, 여기 좀 봐 추가 색인. 나타내는

((n+1)+t-1) choose (t) =: A, 루프가 다소 영리하고 미묘한 동안

n choose t =: B 전반적으로 우리가 O(1) + B*O(n) + (A-B)*O(1)

+0

"Secondly"단락이 정확하다고 생각하지 않습니다. 'while' 루프는 무조건적으로'a [k]'를 증가시킴으로써 시작됩니다. (어떤 이유인지 모르겠지만, 이것을 'if'테스트에 넣음으로써 난독 화되었습니다.) 거기에 있습니다.) – ruakh

+0

@ruakh 그의 실행 예제를 보면, 모든 감소하지 않는 시리즈를 통과하는 것으로 생각했습니다. 내가 잘못? – GoldenSpecOps

+0

그의 실행 예제는 각 루프 반복의 * start *에서 벡터의 내용을 보여줍니다. 벡터는 루프 반복 중에 수정됩니다. 그러나 그것은 복잡합니다. 벡터의 내용은 절대로 '1 1 1'(같은 값이 3 번 반복됨) 일 수 없지만 일시적으로 '1 1 4'또는 '1 2 2'와 같을 수 있습니다. – ruakh