c#递归步法

时间:2016-04-19 19:18:49

标签: c# arrays recursion

我尝试使用递归方法检查整数数组中的最后一个数字(总是0)(所有> 0整数)是否可通过增加(或减少)数组的索引来访问当前索引的数组元素的值,同时保持在数组的范围内。

示例:

说我们有以下数组,并且起始索引== 0:

int[] arr = {3, 6, 4, 1, 3, 4, 2, 5, 3, 0};
  

步骤0:index = 0,value = 3

     

步骤1:index = 3,value = 1

     

第2步:index = 4,value = 3

     

步骤3:index = 7,value = 5

     

步骤4:index = 2,value = 4

     

步骤5:index = 6,value = 2

     

步骤6:index = 8,value = 3

     

步骤7:index = 5,value = 4

     

步骤8:index = 9,value = 0 - end

我目前的代码:

        static bool Solveable(int index, int[] arr)
        {
            if (arr[index] == 0)
                return true;
            if (index + arr[index] < arr.Length)
                return Solveable(index + arr[index], arr);
            if (index - arr[index] >= 0)
                return Solveable(index - arr[index], arr);

            return false;
        }

这个问题是它只适用于可解决的情况,所有其他情况都会导致stackoverflow异常。

如何在不使用全局变量存储以前的结果的情况下解决这个问题?

编辑:

我只能使用参数:(int index,int [] arr)

5 个答案:

答案 0 :(得分:2)

对于无法解决的情况,你的堆栈溢出是正确的:递归代码的行为就像一只狗追逐它自己的尾巴,直到它达到堆栈限制。

幸运的是,你可以通过观察你最多有N个步骤到达数组的末尾来打破这种无限递归,如果你要达到它的话。因此,您可以添加第三个参数来指示您已经采取了多少步骤。如果在步数通过N之前达到零,则您有一条路径;否则,你没有路径。

static bool Solveable(int index, int[] arr, int stepsSoFar) {
    if (arr[index] == 0)
        return true;
    if (stepsSoFar > arr.Length)
        return false;
    ...
    // The rest of your code; pass stepsSoFar+1 down to the next level
}
  

我只能使用我的代码段中包含的两个参数

您可以通过将arr放入-1来标记您在arr内访问过的索引。为了保留数组的原始状态,将旧值存储在局部变量中,并在返回之前将其重新设置为static bool Solveable(int index, int[] arr) { if (arr[index] == 0) return true; if (arr[index] == -1) return false; int oldArrAtIndex = arr[index]; arr[index] = -1; try { ... // The rest of your code } finally { arr[index] = oldArrAtIndex; } }

@WebListener
public class MainWebListener implements ServletContextListener {

    private Thread threadQueueListener;
    private QueueThreadListener queueListener;

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        try {
            queueListener.disconnectQueue();
            Thread.sleep(QueueThreadListener.QUEUE_DELIVERY_TIMEOUT + 20);
        } catch (Throwable tt) {
            tt.printStackTrace();
        }
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        try {
            queueListener = new QueueThreadListener();
            threadQueueListener = new Thread(queueListener);
            threadQueueListener.setContextClassLoader(Thread.currentThread().getContextClassLoader());
            threadQueueListener.start();
        } catch (Throwable tt) {
            tt.printStackTrace();
        }
    }
}

答案 1 :(得分:1)

传递跟踪您已经旅行过的指数的第三个参数。如果您已经尝试过当前索引,请停止处理。

此外,您可能希望更改以适应任何方向的旅行:

var solvable = false;
//...

if (index + arr[index] < arr.Length)
   solvable = Solveable(index + arr[index], arr);
if (!solvable && index - arr[index] >= 0)
   solvable = Solveable(index - arr[index], arr);

return solvable;

答案 2 :(得分:1)

学校作业与否,关于递归的课程,没有增加复杂性。

<div id="nav">
    <div id="wrap">
        <ul>
        <li><a href="home.html">Home</a></li><li>

        <a href="#">Study</a>
            <ul>
                <li><a href="Present.html">Present Simple</a></li><li> 
                <a href="Possessives.html">Possesives</a></li><li>  
                <a href="Articles.html">Articles</a></li><li> 
                <a href="Modal.html">Modal Verbs</a></li><li>   
                <a href="Prepositions.html">Prepositions</a></li><li>    
                <a href="Plural.html">Plural of nouns</a></li><li>    
                <a href="Countability.html">Countability</a></li>           
            </ul>
          </li><li>
        <a href="#">Games</a>
            <ul>
                <li><a href="#">Riddles</a></li><li> 
                <a href="#">Flip card game</a></li><li>  
                <a href="#">Spot the mistake</a></li><li> 
                <a href="#">Multiple choice</a></li>                
            </ul>
          </li><li>
        <a href="oferta.html">Shop</a></li><li>
        <a href="contact.html">Contact</a></li><li>
        <a href="about.html">About Us</a></li>
        <li style="float:right"><a><img src="gmail.png" height="30px" width="30px"></a></li> <li style="float:right"><a><img src="twitter.png" height="30px" width="30px"></a></li><li style="float:right"><a><img src="facebook.png" height="30px" width="30px"></a></li>
        </ul>

    </div>
</div>

答案 3 :(得分:0)

您可以传递一个包含当前访问过的索引的数组,而不是传递int索引,如果您的下一个索引包含在被访问数组中,那么您只需要中断并返回false。

高层次的代码理念是:

static void Main(string[] args)
{

    int[] arr = { 3, 6, 4, 1, 3, 4, 2, 5, 3, 0 };
    var result = Solveable(new[] {0}, arr);


    Console.WriteLine(result);
    Console.ReadLine();
}

static bool Solveable(int[] path, int[] arr)
{
    var index = path.Last();

    if (arr[index] == 0)
        return true;
    if (index + arr[index] < arr.Length)
    {
        var nextIndex = index + arr[index];
        var nextStepPath = path.Concat(new[] { nextIndex }).ToArray();

        if (path.Contains(nextIndex))
            return false;

        return Solveable(nextStepPath, arr);                                      
    }
    if (index - arr[index] >= 0)
    {
        var nextIndex = index - arr[index];
        var nextStepPath = path.Concat(new[] {nextIndex}).ToArray();

        if (path.Contains(nextIndex))
            return false;

        return Solveable(nextStepPath, arr);
    }

    return false;
}

它需要一些清理,但为您提供高级的想法,并且只使用2个参数而不为您的数组引入类/结构。

答案 4 :(得分:0)

这是一种不修改状态的算法:

static bool Solveable(int index, int[] arr)
{
    if (arr[index] == 0)
        return true;
    int nextIndex = index + arr[index];
    if (nextIndex < arr.Length)
        return Solveable(nextIndex, arr);
    // Search for a previous index that leads to a different path
    int prevIndex;
    while (true)
    {
        prevIndex = index - arr[index];
        if (prevIndex < 0)
            return false; // Not found, we are done
        if (prevIndex + arr[prevIndex] != index)
            return Solveable(prevIndex, arr); // Process the other path
        index = prevIndex; // Keep searching
    }
}

关键部分是非递归后退步骤处理部分(参见代码中的注释)。