powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / рекурсивная функция делает переполнение кучи.
25 сообщений из 132, страница 2 из 6
рекурсивная функция делает переполнение кучи.
    #39364539
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Субъективно. Много лишних непонятных действий. Что это? Почему 2? Что это за магическая константа?
Код: java
1.
2.
        Horse h = new Horse();
        h.tryHorse(2);


Далее. System.out флудит беспощадно и блокирует скорость вычислений. Даже с заглушкой в /dev/null все равно
будет обеспечет терафлоп ненужной работы которую никто не смотрит. Вобщем вынести в slf4j или JUL с уровнем trace.

Результат вычислений возвращается через строковую константу. Это странно. Так обычно не делают.

Есть flow где имеет смысл добавить линию else чтобы отключить избыточные расчеты.
Есть повторы вычисления одного выражения которые можно зарефакторить через
introduce temp variable.

Очень много замечаний к codeStyle. Классы с маленькой буквы а имена переменных с dash.
Это ломает зрение.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364548
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

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

1) 2 это потому, что одного коня мы ставим уже в конструкторе , его координата int i_start=1;int j_start=1;. поэтому в рекурсивную функцию уже подаём 2.
2) System.out я использовал чтобы видеть, что он делает. о протоколировании по средствам slf4j даже и не догадывался. изучу . спасибо
3) Конечно же Вы правы. исправлю на boolean
4) Где вы предлагаете добавить ?
5) Поясните какие , пожалуйста.
6) Конечно, учту !
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364580
uid unique
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron81mayton,

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

1) 2 это потому, что одного коня мы ставим уже в конструкторе , его координата int i_start=1;int j_start=1;. поэтому в рекурсивную функцию уже подаём 2.
2) System.out я использовал чтобы видеть, что он делает. о протоколировании по средствам slf4j даже и не догадывался. изучу . спасибо
3) Конечно же Вы правы. исправлю на boolean
4) Где вы предлагаете добавить ?
5) Поясните какие , пожалуйста.
6) Конечно, учту !

Ничего страшного, немного причесал код. Память расходует от 120 до 260 МБ хипа, вроде сбрасывает до 140 примерно, особо ждать времени не было когда закончится цикл или хип.

1. Поставьте хипа хотя бы 512МБ, дефолтные размер может переполниться. Пример с гигом: java -Xmx1024m
2. Настройте логгирование, полезная вещь, читать и скачивать jar для log4j фасада и реализации в вашем случае скорее всего logback standalone http://logback.qos.ch/
3. Придерживайтесь рекомендуемого стиля Java кода: Sun (Oracle) http://www.oracle.com/technetwork/java/codeconvtoc-136057.html Google https://google.github.io/styleguide/javaguide.html

Код после легкой рехтовки, возможно легкомысленно изменил перебор if/if/if на if else/if else/.. в паре мест, проверьте, это просто пример. В алгоритм не вникал.

PS используйте переносы, разделяйте блоки кода, хотя на вкус и цвет товарищей нет...
Код: 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.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
package ru.sql.forum.samples.horse;

import org.slf4j.Logger;

public class Horse {

    private Logger logger = org.slf4j.LoggerFactory.getLogger(Horse.class);

    int hourseCount = 65;
    int[][] x = new int[9][9];
    int[] is = new int[hourseCount];
    int[] js = new int[hourseCount];
    long depth = 0;
    int iStartPos = 1;
    int jStartPos = 1;

    public Horse() {
        x[iStartPos][jStartPos] = 1;
        is[1] = iStartPos;
        js[1] = jStartPos;

        logger.debug("start");

        printState();
    }

    public static void main(String args[]) {
        Horse h = new  Horse();

        h.tryHorse(2);
    }

    public boolean tryHorse(int horseIndex) {
        boolean success = true;
        int[] moving;
        int mc = 1;
        int x1;
        int y1;
        depth++;
        logger.debug("Глубина = {}", depth);

        if (horseIndex == 2) {
            x1 = iStartPos;
            y1 = jStartPos;
            is[horseIndex] = x1;
            js[horseIndex] = y1;
        }

        do {
            moving = moveHorse(mc, is[horseIndex - 1], js[horseIndex - 1]);
            if (moving[0] != 0 && moving[1] != 0) { //если можно поставить коня
                x1 = moving[0];
                y1 = moving[1];

                x[x1][y1] = horseIndex;/*ставим*/
                is[horseIndex] = x1;
                js[horseIndex] = y1;

                logger.debug("Можно !  Передвигаем коня на  x={} y={}, ход {}", x1, y1, horseIndex);

                printState();

                if (horseIndex <= 64) {
                    success = tryHorse(horseIndex + 1);
                }

                if (!success) {
                    logger.debug("Плохо !  Вынуждены убрать коня с x={} y={} ", is[horseIndex], js[horseIndex]);

                    x[is[horseIndex]][js[horseIndex]] = 0;
                    is[horseIndex] = 0;
                    js[horseIndex] = 0;
                    success = true;
                }
            }
            mc++;
            if (mc == 9) {
                success = false;
            }
        } while (!(!success || mc == 9));

        depth--;

        return success;
    }

