Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / рекурсивная функция делает переполнение кучи. / 25 сообщений из 132, страница 1 из 6
10.12.2016, 12:05
    #39364021
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Добрый день , друзья.

Помогите дилетанту .
Не могу разобраться , почему моя рекурсивная функция переполняет кучу.
Тупая реализация классической задачки на обход конем доски. Я правда так и не разобрался пока как закончить её выполнение. Но это не сильно и важно. (на данный момент просто хотелось бы добиться чтобы высветилось хотя бы одно решение, пусть и с зацикливанием)
Пытаюсь даже выводить грубо глубину рекурсии - она теоретически не должна превышать 64 - так и есть.
Однако при длительной работе (а дерево разрастается очень стремительно) высвечивает Java heap space.


Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
package horses;
import java.util.concurrent.TimeUnit;
public class horse {
int qty_of_hourse = 65;
int [][] x = new int[9][9];
int [] is = new int[65];
int [] js = new int[65];
long depth = 0;
int i_start=1;
int j_start=1;
int horse_count = 1;
public horse() {
x[i_start][j_start]=1; 
is[1] = i_start;js[1] = j_start;
System.out.println("start");
print_field();
}
public String try_horse(int current_horse) {
String res="good" ;
int [] moving= new int [2];
int mc=1; 
int x1=0;
int y1=0; 
depth++;
System.out.println("Глубина = " + depth);
if (current_horse==2) {x1=i_start; y1=j_start; is[current_horse] = x1;js[current_horse] = y1;}
do {
moving = move_horse(mc,is[current_horse-1],js[current_horse-1]);
if (moving[0]!=0 && moving[1]!=0) { //если можно поставить коня
	x1 = moving[0];
	y1 = moving[1];
x[x1][y1]=current_horse;/*ставим*/
is[current_horse] = x1;
js[current_horse] = y1;
System.out.println("Можно !  Передвигаем коня на "+x1+ " "+y1+", ход №"+current_horse);
print_field();
if (current_horse<=64) { res=try_horse(current_horse+1); }
if (res=="bad") {
	System.out.println("Плохо !  Вынуждены убрать коня с "+is[current_horse]+ " "+js[current_horse]);
	x[is[current_horse]][js[current_horse]]=0;
	is[current_horse]=0;
	js[current_horse]=0;
	res="good";
} 
} 
mc++;
if (mc==9) {res="bad";}
} while (!(res=="bad" || mc==9 )) ;
depth--;
return res;
}
public int [] move_horse(int i1 , int i , int j ) { 
int [] result= new int [2]; 
result[0] = 0 ;
result[1] = 0 ;
int is=0;
int js=0;

System.out.println("Попытка "+ i1 +" из 8. проверим можно ли передвинуть с " +i+ " "+  j);

if (i1==1 && i-2>=1 && j-1>=1 && x[i-2][j-1]==0) {is=i-2 ; js=j-1; result[0] = is ;result[1] = js ; 

} 
if (i1==2 && i-1>=1 && j-2>=1 && x[i-1][j-2]==0) {is=i-1 ; js=j-2; result[0] = is ;result[1] = js ; 

} 
if (i1==3 && i+1<=8 && j-2>=1 && x[i+1][j-2]==0) {is=i+1 ; js=j-2; result[0] = is ;result[1] = js; 

}
if (i1==4 && i+2<=8 && j-1>=1 && x[i+2][j-1]==0) {is=i+2 ; js=j-1; result[0] = is ;result[1] = js; 

}
if (i1==5 && i+2<=8 && j+1<=8 && x[i+2][j+1]==0) {is=i+2 ; js=j+1; result[0] = is ;result[1] = js; 

}
if (i1==6 && i+1<=8 && j+2<=8 && x[i+1][j+2]==0) {is=i+1 ; js=j+2; result[0] = is ;result[1] = js; 

}
if (i1==7 && i-1>=1 && j+2<=8 && x[i-1][j+2]==0) {is=i-1 ; js=j+2; result[0] = is ;result[1] = js; 

}
if (i1==8 && i-2>=1 && j+1<=8 && x[i-2][j+1]==0) {is=i-2 ; js=j+1; result[0] = is ;result[1] = js ; 

}
return result;
}
public void print_field() {
int i1;
int j1;
for (i1 = 1; i1 <= 8; i1++) {
for (j1 = 1; j1 <= 8; j1++) {
if (x[i1][j1]>0) {System.out.print(x[i1][j1]+" ");}
if (x[i1][j1]<0) {System.out.print("B ");}
if (x[i1][j1]==0) {System.out.print("0 ");}
}
System.out.println();
}
System.out.println();
}
}




Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
package horses;

