Как перезапустить цикл в C ++ (поиск уникальной последовательности в случайном порядке)
Вопрос
Следующие коды пытаются сгенерировать случайные строки на 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;
}
Решение
Ваш код на первый взгляд выглядит хорошо, если я не пропущу большую часть ваших требований.
Прочтите эту перед использованием 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
, и выходит из области видимости при закрывающем }
Цикл для
. Таким образом, он не будет увеличен, чтобы функционировать как надлежащая проверка на наличие дубликатов. В идеале вы должны использовать std :: set
и продолжать вставлять в него. Дубликаты не допускаются, и вы избавлены от многих неприятностей.
Подробнее об использовании rand ()
srand ()
и генерации случайных чисел:
Из FAQ по comp.lang.c:
[...] младшие биты многих генераторов случайных чисел являются крайне неслучайными
Если вы хотите, чтобы ваши случайные числа находились в диапазоне
[0, 1, ... N - 1]
лучший способ по сравнению с простым rand ()% N
(как указано в ссылке) заключается в использовании следующего:
(int)((double)rand() / ((double)RAND_MAX + 1) * N)
Теперь, если вы запустите свою программу, каждый раз вы будете получать один и тот же набор из 10000 нечетных случайных цепей ДНК. Оказывается, это потому, что:
Для большинства генераторов псевдослучайных чисел (и определенного свойства rand библиотеки C) характерно, что они всегда начинаются с одного и того же числа и проходят одну и ту же последовательность. Р>
из другого часто задаваемых вопросов 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;
}
Другие советы
Ваш алгоритм фальшивый. Что бы вы ни пытались сделать, вы этого не делаете, и поскольку там нет ни одного комментария, я не могу точно сказать, где вы ошиблись.
Ваш внутренний цикл:
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.
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 ()
отсутствует обратная косая черта, так как я не мог понять, как сделать так, чтобы текстовый редактор позволял мне печатать один. :) Р>
Вы поняли, что 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;
}
Как уже говорили другие, с этим кодом сложно понять, что вы хотели сделать. Не могли бы вы сказать нам, пожалуйста, как вы имеете в виду «совершенно другой»? например?
Ответ dirkgentlys довольно исчерпывающий для того, что я пытался сказать сейчас.
Я хотел бы порекомендовать вам не использовать continue, поскольку большинство стандартов кодирования рекомендуют не использовать continue по уважительной причине, поскольку это усложняет контроль за потоком.