-2

乱数を作成し、それがデータベース テーブルに存在するかどうかを確認します。もしそうなら、私は別のものを生成してもう一度チェックします。

public int GenerateNumber()
{
    Random r = new Random();
    int num = r.Next(1000);

    //Psuedo-code
    if(num is in table)
        GenerateNumber();

    return num;
}

以下の回答に基づいて、ここでは再帰を避ける必要があり、数値を自動インクリメントする必要があるため、自動インクリメントを 1 から開始し、8 文字になるまで 0 でパディングすることをお勧めします。 10,000,000。

また、データ型が varchar(8) でなければならない場合はどうでしょう。数値を自動インクリメントして varchar(8) に格納するにはどうすればよいですか?

4

7 に答える 7

6

ここでのアプローチには、他の人が対処した多くの問題があるため、代わりに、あなたが尋ねるべきでしたが、しなかった質問に答えます。

再帰を正しく使用するために問題に必要な特性は何ですか?

ソリューションが次のすべての特性を示さない限り、再帰を使用しないでください。

  • 再帰なしで常に解決できる問題の「簡単な」バージョンがあります。
  • すべての重要な問題は、1 つまたは複数の厳密に小さな問題に縮小できます。
  • 問題をより小さな問題に繰り返し縮小すると、最終的には小さな問題を解決しようとする結果になります。つまり、「小さい」とは、たとえば、数百万ではなく数百のステップを意味する少数のステップの後です。(この条件は、「末尾再帰」言語では緩和できます。C# は末尾再帰言語ではありません。)
  • 小さい問題の解決策は、より大きな問題の解決策に効率的に組み合わせることができます。

あなたのサンプル コードは、これらの特徴をまったく示していません。再帰を使用するには、これらすべての特性を示す必要があるため、いかなる状況でも再帰を使用しないでください

再帰によってうまく解決される問題の例を挙げましょう。

ツリーは空であるか、左右のサブツリーで構成されています。ツリーにループが含まれることはありません。空の木の高さはゼロです。空でないツリーの高さは、ルートから「最も深い」空のサブツリーまでの最長パスの長さです。高さが 200 未満であると仮定して、木の高さを決定するメソッドを作成します。

この問題は、再帰で解決できる問題のすべての特徴を示しているため、再帰を実行できます。すべての再帰プログラムには次のパターンがあります。

  • できれば簡単な問題を解いてください。
  • それ以外の場合は、問題を小さな問題に分割し、それらを再帰的に解き、解を構成します。

それでは、それをしましょう:

int Height(Tree tree)
{
    // Trivial case:
    if (tree.IsEmpty) return 0;
    // Non-trivial case: reduce the problem to two smaller problems:
    int leftHeight = Height(tree.Left);
    int rightHeight = Height(tree.Right);
    int height = Math.Max(leftHeight, rightHeight) + 1;
    return height;
}
于 2013-05-08T22:04:27.360 に答える
5

これは、再帰によって解決する必要がある問題ではありません。データベースにかなりの数があり、これが何度もループする場合、スタックオーバーフローエラーがすぐに発生するという事実は言うまでもありません。反復関数に変更しないでください:

public int GenerateNumber()
{
    Random r = new Randon();
    int num = r.Next(1000);

    while(num is in database)
    {
        num = r.Next(1000);
    }

    return num;
}

別のアプローチ、私がここにいる間

これらの値の間に推移的な違いを実装しないのはなぜですか? つまり、最初の数字は 1 で、次に 2 などです。次に、最新のエントリを取得して、それに 1 を追加するだけです。一貫してデータベース クエリを実行し続ける必要はありません。

于 2013-05-08T21:29:24.793 に答える
0

これにより、パフォーマンスが非常に低下する可能性があります。これには、たとえば Guid を使用します

var rand = Guid.NewGuid().ToString()
于 2013-05-08T21:28:52.293 に答える
0

そうではありません。

if (num is in table)
  return GenerateNumber();
else
  return num;

動作しますが、ループする方が簡単/安全です:

int num;

do
{
   num = r.Next(1000);
} while (num is in table);

return num;
于 2013-05-08T21:31:05.387 に答える
0

いいえ、そうではありません。GenerateNumber を再度呼び出して取得した番号を取得する必要があります。

public int GenerateNumber()
{
    Random r = new Randon();
    int num = r.Next(1000);

    //Psuedo-code
    if(num is in table)
     num = GenerateNumber(); //num = added.

    return num;
}

これを再帰的に解決する必要はありません。C# では、C# は他の言語のように末尾の最適化を行わないため、お勧めできません (コンパイル中に再帰呼び出しを反復呼び出しに変更しません)。時間)。これは機能しますが、スタックで余分な作業を行うと、スタック オーバーフロー エラーが発生する可能性があります。ただし、あなたが尋ねたので、これがコードを修正して機能させる方法です。

次のようにして、再帰を使用しないように簡単に変更できます。

while(num is in table){ //I always use brackets to be clear.
   num = r.Next(1000);
}
于 2013-05-08T21:31:53.417 に答える
0

テーブルが十分なサイズの場合に必然的に発生する StackOverFlow 例外によるクラッシュを回避するには、反復を使用します。

public int GenerateNumber()
{
    bool match = false;

    while (!match) {
        Random r = new Randon();
        int num = r.Next(1000);

    //Psuedo-code
    if(num is not in table)
        //insert
    }

    return num;
}
于 2013-05-08T21:33:16.497 に答える
0

データベースが何であるかを指定しません。使用された数字の単なるメモリ内リストである場合、コードは次のように簡単に実行できます。

private HashSet<int> _usedNumbers = new HashSet<int>();
Random r = new Random(); //Search "Random is not random" on SO to see why I moved this out here.

public int GenerateNumber()
{
    int MaxNum = 1000;

    int num = r.Next(MaxNum);

    if(_usedNumbers.Count == MaxNum)
       throw new Exception("I ran out of numbers :(");

    while(_usedNumbers.Add(num) == false) //Add will return false if the number already was used.
    {
       num = r.Next(MaxNum );
    }

    return num;
}
于 2013-05-08T21:35:17.047 に答える