    public int[] moveHorse(int i1, int i, int j) {
        int[] result = new int[2];
        result[0] = 0;
        result[1] = 0;
        int is;
        int js;

        logger.debug("Попытка {} из 8. проверим можно ли передвинуть с {} {} ",i1, 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;

        } else 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;

        } else 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;

        } else 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;

        } else 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;

        } else 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;

        } else 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;

        } else 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 printState() {
        if(logger.isInfoEnabled()) {
            StringBuilder sb = new StringBuilder();

            for (int x = 1; x <= 8; x++) {
                for (int y = 1; y <= 8; y++) {
                    if (this.x[x][y] > 0) {
                        sb.append(this.x[x][y]).append(" ");
                    } else if (this.x[x][y] < 0) {
                        sb.append("B ");
                    } else if (this.x[x][y] == 0) {
                        sb.append("0 ");
                    }
                }
                sb.append("\n");
            }
            sb.append("\n");

            logger.info(sb.toString());
        }
    }
}
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364708
ivanra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
uid unique,
вот допустим, на 64 ходу найдено решение. Вопрос: выйдет ли код из цикла?
Код: java
1.
while (!(!success || mc == 9))
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364710
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Поскольку исходник живет своей жизнью то я буду комментировать последнюю версию
независимо от автора. Я сделал еще один машинальный рефакторинг.

1) Магические константы типа размер доски = 8 я вынес в отдельную static final переменную.
Это упрощает анализ кода и делает его более строгим.

2) StringBuilder можно инстанциировать заведомо известным размером. Это избавит нас от реаллокаций.

3) Была большая путаница в локальных переменных и переменных класса. Я заменил x,y на i,j и ушел
this и загадочный ...x[x]....

4) Я использовал temp variable чтобы убрать повторные вычисления в блоках if.

Вот что получилось.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
 static final int DESK_SIZE = 8;
    
    public void printState() {
        if(logger.isInfoEnabled()) {
             StringBuilder sb = new StringBuilder(200);
             for (int j = 1; j <= DESK_SIZE; j++) {
                 for (int i = 1; i <= DESK_SIZE; i++) {
                     int cell = x[j][i];
                     if (cell > 0) {
                        sb.append(cell).append(" ");
                    } else if (cell < 0) {
                        sb.append("B ");
                    } else if (cell == 0) {
                        sb.append("0 ");
                    }
                }
                sb.append("\n");
            }
            sb.append("\n");

            logger.info(sb.toString());
        }
    }
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364716
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Далее.

Код: java
1.
if (i1 == 1 && i - 2 >= 1 && j - 1 >= 1 && x[i - 2][j - 1] == 0) {  



используя математику неравенств константы слева и справа от знака сравнения
можно переносить в обе стороны и избавляться от ненужных калькуляций.

Код: java
1.
 if (i1 == 1 && i >= 3 && j >= 2 && x[i - 2][j - 1] == 0) {
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364720
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ivanrauid unique,
вот допустим, на 64 ходу найдено решение. Вопрос: выйдет ли код из цикла?
Код: java
1.
while (!(!success || mc == 9))



я в курсе не завершится никогда .
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364727
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По поводу multidimensional arrays в Java.

Код: java
1.
int[][] x = new int[DESK_SIZE+1][DESK_SIZE+1];



есть основания говорить о том что они не очень эффективны. Правильнее сказать что их реализация
для нашей задачи (шахматная доска) весьма избыточна. Нам хватит и обычного одномерного массива.

Код: java
1.
int[] x = new int[2*(DESK_SIZE+1)];



для доступа к элементу (i,j) мы должны использовать следующий getter

Код: java
1.
2.
3.
int getCellValue(int i, int j){
     return i * (DESK_SIZE+1) + j;
}



Сеттер кодится точно также. Почему i умножается на размер доски а не j - это вопрос договорённостей.
Можно и наоборот. Это влияет на обход доски слева-направо-сверху-вниз или сверху-вниз ... и.т.д.

Обычно на больших матрицах выбирают обход таким образом чтобы доступ к линейным участкам памяти
не сильно "распылялся". Это тоже один из хинтов перформанса.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364728
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Стоп я ошибся. Размер доски в квадрате от стороны.

Код: java
1.
int[] x = new int[(DESK_SIZE+1)*(DESK_SIZE+1)];
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364752
ivanra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andron81ivanrauid unique,
вот допустим, на 64 ходу найдено решение. Вопрос: выйдет ли код из цикла?
Код: java
1.
while (!(!success || mc == 9))


я в курсе не завершится никогда .
Не так, он завершится при mc == 9.
На самом деле, код вроде должен перебирать все решения, но вот с определением, что решение найдено - проблемы.
Во-первых, tryHorse всегда возвращает false, почему бы не преобразовать этот метод в void и не убрать лишнюю переменную?
Во-вторых, опять посмотрим на 64-й ход (horseIndex==64). При найденном решении мы заходим в if(), а там:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
                if (horseIndex <= 64) {
                    success = tryHorse(horseIndex + 1); // tryHorse(65)==false
                }

                if (!success) {
                    logger.debug("Плохо !  Вынуждены убрать коня с x={} y={} ", is[horseIndex], js[horseIndex]);

                    x[is[horseIndex]][js[horseIndex]] = 0;
                    is[horseIndex] = 0;
                    js[horseIndex] = 0;
                    success = true;
                }


это решение признано ошибочным
Конечно, правильное решение было выведено строчкой раньше
Код: java
1.
printState();

, но как мы найдем его среди всего этого флуда (до первого решения может быть выведено на консоль хот миллион неправильных)?
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364841
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если посмотреть на исходник глазами статического анализатора то можно видеть

The Cyclomatic Complexity of this method "moveHorse" is 33 which is greater than 10 authorized.

Complex code can perform poorly and will in any case be difficult to understand and therefore to maintain.

Я не знаю откуда он взял 33. Возможно просуммировал все предикаты в if-else и посчитал
их ветками логики. Но нам повезло что порядок проверки - декартовый и этот список
условий более-менее ясен. А если их заменить на некие абстрактные f1(), f2() то
тогда надо раскуривать сорс очень долго.

Кстати есть мысль что стоит отмечать свободые позиции битовой маской.
Кажется я так делал в своём С++ horse route.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364843
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uid unique1. Поставьте хипа хотя бы 512МБ, дефолтные размер может переполниться. Пример с гигом: java -Xmx1024m
2. Настройте логгирование, полезная вещь, читать и скачивать jar для log4j фасада и реализации в вашем случае скорее всего logback standalone http://logback.qos.ch/


возможно надо выполнить пункт №1, но я не знаю как это сделать.
сделал я только №2. у меня всё та же привычная ошибка : "io console updater java heap space"
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364849
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonКстати есть мысль что стоит отмечать свободые позиции битовой маской.


вы имеете ввиду что наш двухмерный массив должен быть boolean ?
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364865
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я думаю о том как свести арифметические операции проверки координат
к проверке масок.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364871
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonЯ думаю о том как свести арифметические операции проверки координат
к проверке масок.

это, конечно , здорово но это уж совсем слишком вы заморочились с оптимизацией алгоритма. ))
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364888
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Совершенству нет предела. А учитывая бесконечные возможности параллелизма
данной задачи (мы можем не шарить шахматную доску между процессами)
то эта задача скейлируется достаточно выгодно.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364897
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonСовершенству нет предела. А учитывая бесконечные возможности параллелизма
данной задачи (мы можем не шарить шахматную доску между процессами)
то эта задача скейлируется достаточно выгодно.

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


