我想生成长度为fp2 = fopen(tmp, "w");
的所有可能数字,并且我的数字的每个数字都具有集合n
中的值,作为数组。换句话说,我想列出所有不包含{1,2,...,n-1}
的{{1}}基数n
。
现在,我能想到的唯一方法就是嵌套n n
个循环,并将0
分配给第(i + 1)个循环,即
for
然后在最里面的循环中打印每个数组。显而易见的问题是,对于每个n,我需要手动编写myArray[i]
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
循环的最佳方法,但我似乎无法弄清楚如何为递归制作一般方法。
修改
例如,如果for
,我想写出for
,n=3
,1 1 1
,1 1 2
,1 2 1
,{ {1}},1 2 2
,2 1 1
。
我们不仅限于2 1 2
。例如,如果2 2 1
,我们会输出
2 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
只是用于获取其中一个数字,然后我们打印它,然后继续下一个数字并重复。
答案 0 :(得分: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
个元素时。容易腻:
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 ...