public class main {
	public static void main(String args[]) {
		 horse h = new  horse();
		 
		 h.try_horse(2);

		
	}
}
...
Рейтинг: 0 / 0
10.12.2016, 12:12
    #39364025
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
2 ** 64 ~ 10 ** 18
Терабайт это 10 ** 12
...
Рейтинг: 0 / 0
10.12.2016, 12:50
    #39364032
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Basil A. Sidorov2 ** 64 ~ 10 ** 18
Терабайт это 10 ** 12

то есть вы хотите сказать, что когда 64 процедуры вызывают последовательно друг друга , то памяти отъедается более терабайта ? :-)
...
Рейтинг: 0 / 0
10.12.2016, 12:57
    #39364035
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Я хочу сказать, что есть "рекурсия вглубь" и "рекурсия вширь".

P.S. Мне лень разбираться в попытках решить методом полного перебора задачу, которую (насколько мне изменяет склероз) умные люди давно решили вручную.
...
Рейтинг: 0 / 0
10.12.2016, 13:06
    #39364037
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Basil A. Sidorov,

эта именно тупо вглубь .
что значит решили вручную ? ))))
...
Рейтинг: 0 / 0
10.12.2016, 13:19
    #39364043
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Ну, например, в старом журнале ("Наука и жизнь", если правильно помню) была статья, где в качестве одного из способа запоминания ходов автор придумал стихи, строчки которых были мнемониками шахматных клеток. Журнал - не младше середины-конца восьмидесятых.

P.S. Насколько я помню вполне классическую "Алгоритмы + структуры данных = программы", принципиально разных решений всего двенадцать. Издание начала восьмидесятых.
...
Рейтинг: 0 / 0
10.12.2016, 13:38
    #39364048
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Хотя, вру - у Вирта решается задача расстановки восьми ферзей.
Чтобы рекурсия была вглубь требуются две вещи стратегия обхода и запоминание "границы отсечения".
Когда на каждом шаге перебираются все возможные варианты это именно что рекурсия вширь.

P.S. Я бы предложил разбираться с рекурсией на гораздо более простой задаче: лабиринт без циклов, где на каждом шаге можно повернуть или влево или вправо и глубина любого пути не превышает заданного (небольшого) числа шагов.
Начинать с лабиринтов, которые можно нарисовать на листе школьной тетради в клеточку.
...
Рейтинг: 0 / 0
10.12.2016, 13:45
    #39364052
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Basil A. Sidorov,

да, совершенно верно , есть у меня такая . там приведён даже шаблон перемещения по дереву с возвратом. именно им я и воспользовался.


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

Разбираться в моём коде я никого не прошу. просто хочу для себя разобраться почему происходит переполнение памяти.
максимально в любой период времени работы программы может быть не более 64 вызова процедуры.

одна процедура резервирует грубо говоря:
3 переменных int (96 байт),
один массив (64 байта)
переменная типа String
может в последней проблема ? я толком не понимаю пока эта переменная фиксированной длины или же переменной ?

почему вы насчитали, что памяти должно резервироваться более терабайта
...
Рейтинг: 0 / 0
10.12.2016, 13:46
    #39364053
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Basil A. SidorovХотя, вру - у Вирта решается задача расстановки восьми ферзей.


нет, не врете. кони тоже решаются в моем издании
...
Рейтинг: 0 / 0
10.12.2016, 13:47
    #39364056
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
И ещё: чтобы не путать глубину рекурсии с числом (активных) рекурсивных вызовов - сделайте статическую, которая будет увеличиваться на входе в рекурсивный метод и уменьшаться на выходе. Ну и печатайте значение этой переменной по мере надобности.
...
Рейтинг: 0 / 0
10.12.2016, 13:49
    #39364058
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Basil A. SidorovИ ещё: чтобы не путать глубину рекурсии с числом (активных) рекурсивных вызовов - сделайте статическую, которая будет увеличиваться на входе в рекурсивный метод и уменьшаться на выходе. Ну и печатайте значение этой переменной по мере надобности.


так и делал . за исключением статики
...
Рейтинг: 0 / 0
10.12.2016, 13:51
    #39364059
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
andron81,

стоп. статическую что вы имеете ввиду ? переменную или метод вызова статический ?
...
Рейтинг: 0 / 0
10.12.2016, 13:57
    #39364060
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
andron81,

