正确的方法退出递归循环

时间:2011-07-15 03:08:59

标签: c# .net loops

我正在尝试编写一个程序来识别给定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);声明几次然后退出。请建议

2 个答案:

答案 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;
}