C ++でループを再起動する方法(ランダムに実行される一意のシーケンスを見つける)

StackOverflow https://stackoverflow.com/questions/614012

  •  03-07-2019
  •  | 
  •  

質問

次のコードは、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を使用することをお勧めします。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top