C ++でループを再起動する方法(ランダムに実行される一意のシーケンスを見つける)
質問
次のコードは、K回の実行でランダム文字列を生成しようとします。 しかし、新しく生成された文字列はまったく異なるものにしたい 参照文字列とともに。
そのために" continue"を使用しようとしました。ランダムを再起動するには 文字列生成プロセス。しかし、うまくいかないようです。 以下のアプローチの何が問題になっていますか?
#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
への新しいエントリを作成するたびに初期化され、}
の終了時に範囲外になります for
ループ。そのため、重複生成に対する適切なチェックとして機能するようにインクリメントされません。理想的には、 std :: set
を使用し、挿入し続ける必要があります。重複は許可されず、多くのトラブルから救われます。
rand()
srand()
および乱数生成の使用に関する詳細:
comp.lang.c FAQから:
[...]多くの乱数ジェネレーターの下位ビットは、悲惨なほど非ランダムです
範囲内に乱数を保持する場合
[0, 1, ... N - 1]
単純な rand()%N
(リンクで推奨)よりも優れた方法は、以下を使用することです:
(int)((double)rand() / ((double)RAND_MAX + 1) * N)
今、プログラムを実行する場合、毎回10000の奇数のランダムなDNA鎖の同じセットを取得します。理由は次のとおりです。
ほとんどの擬似乱数ジェネレーター(およびCライブラリrandの定義済みプロパティ)の特徴は、常に同じ番号で始まり、同じシーケンスを実行することです。
comp.lang.cの別の FAQ から
複数の実行にわたって異なるストランドを取得するには、次を試してください:
#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
それに追加して、&quot; newString&quot;文字列ではありませんが、文字列のベクトルです。
だから、あなたの問題は 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を使用することをお勧めします。