вот странно если начальная точка 1:1, то решения находятся довольно быстро - меньше минуты
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364906
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Надо подумать как задачи раздать. Чтоб повторов не было.

У вас уже есть мысли по этому вопросу?
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364917
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonНадо подумать как задачи раздать. Чтоб повторов не было.

У вас уже есть мысли по этому вопросу?

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

легче воспользоваться Правилом Варнсдорфа как тут советовали ранее:

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

На практике это реализуется, например, следующим образом. Перед каждым ходом коня вычисляется рейтинг ближайших доступных полей - полей, на которых конь еще не был, и на которые он может перейти за один ход. Рейтинг поля определяется числом ближайших доступных с него полей. Чем меньше рейтинг, тем он лучше. Потом делается ход на поле с наименьшим рейтингом (на любое из таковых, если их несколько), и так далее, пока есть куда ходить.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364932
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron81,

и выход , завершение нужно при нахождении хотя бы одного решения прописать каким-то образом как верно подмечал ivanra
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364957
ivanra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
uid unique,
еще неплохо было бы улучшить копипастный код метода moveHorse(). Например, итерацией по массиву
Код: java
1.
int[][] horseMoves = {{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1},{-1,2}};
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364976
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron81mayton,

легче воспользоваться Правилом Варнсдорфа как тут советовали ранее:
Данное правило, насколько я понял меняет некоторые характеристики
базового однопоточного алгоритма. Возможно улучшает o(n).

Но к предлагаемому мной вопросу (параллельный запуск нескольких
процессов и способ раздачи работ) Варнсдорф не имеет отношения.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39364998
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ivanrauid unique,
еще неплохо было бы улучшить копипастный код метода moveHorse(). Например, итерацией по массиву
Код: java
1.
int[][] horseMoves = {{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1},{-1,2}};




Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
  public int[] moveHorse(int i1, int i, int j) {
    	int[][] horseMoves = {{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1},{-1,2}};
        int[] result = new int[2];
        result[0] = 0;
        result[1] = 0;
        int is;
        int js;

        logger.debug("Попытка {} из 8. проверим можно ли передвинуть с {} {} ",i1, i, j);
        if (i + horseMoves[i1][0] >= 1 && i + horseMoves[i1][0] <= 8 &&
            j + horseMoves[i1][1] >= 1 && j + horseMoves[i1][1] <= 8
             && x[(i + horseMoves[i1][0])][(j + horseMoves[i1][1])] == 0
        		) {
        	
            is = i + horseMoves[i1][0];
            js = j +  horseMoves[i1][1];
            result[0] = is;
            result[1] = js;
        	
        }
        
        return result;
    }



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


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