Как перезапустить цикл в C ++ (поиск уникальной последовательности при случайных запусках) - PullRequest
1 голос
/ 05 марта 2009

Следующие коды пытаются сгенерировать случайные строки на протяжении K серий. Но мы хотим, чтобы вновь сгенерированные строки были совершенно другими с его ссылочной строкой.

Для этого я попытался использовать «продолжить», чтобы перезапустить случайный процесс генерации строки. Однако это не похоже на работу. Что не так с моим подходом ниже?

#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <time.h>
using namespace std;


// In this code we want to print new string that is entirely different with  
// with those in initVector 


template <typename T> void  prn_vec(std::vector < T >&arg, string sep="")
{   // simple function for printing vector
    for (int n = 0; n < arg.size(); n++) {
        cout << arg[n] << sep; 
    }
}


int main  ( int arg_count, char *arg_vec[] ) {

    // This is reference string
    vector <string> initVec;
    initVec.push_back("A");
    initVec.push_back("A");
    initVec.push_back("A");
    initVec.push_back("A");

    vector <string> DNA;
      DNA.push_back("A");
      DNA.push_back("C");
      DNA.push_back("G");
      DNA.push_back("T");

    for (unsigned i =0; i< 10000; i++) {

       vector <string> newString;
       for(unsigned j=0; j<initVec.size(); j++) {

         int dnaNo = rand() % 4;
         string newBase = DNA[dnaNo];
         string oldBase = initVec[j];

         int sameCount = 0;
         if (newBase == oldBase) {
            sameCount++;
         }

         if (sameCount == initVec.size()) {
              continue;
         }

         newString.push_back(newBase);

       } 
       cout << "Run " << i << " : ";
       prn_vec<string>(newString);
       cout << endl;

    }

    return 0;
}

Ответы [ 5 ]

4 голосов
/ 05 марта 2009

Ваш код выглядит на первый взгляд хорошо, если я не пропущу большую часть ваших требований. Прочитайте это , прежде чем использовать rand(). За исключением, конечно, части continue. То, что вы пытаетесь сделать, это посмотреть, если это то же самое, что initVector или нет, верно? Простое сравнение можно выполнить до того, как вы вставите его или напечатаете на консоли.

int sameCount = 0;
if (newBase == oldBase) {
 sameCount++;
}
// sameCount can be 1 at most, 0 otherwise
// this check never return true
if (sameCount == initVec.size()) {
continue;
}

Переменная sameCount инициализируется каждый раз, когда вы создаете новую запись для newString, и выходит из области видимости при закрытии } цикла for. Таким образом, он не будет увеличен, чтобы функционировать как надлежащая проверка на наличие дубликатов. В идеале вы должны использовать std::set и продолжать вставлять в него. Дубликаты не допускаются, и вы избавлены от многих неприятностей.

Подробнее об использовании rand() srand() и генерации случайных чисел:

Из comp.lang.c FAQ:

[...] биты младших разрядов многих генераторов случайных чисел крайне беспорядочно

Если вы хотите, чтобы ваши случайные числа находились в диапазоне

[0, 1, ... N - 1]

лучший метод по сравнению с простым rand() % N (как указано в ссылке) - использовать следующее:

(int)((double)rand() / ((double)RAND_MAX + 1) * N)

Теперь, если вы запустите свою программу, каждый раз вы будете получать один и тот же набор из 10000 нечетных случайных нитей ДНК. Оказывается, это потому, что:

Для большинства генераторов псевдослучайных чисел (и определенного свойства ранда библиотеки C) характерно, что они всегда начинаются с одного и того же числа и проходят одну и ту же последовательность.

из другого FAQ comp.lang.c.

Для получения разных прядей попробуйте следующее:

#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <ctime>
#include <cstdlib>
using namespace std;
    int main  ( int arg_count, char *arg_vec[] ) {

    // most pseudo-random number generators 
    // always start with the same number and 
    // go through the same sequence. 
    // coax it to do something different!
    srand((unsigned int)time((time_t *)NULL));

    // This is reference string
    string initVec("AAAA");    
    // the family
    string DNA("ACGT");

    for (unsigned i =0; i< 5; i++) {
       string newString;
       for(unsigned j=0; j<initVec.size(); j++) {
         int dnaNo = (int)((double)rand() / ((double)RAND_MAX + 1) * 4);
         char newBase = DNA[dnaNo];         
         newString += newBase;
       }
               // ideally push in a std::set 
               // for now keep displaying everything
         if (newString != initVec) {
               cout << "Run " << i << " : " << newString << endl; 
            }
         }
     return 0;
}
2 голосов
/ 05 марта 2009

Ваш алгоритм является поддельным. Что бы вы ни пытались сделать, вы этого не делаете, и поскольку там нет ни одного комментария, я не могу точно сказать, где вы ошиблись.

Ваш внутренний цикл:

for each element of initVec (4)
    create a random element
    set sameCount to 0
    if random element == current element of initVec, set sameCount to 1
    if sameCount == 4, do something (pointless as this never happens)
    add random element to newString

Кроме того, ваша "newString" - это вовсе не строка, а вектор строк.

Итак, ваша проблема даже не в использовании continue, а в том, что ваш алгоритм FUBAR.

1 голос
/ 05 марта 2009

Вы поняли, что sameCount никогда не становится больше 1? Поскольку initVec.size () больше 1, выполнение никогда не завершается.

int sameCount = 0;
    //sameCount is 0
    if (newBase == oldBase) { // if it is true sameCount is 1
        sameCount++;
    }
    // sameCount is 1 or 0
    if (sameCount == initVec.size()) { //this expression is always false if initVec longer than 1
        continue;
    }

Как уже говорили другие, с этим кодом трудно понять, что вы хотели сделать. Не могли бы вы рассказать нам, например, что вы имеете в виду «совсем другой»?

1 голос
/ 05 марта 2009

Ответ Диркгентли довольно исчерпывающий для того, что я пытался сказать сейчас.

Я хотел бы порекомендовать вам не использовать continue, хотя большинство стандартов кодирования рекомендуют не использовать continue по уважительной причине, поскольку это затрудняет контроль за потоком.

1 голос
/ 05 марта 2009

continue не пропускает увеличивающуюся часть цикла for. Все, что он делает, это идет прямо к нему, пропуская остальную часть тела цикла.

for(int i = 0; i < 10; i++)
{
  if(i == 3)
    continue;
  printf("%d ", i);
}

Эквивалентно:

int i = 0;
while(i < 10)
{
  if(i == 3)
    goto increment;
  printf("%d ", i);
increment:
  i++;
}

Никакой обратной косой черты в printf() нет, так как я не мог понять, как заставить текстовый редактор позволить мне напечатать его. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...