我试图在递归算法中找到列表的总和
我正在学习递归算法,我知道我可以用另一种方式做到但我正在学习
这是我的代码(非常简单)
class SumList
{
public SumList(int[] list ) {
List<int> listInteger = new List<int>();
for (int i = 0; i < list.Length; i++)
listInteger.Add(list[i]);
sum(listInteger);
}
private double sum(List<int> list) {
if (list.Count == 1)
{
return list[0];
}
if(list.Count ==2)
{
Console.Write(printList(list));
Console.WriteLine((list[0] + list[1]));
return list[0] + list[1];
}
double last = list[list.Count - 1];
List<int> backupList = new List<int>(list);
list.RemoveAt(list.Count -1);
double s = last + sum(list);
Console.Write(printList(backupList));
Console.WriteLine(s);
return s;
}
private string printList(List<int> list)
{
string result = "";
for (int i = 0; i < list.Count; i++)
{
result += list[i];
if (i != list.Count - 1)
{
result +="+ ";
}
else
{
result+= " = ";
}
}
return result;
}
}
这就是这样称呼的:
int []listInt = new int[] { 4, 5, 6, 7, 9 , 10 };
new SumList(listInt);
Console.ReadLine();
我的问题是结果是:
我想得到结果但是像这样:
4 + 5 + 6 + 7 = ...
4 + 5 + 6 = ...
所以结果应该向后打印
我再次知道有很多方法可以找到列表的总和,但我正在尝试学习递归算法
答案 0 :(得分:2)
您可能知道,递归函数是一个调用自身的函数。这意味着为了递归地解决问题,我们必须将问题分成步骤,使得程序不会在步骤之间改变,但是函数的输入将改变。此外,如果我们的递归函数永远正确终止,问题必须得到更小的&#34;我们采取的每一步。此步骤表示一个递归单位。此外,与&#34; normal&#34;不同。迭代,我们提前知道什么时候才能到达问题的最后。因此,我们需要一种机制来确定何时到达问题的最后并且应该停止递归。这称为基本情况。
让我们尝试找一个列表总和的例子。
我们必须做的第一件事是提出一个递归单位(一个抽象的步骤,我们可以一遍又一遍地重复,直到我们找到解决方案)。
我们知道输入类型为List<int>
在这种情况下,我们可以注意到(此处为伪代码)sum(list) == list[0] + sum(restOfList)
。请注意,现在我们有一个确定的值(list[0]
)和一个List<int>
类型的对象(即restOfList
)。
所以,现在我们有一个整洁,可重复的程序。
//Idk what language you are using, or if it matters, but I am writing this in java
public int sum(List<Integer> list) {
//still need a base case
return list.get(0) + sum(list.subList(1, list.size()));
}
现在我们只需确定基本情况。所以我们需要确定何时我们将完成列表的所有元素。
为此,让我们通过几个步骤来看看会发生什么。让我们从以下列表开始:{1, 2, 3, 4}
sum({1, 2, 3, 4})
-> 1 + sum({2, 3, 4})
-> 2 + sum({3, 4})
-> 3 + sum({4})
-> 4 + oops!!!
显然,我们无法从大小为1的列表中获取从索引1开始的子列表。这为我们的基本情况提供了答案。
public int sum(List<Integer> list) {
printList(list);
//base case
if (list.size() == 1)
return list.get(0); //recall that this is the entire list
//otherwise, continue to next step.
return list.get(0) + sum(list.subList(1, list.size()));
}
添加有效,因为第一步的return语句取决于第二步的return语句,依此类推。这也是步骤以相反顺序打印的原因。
为了清楚起见,让我们最后一次追踪它。
sum({1, 2, 3, 4}) //sum({1, 2, 3, 4}) is called from main()
-> 1 + sum({2, 3, 4}) //sum({2, 3, 4}) is called from sum({1, 2, 3, 4})
-> 2 + sum({3, 4}) //sum({3, 4}) is called from sum({2, 3, 4})
-> 3 + sum({4}) //sum({4}) is called from sum({3, 4})
<- 4 //sum({4}) returns 4 to sum({3, 4})
3 + 4
<- 7 //sum({3, 4}) returns 7 to sum({2, 3, 4})
2 + 7
<- 9 //sum({2, 3, 4}) returns 9 to sum({1, 2, 3, 4})
1 + 9
<- 10 //sum({1, 2, 3, 4}) returns 10
我希望这有助于使事情变得更加清晰。
答案 1 :(得分:2)
或试试这个
public static int Sum(List<int> listOfInt)
{
if (listOfInt.Count == 1)
{
return Convert.ToInt32(listOfInt[0]);
}
else
{
return Convert.ToInt32(listOfInt[0]) + Sum(listOfInt.Skip(1).ToList());
}
}
答案 2 :(得分:1)
嗯,这不是我怎么做的,它肯定有很多奇怪之处。但是,如果我试图保留你的设计背后的精神,那么我认为实现这一目标的一个好方法是在StringBuilder
中缓冲输出,并使用其Insert(0, str)
方法将线放在右边的地方。
public SumList(int[] list)
{
List<int> listInteger = new List<int>();
for (int i = 0; i < list.Length; i++)
listInteger.Add(list[i]);
StringBuilder output = new StringBuilder();
sum(listInteger, output);
Console.WriteLine(output.ToString());
}
private double sum(List<int> list, StringBuilder output)
{
if (list.Count == 1)
{
return list[0];
}
if (list.Count == 2)
{
output.Append(printList(list));
output.Append((list[0] + list[1])).Append(Environment.NewLine);
return list[0] + list[1];
}
double last = list[list.Count - 1];
List<int> backupList = new List<int>(list);
list.RemoveAt(list.Count - 1);
double s = last + sum(list, output);
output.Insert(0, Environment.NewLine);
output.Insert(0, s);
output.Insert(0, printList(backupList));
return s;
}
private string printList(List<int> list)
{
string result = "";
for (int i = 0; i < list.Count; i++)
{
result += list[i];
if (i != list.Count - 1)
{
result += " + ";
}
else
{
result += " = ";
}
}
return result;
}
答案 3 :(得分:0)
您的代码通过计算所有列表的总和(并逐渐减少列表)然后向后打印它们来工作,这解释了为什么您看到的列表的大小正在增加。修复此问题的方法是修复递归。为了让它们按递减顺序打印,您希望递归按顺序递增。那么,计算sum(List.subList(1)),然后求和(List.subList(2)),依此类推......
另一种快速解决方法是将输出保存为数组中的字符串,然后向后打印数组。
答案 4 :(得分:0)
一种可能的解决方案是
List<int> listInteger = new List<int> ();
public SumList (int[] list)
{
for (int i = 0; i < list.Length; i++)
listInteger.Add (list [i]);
listInteger.Reverse();
}
private void sumR (List<int> list, int index)
{
int sigma = 0;
if (list.Count - 1 == index) {
return;// sigma + list [index];
} else {
for (int i = list.Count-1; i>=index; i--) {
sigma += list [i];
if (i == list.Count - 1)
Console.Write ("{0} ", list [i]);
else
Console.Write ("+ {0} ", list [i]);
}
Console.WriteLine ("= {0}", sigma);
sumR (list, index + 1);
}
}
public void doSum(){
sumR(listInteger, 0);
}
不需要其他方法,但如果您愿意,可以从构造函数中调用sumR。测试是
int [] listInt = new int[] { 4, 5, 6, 7, 9 , 10 };
SumList sl = new SumList (listInt);
sl.doSum();
Console.ReadLine ();
输出是:
4 + 5 + 6 + 7 + 9 + 10 = 41
4 + 5 + 6 + 7 + 9 = 31
4 + 5 + 6 + 7 = 22
4 + 5 + 6 = 15
4 + 5 = 9
答案 5 :(得分:0)
递归函数:
public static void PrintSum(int[] list)
{
// Define the end of the recursion
if (list.Count() > 2)
// Copy the shorter list to PrintSum()
PrintSum(list.Take(list.Count() - 1).ToArray());
// Print the result of list AFTER shorter list is done
System.Diagnostics.Debug.WriteLine(
string.Format("{0} = {1}", string.Join("+ ", list),
list.Sum()));
}
public static void PrintSumReverse(int[] list)
{
// Print the result of list
System.Diagnostics.Debug.WriteLine(
string.Format("{0} = {1}", string.Join("+ ", list),
list.Sum()));
// Define the end of the recursion
if (list.Count() > 2)
// Copy the shorter list to PrintSum()
PrintSum(list.Take(list.Count() - 1).ToArray());
}
用法:
var listInt = new int[] { 4, 5, 6, 7, 9, 10 };
PrintSum(listInt);
/* Result:
4+ 5 = 9
4+ 5+ 6 = 15
4+ 5+ 6+ 7 = 22
4+ 5+ 6+ 7+ 9 = 31
4+ 5+ 6+ 7+ 9+ 10 = 41
*/
PrintSumReverse(listInt);
/* Result
4+ 5+ 6+ 7+ 9+ 10 = 41
4+ 5+ 6+ 7+ 9 = 31
4+ 5+ 6+ 7 = 22
4+ 5+ 6 = 15
4+ 5 = 9
*/