我正在尝试编写一个程序来识别给定N个数组中3个连续整数的出现,并用中间值替换它们,删除其他两个。 例如输入 - > 55 99 99 100 101 101 34 35 36 5 28 7 50 50 51 52 52 24 13 14 15 5 6 7 37 31 37 38 39 36 40 输出 - > 55 100 35 5 28 7 51 24 14 6 37 31 38 36 40
为了实现这一点,我写了这个方法,它接受数组作为输入,并返回修改后的数组。
//input
int[] original = new int[] { 1, 3, 4, 5, 5, 6, 8} ;
List<int> lstoriginal = new List<int>(original);
List<int> modified = Test(lstoriginal);
//method
public static List<int> Test(List<int> arrayInput)
{
for (i = 0; i < arrayInput.Count; i++)
{
if (i + 2 < arrayInput.Count)
{
if (arrayInput[i + 2] == arrayInput[i + 1] + 1
&& arrayInput[i + 2] == arrayInput[i] + 2)
{
arrayInput.RemoveAt(i + 2);
arrayInput.RemoveAt(i);
List<int> temp = arrayInput;
Test(temp);
}
}
}
return arrayInput;
}
Follwoing是我分析的执行步骤/结果 -
1 - 最初如果测试输入是1,3,4,5,5,6,8
2 - 当i = 1且它发现3,4,5顺序时它会删除3和5并且列表变为1,4,5,6,8
3 - 下一次当i = 1然后它找到4,5,6并且它移除4和6并且新列表是1,5,8
4-i我希望在i + 2&lt; arrayInput.Count返回false并尝试立即重新执行修改后的数组,返回语句执行但不返回结果,它再次调用Test(temp);声明几次然后退出。请建议
答案 0 :(得分:0)
请定义“无法退出”。你是说for for无限循环?我不认为这个代码发生了这种情况。
对我来说是什么样的:
此功能将: 逐步执行输入,int by int。检查此int和接下来的2是否是顺序的。然后它删除这个和下一个之后的那个,然后将结果反馈到同一个函数中。然后它忽略了这可能给我们带来的任何价值,并继续以其快乐的方式。
您的输入为8,9,10 它开始逐步完成:i = 0和所有这一切。 所以它发现8,9,10是顺序的,然后删除8和9并将结果输入到同一个函数中。
所以我们重新开始:
您的输入为9 它开始逐步通过:i = 0再次。 它逐步执行并发现列表中至少有3个值,并返回原始值。
然后我们完全忽略该结果并继续上面的原始循环。现在i = 1,但是在arrayInput中只有一件事,所以它应该结束。
从你正在做的事情来看,我认为没有理由进行递归通话。你没有对结果做任何事情,即使你是,如果你有一个像8,9,10,10,11这样的集合,它只会对你有帮助。然后第一个调用会将其减少到9,10,11,递归调用会将其减少到10
答案 1 :(得分:0)
你实际上根本不需要递归。您可以在删除序列后移动i
,从而显着加快执行任务的速度。这是一个更简单的功能,完全相同。我在数以万计的随机生成的无序序列上测试了它。
public static List<int> Test2(List<int> arrayInput)
{
for (int i = 0; i < arrayInput.Count - 2; i++)
{
if (arrayInput[i + 2] == arrayInput[i + 1] + 1
&& arrayInput[i + 2] == arrayInput[i] + 2)
{
arrayInput.RemoveAt(i + 2);
arrayInput.RemoveAt(i);
i = Math.Max(-1, i - 3); // -1 'cause i++ in loop will increment it
}
}
return arrayInput;
}
也就是说,要回答您的具体问题,退出递归循环的最佳方法就是更改递归函数的签名以返回bool
,指示它是否实际进行了任何更改。当第一个返回时没有任何更改,它们都可以存在,因此您对Test
的调用可以包含在if (!Test(...)) { return; }
中。
以下是将原始版本与修改版本进行比较的完整测试和测试数据:
public static void Main()
{
const int COUNT = 10000;
var r = new Random();
int matchCount = 0;
var stopwatch1 = new Stopwatch();
var stopwatch2 = new Stopwatch();
for (int j = 0; j < COUNT; j++)
{
var list = new List<int>(100) {1};
for(int k=1; k<100; k++)
{
switch(r.Next(5))
{
case 0:
case 1:
case 2:
list.Add(list[k - 1] + 1);
break;
case 3:
list.Add(list[k - 1] + r.Next(2));
break;
case 4:
list.Add(list[k - 1] - r.Next(5));
break;
}
}
stopwatch1.Start();
List<int> copy1 = Test1(new List<int>(list));
stopwatch1.Stop();
stopwatch2.Start();
List<int> copy2 = Test2(new List<int>(list));
stopwatch2.Stop();
string list1 = String.Join(",", copy1);
string list2 = String.Join(",", copy2);
if (list1 == list2)
{
if (copy1.Count == list.Count)
{
Console.WriteLine("No change:" + list1);
}
else
{
matchCount++;
}
}
else
{
Console.WriteLine("MISMATCH:");
Console.WriteLine(" Orig : " + String.Join(",", list));
Console.WriteLine(" Test1 : " + list1);
Console.WriteLine(" Test2 : " + list2);
}
}
Console.WriteLine("Matches: " + matchCount);
Console.WriteLine("Elapsed 1: {0:#,##0} ms", stopwatch1.ElapsedMilliseconds);
Console.WriteLine("Elapsed 2: {0:#,##0} ms", stopwatch2.ElapsedMilliseconds);
}
public static List<int> Test1(List<int> arrayInput)
{
for (int i = 0; i < arrayInput.Count; i++)
{
if (i + 2 < arrayInput.Count)
{
if (arrayInput[i + 2] == arrayInput[i + 1] + 1
&& arrayInput[i + 2] == arrayInput[i] + 2)
{
arrayInput.RemoveAt(i + 2);
arrayInput.RemoveAt(i);
List<int> temp = arrayInput;
Test1(temp);
}
}
else
{ // modified part: return the array
return arrayInput;
}
}
return arrayInput;
}
//method
public static List<int> Test2(List<int> arrayInput)
{
for (int i = 0; i < arrayInput.Count - 2; i++)
{
if (arrayInput[i + 2] == arrayInput[i + 1] + 1
&& arrayInput[i + 2] == arrayInput[i] + 2)
{
arrayInput.RemoveAt(i + 2);
arrayInput.RemoveAt(i);
i = Math.Max(-1, i - 3); // -1 'cause i++ in loop will increment it
}
}
return arrayInput;
}