2013-05-08 118 views
-2

我創建一個隨機數,然後檢查它是否存在於數據庫表中。如果是這樣,我生成另一個並再次檢查,下面的工作也會如此嗎?遞歸檢查數據庫中的重複隨機數

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)中?

+0

我投票決定關閉這個問題,以幫助凡要關閉它。 – Xaisoft 2013-05-09 18:25:48

回答

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

所以我們擺脫了堆棧溢出,現在只需要考慮非確定性運行時間和競爭條件。進展! – Jon 2013-05-08 21:32:05

+0

檢查我的編輯:) – christopher 2013-05-08 21:32:57

+0

@ChrisCooney - 謝謝,它實際上是100,000,000。 – Xaisoft 2013-05-08 21:37:52

0

這可能會導致非常糟糕的表現。使用,例如,Guid,爲此

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

@SamIam事情告訴我,我正在指導正確的路徑。 – I4V 2013-05-08 21:30:19

+1

我無法使用GUID。它的編號傳遞給一個使用8個字符長的字符串的外部系統,否則我會使用GUID。 – Xaisoft 2013-05-08 21:36:41

+0

@Xaisoft那麼你應該設計一個很好的算法,因爲創建一個以前沒有生成的隨機數(通過查找)可以在理論上無限延續(?)。那麼你最好的選擇是使用*序列*。無論你喜不喜歡,所有其他答案都是不可接受的(至少是我) – I4V 2013-05-08 22:02:38

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; 
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); 
} 
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; 
} 
+0

我會試一試謝謝。 – Xaisoft 2013-05-08 21:39:06

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; 
} 
6

有很多問題,在這裏你的方法已經由其他人解決,所以不是我來回答你一個問題應該問,但沒有:

問題爲了正確使用遞歸有什麼特點?

  • 有問題的「瑣碎」的版本,可以總是無遞歸來解決:除非您的解決方案表現出以下所有特性

不得使用遞歸

  • 每個不平凡的問題可以減少到一個或多個嚴格小於的問題。
  • 將問題反覆減少到更小的問題最終會導致嘗試解決一個小問題,在經過少量步驟後,我們的意思是「小」,即幾百步,而不是幾百萬步。 (這種情況可以在「尾遞歸」語言中放鬆; 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; 
    } 
    
    +1

    OP的遞歸模式在尾遞歸語言中可能很好,甚至可能在某些函數式語言中慣用。 – CodesInChaos 2013-05-08 22:14:16

    +0

    人們甚至可以爭辯說,這個問題符合你提到的所有條件。 1)平凡的版本是沒有檢測到重複的情況2)只要平均值*小於*,問題不需要嚴格小於*,如果最大數量大於表格大小。 3)達到某個遞歸深度的機會呈指數下降。如果最大值大於表格大小,則不會達到高值。 4)平凡|我不會認爲這是C#中的一個很好的解決方案,但它並不像你顯示的那樣糟糕。 – CodesInChaos 2013-05-08 22:17:48

    +0

    @CodesInChaos,OP的問題不能保證終止。如果他的範圍是1000(或100,000,000)個整數,並且他們中的每一個都被使用,那麼他將只是繼續無限地緩存直到時間結束,如果這樣的事情是可能的話。 – 2013-05-08 22:18:42