Отладка рекурсивного алгоритма

мой вопрос в том, есть ли какие-то умные способы отладки сложных рекурсивных алгоритмов. Предположим, что у нас есть сложный (а не простой случай, когда счетчик рекурсии уменьшается в каждой "вложенной итерации").

Я имею в виду что-то вроде рекурсивного обхода графа, когда петли возможны.

Мне нужно проверить, не получаю ли я бесконечный цикл где-нибудь. И делать это просто с помощью отладчика дает не определенный ответ (потому что я не уверен, что алгоритм в бесконечном цикле или просто процесс, как надо).

Это трудно объяснить без конкретных примеров. Но то, что мне нужно...

'чтобы проверить, не возникают ли бесконечные циклы, скажем, в сложном рекурсивном алгоритме'.

5 ответов


вам нужно сформировать теорию, почему вы думаете, что алгоритм завершается. В идеале докажите теорию как математическую теорему.

вы можете искать функцию состояния проблемы, которая сокращается при каждом рекурсивном вызове. Например, см. следующее обсуждение функции Ackermann, from Википедия

может быть не сразу очевидно, что оценка A(m, n) всегда заканчивается. Однако, рекурсия ограничена, потому что в каждое рекурсивное приложение либо M уменьшается, либо m остается неизменным и N уменьшается. Каждый раз, когда n достигает нуля, m уменьшается, поэтому M в конечном итоге также достигает нуля. (Выражаясь более технически, в каждом случае пара (m, n) уменьшается в лексикографическом порядке на парах, что является хорошим порядком, как и порядок одиночных неотрицательных целых чисел; это означает, что нельзя спускаться в порядке бесконечно много раз подряд.) Однако, когда M уменьшается, нет верхней границы того, как много n может увеличиться - и часто будет сильно увеличиваться.

Это тип рассуждений, которые вы должны думать о применении к вашему алгоритму.

Если вы не можете найти способ доказать, что ваш алгоритм завершается, подумайте о поиске варианта, завершение которого вы можете доказать. Не всегда возможно решить, завершается ли произвольная программа или нет. Фокус в том, чтобы написать алгоритмы, которые вы можете доказать.


лучше доказывает конечность по условиям pre и post, вариантам и инвариантам. Если вы можете указать (виртуальную) формулу, значение которой увеличивается при каждом вызове, у вас есть гарантия.

Это то же самое, что доказать, что петли конечны. Кроме того, это может сделать сложные алгоритмы более доступными.


Если вы хотите проверить наличие бесконечных циклов,

написать System.out.println("no its not endless"); на следующей строке вызова рекурсивной функции.

если цикл будет бесконечным, этот оператор не получит печать, если в противном случае вы увидите вывод


вам нужно подсчитать глубину рекурсивных вызовов ... а затем бросать исключение, если глубина рекурсивных вызовов достигает определенного порога.

например:

void TheMethod(object[] otherParameters, int recursiveCallDepth)
{
   if (recursiveCallDepth > 100) { 
      throw new Exception("...."); }
   TheMethod(otherParameters, ++recursiveCallDepth);
}

одно предложение следующее:

Если у вас есть бесконечный цикл, то в случае графа вы получите путь с количеством вершин, большим, чем общее количество вершин в графе. Предполагая, что число вершин в графе является глобальной переменной (что, я думаю, является наиболее распространенным случаем), вы можете сделать условную точку останова в начале рекурсии, если глубина уже выше общего числа вершин.

здесь ссылка как вы делаете условные точки останова для java в Eclipse.