Рекурсивный вывод текста

У меня есть процедура:

public void rec(int n)
    {try {
     editTextProg.setText(
          editTextProg.getText().toString()
          +Integer.toString(n)+" ");}
      catch (Exception e) {}
      n++;
      rec(n);
    }

Как видите она рекурсивно вызывает сама себя. Запускаю я ее в отдельном потоке с числом 0. Раньше когда небыло try {} приложение после вывода 0 вылетало, теперь оно вылетает где-то на 500 числе. Что делать чтобы приложение продолжало работать дальше.

Чот у вас дико странное форматирование :dadparrot:

Обычно люди форматируют примерно в таком стиле:

public void rec(int n) {
    try {
        editTextProg.setText(editTextProg.getText().toString() + Integer.toString(n) + " ");
    } catch(Exception e) {}
    n++;
    rec(n);
}

А что про 0 выдавало? Вроде бы не должно тут ничего странного с нулем происходить.

Но тут рекурсия бесконечная, так что непонятно чего вы ожидаете, рано или поздно стек переполнится. Видимо на 500 вызове это и произошло.

И лучше не сразу выводить в editTextProg, а возвращать функцией строку и потом её всю выводить один раз.

Обычно из другого потока нельзя так просто обращаться к GUI, только из основного.

1 лайк

У меня рекурсивная процедура начинается с нуля, без try {} приложение выводило первое значение n и после этого срывалось.

Но тут рекурсия бесконечная, так что непонятно чего вы ожидаете, рано или поздно стек переполнится. Видимо на 500 вызове это и произошло.

Это упрощенная версия другой моей программы, там она должна завершится через где-то 10000 вложений. С помощью цикла не решить. При создании потока для работы процедуры, я указываю размер стека с 9 нулями.

И лучше не сразу выводить в editTextProg, а возвращать функцией строку и потом её всю выводить один раз.

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

Обычно из другого потока нельзя так просто обращаться к GUI, только из основного.

А мне очень нужно из потока. Неучто нет обходного пути?

Это как? Любую рекурсию можно заменить циклом. Хотя бы просто создав свой стек.

Что программа делать должна?

Это много, и в Джаве вроде нет оптимизации хвостовой рекурсии.

1 лайк

Мое приложение эмулирует работу Пролог программы. Возьмем к примеру такой вопрос с предикатами: “?- родитель(том,анна), дедушка(том).”. Программа ищет истинность этих предикатов с лева направо, причем каждый раз появляется цикл в котором перебираются факты сопостовляя с текущим предикатом на равенство.
Все бы ничего. Но, когда вместе с фактами попадается правило, то нужно открыть новый цикл для доказательства истинности предикатов этого правила. А там, скажем, попадутся еще правила, что потребуют еще новых вложенных циклов и т.д. Как же тут без рекурсии обойтись?
На самом деле, у меня уже есть рабочая версия приложения. Стал писать программу игры в шашки с компьютером, написал треть программы и остановился. Программа через некоторое время останавливается (при большой глубине рекурсии). Проверял предикаты по отдельности - все в порядке, а вместе - через некоторое время выполнение программы останавливается (как-будто зависает, но это не так). Даже, задавал параметры для меньших вычислений - все работает (Кстати, в моем приложении, чем больше вложений в рекурсии, тем медленнее выполняются вычисления).

В java нет оптимизации хвостовой рекурсии".

В чем она заключается? Что тут можно бсделать?

Вернусь к тому на чем остановился. Рекурсивная процедура без вывода текста в EditText работает без остановок. Что делать, чтобы с выводом в EditText также работала?

Всегда можно как минимум просто создать свой стек и делать то же самое, что и происходит при рекурсии. Тогда размер стека будет ограничен только размером памяти, а не около 1 МБ по умолчанию.

Можно попробовать просто задать больший размер в параметрах потока при создании, но Джава не гарантирует, что применит это. Thread (Java Platform SE 7 )

On some platforms, specifying a higher value for the stackSize parameter may allow a thread to achieve greater recursion depth before throwing a StackOverflowError . Similarly, specifying a lower value may allow a greater number of threads to exist concurrently without throwing an OutOfMemoryError (or other internal error). The details of the relationship between the value of the stackSize parameter and the maximum recursion depth and concurrency level are platform-dependent. On some platforms, the value of the stackSize parameter may have no effect whatsoever.

The virtual machine is free to treat the stackSize parameter as a suggestion. If the specified value is unreasonably low for the platform, the virtual machine may instead use some platform-specific minimum value; if the specified value is unreasonably high, the virtual machine may instead use some platform-specific maximum. Likewise, the virtual machine is free to round the specified value up or down as it sees fit (or to ignore it completely).


В википедии же объяснено по ссылке выше. Если рекурсию можно сделать хвостовой, то теоретически компилятор может развернуть её в цикл (зависит от языка насколько это гарантировано).

1 лайк

Так а ошибку какую выдает?
Не думаю, что с самой рекурсией что-то происходит из-за EditText, и по идее раз всё в try catch, то оно не остановится если Джава выкинет исключение при взаимодействии с EditText (другой вопрос, что не факт, что будет работать корректно).

Но вообще тут проблема как минимум в

как это решить зависит от используемой технологии создания GUI, способа создания потока, версии Джавы.

1 лайк

Нашел способ:

       // отображаем в текстовом поле
       editTextProg.post(new Runnable() {
               public void run() {
          editTextProg.append(Integer.toString(n)+" ");
                            }
         });
        try{ thread.sleep(1);}catch (Exception e) {} //Чтобы фоновый поток не захватывал все процессорное время**