это вы имеете ввиду ?

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
public class horse {
...
static long depth = 0;
...

public String try_horse(int current_horse) {
string result;
depth ++;
     ....
try_horse(current_horse+1) ;
     ....
depth --;

return  result ;
}



у меня переменная depth сейчас считается так же за исключением того , что объявлена она не как static.
честно говоря не чувствую разницы
...
Рейтинг: 0 / 0
10.12.2016, 14:01
    #39364061
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Статика непринципиальна.
Просто вы считаете именно что глубину рекурсии, а считать надо число активных вызовов.
Цепочка вызовов активна до тех пор пока мы или не нашли (очередное) решение или не обнаружили, что эта цепочка ходов решением не является.
Когда вы осознаете, что каждый узел в цепочке вызовов порождает свою цепочку вызовов, вам станет понятнее "куда девается память".
...
Рейтинг: 0 / 0
10.12.2016, 14:30
    #39364072
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Basil A. Sidorov,

как я понимаю мой алгоритм в любой момент времени хранит только лишь текущую самую глубокую ветку и всю цепочку до неё .
остальные пройденные субдеревья и не приведшие к удаче в данный момент не хранятся. Или нет ?

вот на рисунке мы скажем в данный промежуток времени проделали маршрут 1->7->8->9->12. мы этот маршрут и храним.
пусть даже до этого были маршруты
1->2-> 3-> 4
1->2-> 3-> 5
1->2-> 3-> 6
а так же
1->7->8->9->10->11
но они не привели к решению . ну значит мы по ним и выполнили всюду return-ы , а это значит и память по ним расчистилась. Или же нет ?

а маршрут 1->7->8->9->12 это 5 вызовов. и глубина = 5. или же нет ??
...
Рейтинг: 0 / 0
10.12.2016, 14:58
    #39364080
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Basil A. SidorovЦепочка вызовов активна до тех пор пока мы или не нашли (очередное) решение или не обнаружили, что эта цепочка ходов решением не является.


верно и это понятно. но цепочка вызовов не может превышать 64 (число ходов, а значит клеток на шахматной доске).
...
Рейтинг: 0 / 0
10.12.2016, 18:17
    #39364109
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Кстати, об ограничениях ...
Чтобы шестьдесят четвёртым ходом оказаться в точке (0,0), на шестьдесят третьем ходу надо быть или в точке (2,1) или в точке (1,2).
...
Рейтинг: 0 / 0
10.12.2016, 18:32
    #39364111
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Basil A. Sidorov,

блин, да нет же. задача стоит проще: просто обойти абсолютно все клетки , закрасив их.

кстати, я Вам соврал. похоже, что ругается консоль . "io console updater java heap space" я наверно превысил допустимое число вывода на экран . кстати , можно ли выводить не в консоль , а в файл (Eclipse) ? гугл не помог.

а "ругань" превышения допустимых вызовов рекурсивной функции выглядит иначе. достаточно накидать программу n! и поставить в качестве входного параметра скажем громадное число. там со стэком будет ошибка.
...
Рейтинг: 0 / 0
10.12.2016, 18:33
    #39364112
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
andron81,

P.s. стоит задача обойти все клетки конем побывав ровно по одному в каждой
...
Рейтинг: 0 / 0
11.12.2016, 16:12
    #39364421
Atum1
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
andron81,

=) помню сдавал такую курсовую два раза за обучение :)

Вот пример . тут даже с графикой )


http://5fan.ru/wievjob.php?id=49236
...
Рейтинг: 0 / 0
11.12.2016, 16:53
    #39364430
Atum1
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
...
Рейтинг: 0 / 0
11.12.2016, 18:47
    #39364472
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Atum1,

спасибо , конечно, интересней самому решить, что я и сделал.

для начальной точки 1,1 выдаёт решения за время меньше минуты.
а вот на точке 1,2 выходит в ступор. дерево разрастается настолько , что и за 40 минут ни одного решения не выдаёт
...
Рейтинг: 0 / 0
11.12.2016, 18:58
    #39364476
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Atum1 http://algolist.manual.ru/maths/combinat/knight.php

хотя интересное правило Варнсдорфа описано.
но я правило такого не знал. поэтому у меня тупой перебор всего дерева. поэтому видимо и долго
...
Рейтинг: 0 / 0
11.12.2016, 19:31
    #39364485
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
Лет 10 назад я кодил на С++/Win32 GDI приложение для решения horse problem.

Чтоб рекурсия не заходила в слишком глубокие поиски я разработал правила
построения кориродов (только для прямоугольной доски) чтобы ограничить
для коня следущие несколько N ходов. Для этого я выбирал ширину коридора
(4 клетки) и змейкой заполнял всю доску.

К сожалению сорцы потерял.
...
Рейтинг: 0 / 0
11.12.2016, 19:43
    #39364488
andron81
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
рекурсивная функция делает переполнение кучи.
mayton,

мне не сильно важна оптимизация пока моего алгоритма. важен сам факт - ищет / не ищет. тем более решение кое-какие находит.
А вообще я пытаюсь разобраться с рекурсией.
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / рекурсивная функция делает переполнение кучи. / 25 сообщений из 132, страница 1 из 6
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]