递归检查数据库中的重复随机数

时间:2013-05-08 21:26:53

标签: c#

我创建一个随机数,然后检查它是否存在于数据库表中。如果确实如此,我会生成另一个并再次检查,以下工作会如何?

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

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

    return num;
}

似乎基于下面的答案,这里应该避免递归,我应该自动增加数字,所以一个好的选择是开始自动增量为1,填充为0,直到长度为8个字符或者以10,000,000开始。

此外,如果数据类型必须是varchar(8),该怎么办?如何自动递增数字,但是将其存储在varchar(8)中?

7 个答案:

答案 0 :(得分:6)

你的方法存在很多问题已被其他人解决,所以相反我会回答你应该问的问题,但不会:

  

为了正确使用递归,问题必须具备哪些特征?

不得使用递归,除非您的解决方案展示所有以下特征:

  • 问题的“琐碎”版本可以始终在没有递归的情况下解决。
  • 每个非平凡问题都可以减少到一个或多个严格较小的问题。
  • 在一个小步骤之后,反复将问题减少到一个较小的问题最终会导致尝试解决一个小问题,其中“小”是指几百步,而不是几百万步。 (这种情况可以在“尾递归”语言中放宽; C#不是尾部重复语言。)
  • 小问题的解决方案总能有效地结合到解决更大问题的解决方案中。

您的示例代码展示了 none 这些特征;使用递归要求您展示所有这些特征,所以在任何情况下都不应该使用递归

让我举一个例子,通过递归很好地解决 的问题:

  

树是空的或由左右子树组成;树永远不会包含循环。空树的高度为零;非空树的高度是从根到“最深”空子树的最长路径的长度。编写一个确定树高的方法,假设高度小于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;
}

答案 1 :(得分:5)

这不是需要通过递归解决的问题。更不用说如果你的数据库中有一些数字很多,而且循环很多次,你很快就会出现堆栈溢出错误。为什么不将其更改为迭代函数:

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

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

    return num;
}

一种不同的方法,而我在这里

为什么不在这些值之间实现一些传递差异?即:第一个数字是一个,然后是两个等等。然后您需要做的就是获取最新的条目,然后添加一个。无需持续不断地进行数据库查询。

答案 2 :(得分:0)

这可能会导致非常糟糕的表现。使用,例如,Guid,用于此

var rand = Guid.NewGuid().ToString()

答案 3 :(得分: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;

答案 4 :(得分: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);
}

答案 5 :(得分: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;
}

答案 6 :(得分: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;
}