2017-01-16 87 views
2

我想生成所有具有長度n和我的電話號碼的每個數字具有與集{1,2,...,n-1}的值,作爲數組的可能數目。換句話說,我想列出長度爲n的所有基數n,其中不包括0創建所有可能的陣列而不嵌套for循環

現在,我可以認爲通過嵌套Ñfor環路,以及分配myArray[i]與第(i + 1)個循環來做到這一點是唯一的方法,也就是

int n; 
int[] myArray = new int[n]; 
for (int i1 = 1; i1 < n; i1++) 
    myArray[0]=i1; 
    for (int i2 = 1; i2 < n; i2++) 
     myArray[1]=i2; 
     // and so on.... 
      for (int in = 1; in < n; in++) 
      { 
       myArray[n]=in; 
       foreach (var item in myArray) 
        Console.Write(item.ToString()); 
        Console.Write(Environment.NewLine); 
      } 

,然後打印每個陣列在最內層的循環。顯而易見的問題是,對於每個n,我需要手動編寫nfor循環。

從我讀過的,遞歸似乎是取代嵌套for循環的最好方法,但我似乎無法弄清楚如何製作遞歸的一般方法。

編輯

例如,如果n=3,我想寫出1 1 11 1 21 2 11 2 22 1 12 1 22 2 12 2 2

我們不限於n<11。例如,如果n=11,我們將輸出

1 1 1 1 1 1 1 1 1 1 1 
1 1 1 1 1 1 1 1 1 1 2 
1 1 1 1 1 1 1 1 1 1 3 
... 
1 1 1 1 1 1 1 1 1 1 10 
1 1 1 1 1 1 1 1 1 2 1 
1 1 1 1 1 1 1 1 1 2 2 
1 1 1 1 1 1 1 1 1 2 3 
... 
1 1 1 1 1 1 1 1 1 9 10 
1 1 1 1 1 1 1 1 1 10 1 
1 1 1 1 1 1 1 1 1 10 2 
1 1 1 1 1 1 1 1 1 10 3 
... 
10 10 10 10 10 10 10 10 10 9 10 
10 10 10 10 10 10 10 10 10 10 1 
10 10 10 10 10 10 10 10 10 10 2 
... 
10 10 10 10 10 10 10 10 10 10 10 

因此,一個數的數字可以是介於幷包括110任何值。數組myArray只是用來獲得這些數字之一,然後我們打印它,然後繼續下一個數字並重復。

+0

您在代碼中有一個問題是,你使用'N'元素(用於存儲你正在尋找所有可能的值,我假設)的陣列,但數量你需要找到價值要高得多(在'n的命令!'或'(N-1)*(N-1)',如果我理解你的問題) –

+0

你能澄清你的問題一點?預期的投入和產出?你的代碼根據你所說的問題可以想出任何我能想到的解釋,但你所說的問題並不完全清楚。 –

+0

我猜'n'最多可以是'10',否則我不確定*一個數字如何具有該集合的值。 – InBetween

回答

3

像往常一樣,在遞歸解決方案的思維時,請嘗試使用一成不變的結構來解決這個問題;一切都很容易理解。所以首先,讓我們建立一個快速的小不變的堆棧,這將幫助我們跟蹤我們當前生成的數量(同時不用擔心在遞歸調用中生成的其他數字......記住,不可變的數據不能改變!):

public class ImmutableStack<T>: IEnumerable<T> 
{ 
    public static readonly ImmutableStack<T> Empty = new ImmutableStack<T>(); 
    private readonly T first; 
    private readonly ImmutableStack<T> rest; 

    public int Count { get; } 

    private ImmutableStack() 
    { 
     Count = 0; 
    } 

    private ImmutableStack(T first, ImmutableStack<T> rest) 
    { 
     Debug.Assert(rest != null); 

     this.first = first; 
     this.rest = rest; 
     Count = rest.Count + 1; 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     var current = this; 

     while (current != Empty) 
     { 
      yield return current.first; 
      current = current.rest; 
     } 
    } 

    public T Peek() 
    { 
     if (this == Empty) 
      throw new InvalidOperationException("Can not peek an empty stack."); 

     return first; 
    } 

    public ImmutableStack<T> Pop() 
    { 
     if (this == Empty) 
      throw new InvalidOperationException("Can not pop an empty stack."); 

     return rest; 
    } 

    public ImmutableStack<T> Push(T item) => new ImmutableStack<T>(item, this); 

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 
} 

這很簡單。注意堆棧如何重用數據。我們的小程序中會有多少空的不可改變的結構?只有一個。和包含序列1->2->4的堆棧?是的,只有一個。現在

,我們實現遞歸函數,只是不斷增加的數字堆棧,直到我們達到我們的「拯救」的條件。哪個?當堆棧包含n元素時。易peasy:

private static IEnumerable<int> generateNumbers(ImmutableStack<string> digits, IEnumerable<string> set, int length) 
{ 
    if (digits.Count == length) 
    { 
     yield return int.Parse(string.Concat(digits)); 
    } 
    else 
    { 
     foreach (var digit in set) 
     { 
      var newDigits = digits.Push(digit); 

      foreach (var newNumber in generateNumbers(newDigits, set, length)) 
      { 
       yield return newNumber; 
      } 
     } 
    } 
} 

好了,現在我們只需要與我們的公共方法產品總數比分扳成:

public static IEnumerable<int> GenerateNumbers(int length) 
{ 
    if (length < 1) 
     throw new ArgumentOutOfRangeException(nameof(length)); 

    return generateNumbers(ImmutableStack<string>.Empty, 
          Enumerable.Range(1, length - 1).Select(d => d.ToString(CultureInfo.InvariantCulture)), 
          length); 
} 

果然,如果我們把這個事情:

var ns = GenerateNumbers(3); 
Console.WriteLine(string.Join(Environment.NewLine, 
           ns.Select((n, index) => $"[{index + 1}]\t: {n}"))); 

我們得到預期產出:

[1]  : 111 
[2]  : 211 
[3]  : 121 
[4]  : 221 
[5]  : 112 
[6]  : 212 
[7]  : 122 
[8]  : 222 

待辦事項注意號碼的一個指定長度n所產生的總金額爲(n - 1)^n這意味着對於length值相對較小,你會得到生成的數字相當量; n = 10產生3 486 784 401 ...