2017-01-16 62 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 ...