powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / рекурсивная функция делает переполнение кучи.
25 сообщений из 132, страница 5 из 6
рекурсивная функция делает переполнение кучи.
    #39368805
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonДержи. Я поставил отметки TODO: только там где на мой взгляд имеет место
недостаток performance.

TODO не удаляй до тех пор пока фактически не будет
сделано по ним исправление. Задавай вопросы. Отвечу.



постараюсь выполнить за выходные .

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

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

mayton // TODO: заименить int[][] x на int[] x. Переписать логику соотв.
int[][] x = new int[lll+1][lll+1];


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

mayton // TODO: заименить int[][] x на int[] x. Переписать логику соотв.
int[][] x = new int[lll+1][lll+1];


а как вы собираетесь проверять был ли конь в клетке i,j ?

это же простая развертка двумерного массива в одномерный, на пальцах:

массив а=int[8][10] приводим в b=int[80];

a[5][3] = b[5 *10 + 3] = b[53]
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39368939
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uid uniqueandron81и сразу вопрос

пропущено...


а как вы собираетесь проверять был ли конь в клетке i,j ?

это же простая развертка двумерного массива в одномерный, на пальцах:

массив а=int[8][10] приводим в b=int[80];

a[5][3] = b[5 *10 + 3] = b[53]

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

Оптимизация по скорости и расходу памяти, ведь каждый объект занимает дополнительное место (описание и связи), каждый вызов метода примерно на 15% медленнее выполнения inline кода или доступа к полю напрямую.

Нашел такой тест, не поленился его запустить в микро-бенчмарке

Код: 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.
package org.sample;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OperationsPerInvocation;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.sample.Measure.X;
import static org.sample.Measure.Y;

@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
@OperationsPerInvocation(X*Y)
@Warmup(iterations = 30, time = 100, timeUnit=MILLISECONDS)
@Measurement(iterations = 5, time = 1000, timeUnit=MILLISECONDS)
@State(Scope.Thread)
@Threads(1)
@Fork(1)
public class Measure
{
    static final int X = 100_000, Y = 10;
    private final int[] single = new int[X*Y];
    private final int[][] multi = new int[X][Y];

    @Setup
    public void setup() {
        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
        for (int i=0; i<single.length; i++) single[i] = rnd.nextInt();
        for (int i=0; i<multi.length; i++)
            for (int j=0; j<multi[0].length; j++)
                multi[i][j] = rnd.nextInt();
    }

    @Benchmark
    public long sumSingle() { return sumSingle(single); }

    @Benchmark
    public long sumMulti() { return sumMulti(multi); }

    public static long sumSingle(int[] arr) {
        int total = 0;
        for (int i=0; i<arr.length; i++)
            total+=arr[i];
        return total;
    }

    public static long sumMulti(int[][] arr) {
        int total = 0;
        for (int i=0; i<arr.length; i++)
            for (int j=0; j<arr[0].length; j++)
                total+=arr[i][j];
        return total;
    }
}



Результат (на 8 Java):

# Run complete. Total time: 00:00:16

Benchmark Mode Cnt Score Error Units
Measure.sumMulti avgt 5 0.655 ± 0.037 ns/op
Measure.sumSingle avgt 5 0.288 ± 0.023 ns/op

Примерно в 2 раза медленне подсчет суммы (из за циклов / проверок) в многомерном массиве чем в одномерном.

В вашем случае большой экономии не будет, можно не обращать внимания.
Вам эта оптимизация сейчас не нужна, отработайте алгоритм вначале.

Аналогично, целочисленное деление и умножение быстрее примерно в 2 раза чем с плавающей точкой (но это тоже не нужно, просто к сведению)

По расходу памяти когда запускал пример (с первой страницы форума), хип был в пределах 120 - 270 МБ, периодически сбрасывался на 120-140 те расход небольшой. Out of memory мог быть вызван тем что использовался размер хипа по умолчанию близкий к 250МБ

Как проверить размер хипа по умолчанию

java -XX:+PrintFlagsFinal -version | findstr HeapSize

или на юниксе/линуксе/маке

java -XX:+PrintFlagsFinal -version | grep HeapSize

У меня вывела 256МБ начальный размер хипа по умолчанию:

uintx ErgoHeapSizeLimit = 0 {product}
uintx HeapSizePerGCThread = 87241520 {product}
uintx InitialHeapSize := 268435456 {product}
uintx LargePageHeapSizeThreshold = 134217728 {product}
uintx MaxHeapSize := 4294967296 {product}

PS пардон что не вникаю в тему, у меня сейчас разгребания Java кода конца 90х (почти Java 1.1) нaписанного в стиле 80х (даже коллекций нет и процедурное программирование к зачатками объектов), голова уже не соображает, особенно в пятницу... ;-) Хороших выходных!
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39369346
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonДержи. Я поставил отметки TODO: только там где на мой взгляд имеет место
недостаток performance.

TODO не удаляй до тех пор пока фактически не будет
сделано по ним исправление. Задавай вопросы. Отвечу.



Код: javascript
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.
package horses;

import java.util.* ;

public class Horse implements Runnable {
    int sideofBoard=6;/*сторона доски*/
    int Count = sideofBoard*sideofBoard; /*количество ходов кот. нужно сделать*/
    // TODO: заименить int[][] x  на  int[] x. Переписать логику соотв.
    int[] board = new int[sideofBoard*10+sideofBoard+1]; 
    int[] iresultLog = new int[Count+1]; /*лог результат по вертикале.   hourseCount+1 , потому как хочу индекс вести не с 0, а с 1  */
    int[] jresultLog = new int[Count+1]; /*лог результат по горизонтале. hourseCount+1 , потому как хочу индекс вести не с 0, а с 1  */
    long depth = 0;
    int threadName;                            /*имя потока*/
    int iStartPos ;							   /*старт координата по вертикале*/	
    int jStartPos;							   /*старт координата по горизонтале*/	
    public Horse(int t,int iStartPos , int jStartPos )
    {
        threadName=t;						   /*именуем поток */
        board[iStartPos*10+jStartPos] = 1;	   /*ставим первый ход в массиве на доске*/
        this.jStartPos=jStartPos ;
        this.iStartPos=iStartPos;
        iresultLog[1] = iStartPos;			   /*ставим первый ход в лог по вертикале*/
        jresultLog[1] = jStartPos;			   /*ставим первый ход в лог по горизонтале*/	
    }
  public boolean tryHorse(int horseIndex) {
        boolean success = true;
        int[] moving;
        int variant  = (int)(Math.random() * 8);
        int x1;
        int y1;
        depth++;
        // TODO: Убрать printState()
       if (horseIndex == 2) {
            x1 = this.iStartPos;
            y1 = this.jStartPos;
            iresultLog[horseIndex] = x1;
            jresultLog[horseIndex] = y1;
            // TODO: Убрать printState() 
        }
        do {
            moving = moveHorse( variant, iresultLog[horseIndex - 1], jresultLog[horseIndex - 1]);
            if (moving[0] != 0 && moving[1] != 0) { //если можно поставить коня
                x1 = moving[0];
                y1 = moving[1];
                 board[x1*10+y1] = horseIndex;/*ставим*/
                iresultLog[horseIndex] =  x1;
                jresultLog[horseIndex] =  y1;
                // TODO: Убрать printState()
              if (horseIndex ==sideofBoard*sideofBoard) 	{
                	// TODO: Оставить printState только там где найден вариант решения этой задачи.
                	printState();}
                if (horseIndex <= sideofBoard*sideofBoard+1) {
                    success = tryHorse(horseIndex + 1);
                } 
                if (!success) {
                // TODO: Убрать printState()
                    board[iresultLog[horseIndex]*10+jresultLog[horseIndex]] = 0;
                    //System.out.println("Плохо !   Вынуждены убрать коня "+ is[horseIndex]+" "+js[horseIndex] +" ход ");
					iresultLog[horseIndex] = 0;
                	jresultLog[horseIndex] = 0;
                    success = true;                    
                }
            }
            variant = (int)(Math.random() * 9);
            if ( variant == 8) {
                success = false;
            }
        } while (!(!success ||  variant == 8));
        depth--;
        return success;
    }
    

    // TODO: Сделать методом moveHorse inline. Отказаться от returnvalue.
    public int[] moveHorse(int i1, int i, int j) {
        // TODO: заименить horseMoves[][] x  на  одномерный массив int[] x, или два одномерных.
        int[] horseMovesI = {1,2, 2, 1,-1,-2,-2,-1};
        int[] horseMovesJ = {2,1,-1,-2,-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 + horseMovesI[i1] >= 1 && i + horseMovesI[i1] <= sideofBoard &&
                j + horseMovesJ[i1] >= 1 && j + horseMovesJ[i1] <= sideofBoard
                && board[(i + horseMovesI[i1])*10+(j + horseMovesJ[i1])] == 0
                ) {
            is = i + horseMovesI[i1];
            js = j +  horseMovesJ[i1];
            result[0] = is;
            result[1] = js;
        }
        return result;
    }
    public void printState() {
        System.out.println("Поток # "+threadName);
        for (int i = 1; i <= sideofBoard; i++) {
        	for (int j = 1; j <= sideofBoard; j++) {
                System.out.print(board[i*10+j]+ " ");
                   	}
        	System.out.println();        	
        }        
    }
    public void run() {

//		 try{
        tryHorse(2);
//		 }catch(Exception e) {}
    }
}




не справился с inline функцией . то есть погуглив я выяснил(не знаю правда ошибочно или нет), что inline методы в java создать не выйдет. Можно сделать только статик.
Но даже это если и так , то как мне избавится от returnValue совсем неясно. можете привести простой пример ? скажем функцию
вычисляющая x + 10 как сделать inline ?
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39369347
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron81 скажем функцию
вычисляющая x + 10 как сделать inline ?

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


согласен, думаю пример не для отработки (не лёгкий), но раз уж понеслась , то придется )



uid uniqueКак проверить размер хипа по умолчанию

java -XX:+PrintFlagsFinal -version | findstr HeapSize


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

Я обратил внимание на то что функция

Код: java
1.
 moving = moveHorse(mc, is[horseIndex - 1], js[horseIndex - 1]);



Используется 1 единственный раз. При этом она использует return int[] с одной целью - обеспечить
возврат пары координат (moving[]). Поскольку стандарт Java language не дает возможности
делать out-parameters то автор это решает за счет возврата array.

Далее я рассудил так. Если мы тело функции перенесем в 1 единственную точку ее вызова
то мы избавляемся от такого странного способа возврата. А результат работы moveHorse
мы можем записать в переменные.

Код: java
1.
2.
moving[0] => mx
moving[1] => my



Из алгоритма уходят операции индексации moving и операция передачи через стек ссылки
на array. Сам array и его аллокация new[] тоже уходит т.к. массив становится не нужен.
+положительный эффект - меньше нагрузка на heap.

С точки зрения Мартина Фаулера - мы сделали не очень хорошо т.к. увеличиваем размер
метода. Но с точки зрения performance и GC - мы улучшим картину.

Если-бы функция moveHorse использовалась много раз или была-бы рекурсивной то
мы не смогли-бы такой фокус провернуть.

Сам термин inline пускай вас не смущает. Можете заменить его на копи-пасту. Это тоже самое.
Так в C++ например работают механизмы развёртывания макросов.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39369422
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron81зачем ? в чем выигрыш ?
Это мой старый добрый рефакторинг который я юзаю уже много лет.
В основном он эффективен в растровой графике. Задавать картинку
и работать с ней удобнее через int[] rgbColors чем через int[][] rgbColors.
Так скорость выше. Это я знаю еще со времен С++. В некоторых случаях
длину строки выравнивают на число байт кратных машинному WORD
процессора. Типа padding строки. Плюс есть еще много нюансов
связанных с тем как аллокатор int[][] размещает суб-массивы в куче.
При удачном стечении обстоятельств (обходим массив слева направо
и сверху вниз) канал памяти получает тразнакции чтения по линейным
адресам. Это благоприятный кейс. Но возможно будет и не-благоприятный.

Когда я задаю матрицу или куб (или гиперкуб) через линейный массив
то я сам вручную обеспечиваю линейный порядок доступа к элементам
памяти.

Некий господин выше не поленился и даже привел бенчмарк с использованием JMH
и с прогревом компиллятора как положено. Что-ж. Я не буду с ним спорить.
Мои последние бенчмарки я делал еще во время JDK6 а тогда
и деревья были выше и оптимизатор был попроще.

Возможно сейчас и нет острой необходимости выключать int[][] но я
лишний раз замечу что наша задача выгодно отличается от других.
У нас - квадратное поле (а не зубчатое) и ширина строки заведомо известна.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39369463
uid unique
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonНекий господин выше не поленился и даже привел бенчмарк с использованием JMH
и с прогревом компиллятора как положено. Что-ж. Я не буду с ним спорить.
Мои последние бенчмарки я делал еще во время JDK6 а тогда
и деревья были выше и оптимизатор был попроще.
JMH тест как раз показываeт большую производительность у линейного массива (> 2 раз) чем у многомерного, как и ожидалось. Если без микробенчмарка делать, с System.currentTime, то скорее всего разница будет менее заметна.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39369471
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
о гспди....обалденно почитать всё это нубу )))
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39369503
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonСейчас поясню суть рефакторинга с inline.

Я обратил внимание на то что функция

Код: java
1.
 moving = moveHorse(mc, is[horseIndex - 1], js[horseIndex - 1]);



Используется 1 единственный раз. При этом она использует return int[] с одной целью - обеспечить
возврат пары координат (moving[]). Поскольку стандарт Java language не дает возможности
делать out-parameters то автор это решает за счет возврата array.

Далее я рассудил так. Если мы тело функции перенесем в 1 единственную точку ее вызова
то мы избавляемся от такого странного способа возврата. А результат работы moveHorse
мы можем записать в переменные.

Код: java
1.
2.
moving[0] => mx
moving[1] => my



Из алгоритма уходят операции индексации moving и операция передачи через стек ссылки
на array. Сам array и его аллокация new[] тоже уходит т.к. массив становится не нужен.
+положительный эффект - меньше нагрузка на heap.

С точки зрения Мартина Фаулера - мы сделали не очень хорошо т.к. увеличиваем размер
метода. Но с точки зрения performance и GC - мы улучшим картину.

Если-бы функция moveHorse использовалась много раз или была-бы рекурсивной то
мы не смогли-бы такой фокус провернуть.

Сам термин inline пускай вас не смущает. Можете заменить его на копи-пасту. Это тоже самое.
Так в C++ например работают механизмы развёртывания макросов.

понял. переделаю
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39369683
uid unique
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron81понял. переделаю
Вроде немного очухался за выходной. Если будете делать перебор в нескольких потоках, то придется либо лочить общий ресурс, либо делать его volatile, что для больших объектов плохо.

Для отдельных локов на чрение и запись, можете использовать подобный код:
(Предупреждаю что сам по себе код бессмысленный, просто пример с расшареным ресурсом):
Код: 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.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Horse implements Runnable {

    static final int[][] HORSE_MOVES = {{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1},{-1,2}};
    static final int HOURSE_COUNT = 65;
    static final int BOARD_DIMENSION =6;/*длина доски*/

    static int[][] USED_BOARD_CELLS = new int[BOARD_DIMENSION +1][BOARD_DIMENSION +1];
    static ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();

    final int[] xPositions = new int[HOURSE_COUNT];
    final int[] yPositions = new int[HOURSE_COUNT];

    long depth = 0;
    int threadId;
    int startXPos;
    int startYPos;


    public Horse(int threadId, int startXPos, int startYPos )
    {
        this.threadId =threadId;

        writeLock.lock();
        try {
            //Double check after obtaining write lock that cell is available
            if(USED_BOARD_CELLS[startXPos][startYPos] != 0) {
                //Cell is used by another Horse
                throw new RuntimeException("Board cell "+startXPos + "x"+startYPos+" is already used!");
            }
            USED_BOARD_CELLS[startXPos][startYPos] = 1;
        } finally {
            //release write lock
            writeLock.unlock();
        }

        this.startYPos =startYPos ;
        this.startXPos =startXPos;

        xPositions[1] = startXPos;
        yPositions[1] = startYPos;
    }

    public static void main (String[] args) {

        Thread t1 = new Thread(new Horse(1,1,2));
		/*
		Thread t1 = new Thread(new Horse(1,5,5));
   Thread t2 = new Thread(new Horse(2,4,2));

   Thread t4 = new Thread(new Horse(4,3,2));
   Thread t5 = new Thread(new Horse(5,6,4));
   Thread t6 = new Thread(new Horse(6,1,3));
   Thread t7 = new Thread(new Horse(7,2,1));
   Thread t8 = new Thread(new Horse(8,3,4));
   */

        t1.start();
/*   t2.start();
   t3.start();
   t4.start();
   t5.start();
   t6.start();
   t7.start();
   t8.start();
  */
    }


    public boolean tryHorse(int horseIndex) {
        boolean success = true;

        int xPos;
        int yPos;
        depth++;
        //System.out.println("tryHorse("+horseIndex+")");
        printState();
        //logger.debug("Глубина = {}", depth);

        if (horseIndex == 2) {
            xPos = this.startXPos;
            yPos = this.startYPos;
            xPositions[horseIndex] = xPos;
            yPositions[horseIndex] = yPos;
            printState();
        }

        int i;
        int j;
        int nextX;
        int nextY;

        for(int stepIndex = 0; stepIndex < HORSE_MOVES.length; stepIndex++){
            i = xPositions[horseIndex - 1];
            j = yPositions[horseIndex - 1];


            readLock.lock();
            try {
                if (i + HORSE_MOVES[stepIndex][0] >= 1 && i + HORSE_MOVES[stepIndex][0] <= BOARD_DIMENSION &&
                        j + HORSE_MOVES[stepIndex][1] >= 1 && j + HORSE_MOVES[stepIndex][1] <= BOARD_DIMENSION
                        && USED_BOARD_CELLS[(i + HORSE_MOVES[stepIndex][0])][(j + HORSE_MOVES[stepIndex][1])] == 0) {
                    nextX = i + HORSE_MOVES[stepIndex][0];
                    nextY = j + HORSE_MOVES[stepIndex][1];

                    //если можно поставить коня
                    xPos = nextX;
                    yPos = nextY;
                } else {
                    // Continue next
                    continue;
                }
            } finally {
                readLock.unlock();
            }


            writeLock.lock();
            try {
                if(USED_BOARD_CELLS[startXPos][startYPos] == 1) {
                    //Cell is used by another Horse, skip and continue
                    continue;
                }
                USED_BOARD_CELLS[xPos][yPos] = horseIndex;/*ставим*/
            } finally {
                writeLock.unlock();
            }

            xPositions[horseIndex] = xPos;
            yPositions[horseIndex] = yPos;

            //System.out.println("Можно !  Передвигаем коня на "+ x1+" "+y1 +" ход "+ horseIndex);
            //printState();

            if (horseIndex <= BOARD_DIMENSION * BOARD_DIMENSION +1) {
                if (!tryHorse(horseIndex + 1)) {
                    //          logger.debug("Плохо !  Вынуждены убрать коня с USED_BOARD_CELLS={} y={} ", xPositions[horseIndex], yPositions[horseIndex]);
                    printState();

                    writeLock.lock();
                    try {
                        USED_BOARD_CELLS[xPositions[horseIndex]][yPositions[horseIndex]] = 0;
                    } finally {
                        writeLock.unlock();
                    }
                    //System.out.println("Плохо !   Вынуждены убрать коня "+ xPositions[horseIndex]+" "+yPositions[horseIndex] +" ход ");
                    xPositions[horseIndex] = 0;
                    yPositions[horseIndex] = 0;
                }
            }
        }

        depth--;

        return success;
    }



    public void printState() {

        System.out.println("Поток # "+ threadId);
        for (int x = 1; x <= BOARD_DIMENSION; x++) {
            for (int y = 1; y <= BOARD_DIMENSION; y++) {
                if (this.USED_BOARD_CELLS[x][y] > 0) {

                    System.out.print(this.USED_BOARD_CELLS[x][y]+" ");

                } else if (this.USED_BOARD_CELLS[x][y] < 0) {

                    System.out.print("B ");
                } else if (this.USED_BOARD_CELLS[x][y] == 0) {
                    System.out.print("0 ");
                }
            }
            System.out.println();
        }
        System.out.println();
    }

    public void run() {

//		 try{
        tryHorse(2);

//		 }catch(Exception e) {}

    }



Без обид но код я не понял, те если за 5 минут код непонятен то нет желания долго с ним копаться.

На просторах интернета нашел пример который делает перебор возможных позиций на доске для коня с заданной глубиной ходов. Код примитивный и понятный, немного его подправил (но не все). Сразу учитесь на хороших примерах и делайте тесты. Этот код написан понятно, изучите и делайте похожий на него код.На досуге можете сравнение в тестах улучшить (не печатать в строку) и попробовать деление на потоки с расшаренным ресурсом (сет с позициями и текущими ходами).

Основной класс.

Код: 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.
package knight;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

public class Knight {

    public static int boardSize = 8;

    static final int [] X_STEPS = {1, 2, 2, 1, -1, -2, -2, -1};
    static final int [] Y_STEPS = {2, 1, -1, -2, -2, -1, 1, 2};

    public Set<Position> getReachableSet(Position pos, int numberofMoves) {
        return getReachableSet(pos, numberofMoves, null);
    }

    protected Set<Position> getReachableSet(Position pos, int numberofMoves, Set<Position> reachableSet) {
        if(reachableSet == null) {
            reachableSet = new HashSet<>();
        }

        if (!reachableSet.contains(pos)) reachableSet.add(pos);

        if (numberofMoves == 0) return reachableSet;

        ArrayList<Position> moves = new ArrayList<>();

        for (int i = 0; i < 8; i++) {
            Position candidate = new Position (pos.x + X_STEPS[i], pos.y + Y_STEPS[i]);

            if (!moveIsPossible(candidate)) continue;

            if (!reachableSet.contains(candidate)) {
                moves.add(candidate);
            }
        }

        for (int j = 0; j < moves.size(); j++) {
            reachableSet = getReachableSet(moves.get(j), numberofMoves-1, reachableSet);
        }

        return reachableSet;
    }

    private static boolean moveIsPossible (Position pos) {
        return (pos.x >= 0 && pos.x <= 7) && (pos.y >= 0 && pos.y <= 7);
    }
}



Позиция, можно использовать что то готовое из awt пакета, там вроде был подобный класс. Для учебного процесса лучше свое написать
Код: 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.
package knight;


public class Position implements Comparable<Position> {
    /**
     * The row on the chess board
     */
    public int x;

    /**
     * The column on the chess board
     */
    public int y;

    /**
     * Create a new position object
     * @param x the row on the chess board
     * @param y the column on the chess board
     */
    public Position(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int compareTo(Position o) {
        if(x == o.x) {
            return Integer.compare(y, o.y);
        } else {
            return Integer.compare(x, o.x);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Position position = (Position) o;

        if (x != position.x) return false;
        return y == position.y;

    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }

    @Override
    public String toString() {
        return "{" + x + ", " + y + "}";
    }
}



На десерт, тест класс. Нужно его доработать, убрать сортировку и сделать сравнение коллекций покультурнее, без печати в строку

Код: 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.
package knight;


import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;

public class KnightTests {

    Knight knight;

    @Before
    public void setup() {
        knight = new Knight();
    }

    private String printSet(Collection<Position> positions)
    {
        StringBuffer s = new StringBuffer("\n  ");
        for (int x=0; x<Knight.boardSize; x++) {
            s.append(x);
        }
        s.append("\n  ");
        for (int x=0; x<Knight.boardSize; x++) {
            s.append("-");
        }
        s.append("\n");

        for (int y=0; y<Knight.boardSize; y++) {
            s.append(y).append("|");
            for (int x=0; x<Knight.boardSize; x++) {
                if (positions.contains(new Position(x, y))) {
                    s.append("X");
                } else {
                    s.append(" ");
                }
            }
            s.append("\n");
        }
        return s.toString();
    }

    private void compare(Set<Position> result, int[]... expected) {
        List<Position> orderedPositions = new ArrayList<>(result);

        Collections.sort(orderedPositions);

        ArrayList<Position> expectedList = new ArrayList<>(expected.length);
        for (int[] pos : expected) {
            expectedList.add(new Position(pos[0], pos[1]));
        }
        Collections.sort(expectedList);

        Assert.assertEquals(printSet(orderedPositions), expectedList.toString(), orderedPositions.toString());
    }

    @Test
    public void noHop() {
        Set<Position> result = knight.getReachableSet(new Position(4, 4), 0);
        int expected[][] = { { 4, 4 } };
        compare(result, expected);
    }

    @Test
    public void oneHop() {
        Set<Position> result = knight.getReachableSet(new Position(4, 4), 1);
        int expected[][] = { {2, 3}, {2, 5}, {3, 2}, {3, 6}, {4, 4}, {5, 2}, {5, 6}, {6, 3}, {6, 5} };
        compare(result, expected);
    }

    @Test
    public void oneHopCorner() {
        Set<Position> result = knight.getReachableSet(new Position(0, 0), 1);
        int expected[][] = { { 0, 0 }, { 1, 2 }, { 2, 1 } };
        compare(result, expected);
    }

    @Test
    public void twoHopsCorner() {
        Set<Position> result = knight.getReachableSet(new Position(0, 0), 2);
        int expected[][] = { { 0, 0 }, { 0, 2 }, { 0, 4 }, { 1, 2 }, { 1, 3 },
                { 2, 0 }, { 2, 1 }, { 2, 4 }, { 3, 1 }, { 3, 3 }, { 4, 0 },
                { 4, 2 } };
        compare(result, expected);
    }

    @Test
    public void threeHops() {
        Set<Position> result = knight.getReachableSet(new Position(4, 4), 3);
        int expected[][] = {
                {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7},
                {4, 5}, {4, 4}, {4, 7}, {4, 6}, {5, 0}, {5, 1}, {5, 2}, {5, 3}, {5, 4},
                {1, 0}, {1, 3}, {1, 4}, {1, 1}, {1, 2}, {1, 7}, {1, 5}, {1, 6}, {5, 7},
                {5, 6}, {5, 5}, {6, 0}, {6, 1}, {6, 4}, {6, 5}, {6, 3}, {2, 1}, {2, 0},
                {2, 7}, {2, 3}, {2, 4}, {2, 5}, {6, 7}, {7, 3}, {7, 4}, {7, 5}, {7, 6},
                {7, 0}, {7, 1}, {7, 2}, {3, 0}, {3, 2}, {3, 1}, {3, 7}, {3, 5}, {3, 6},
                {3, 3}, {3, 4}, {7, 7}, {4, 3}, {4, 2}, {4, 1}, {4, 0}
        };
        compare(result, expected);
    }

    @Test
    public void fourHops() {
        Set<Position> result = knight.getReachableSet(new Position(4, 4), 4);
        int expected[][] = { {0, 0}, {0, 1}, {0, 2}, {0, 4}, {0, 6}, {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6},
                {1, 7}, {2, 0}, {2, 2}, {2, 3}, {2, 4}, {2, 5}, {2, 6}, {2, 7}, {3, 1}, {3, 2}, {3, 3}, {3, 5}, {3, 6},
                {3, 7}, {4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {4, 5}, {4, 6}, {4, 7}, {5, 1}, {5, 2}, {5, 3}, {5, 4},
                {5, 5}, {5, 6}, {5, 7}, {6, 0}, {6, 2}, {6, 3}, {6, 4}, {6, 5}, {6, 6}, {6, 7}, {7, 1}, {7, 2}, {7, 3},
                {7, 5}, {7, 6}, {7, 7}
        };
        compare(result, expected);
    }
}
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39369857
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uid uniqueНа десерт, тест класс. Нужно его доработать, убрать сортировку и сделать сравнение коллекций покультурнее, без печати в строку


что этот тест класс делает ?
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39369865
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
uid uniqueЕсли будете делать перебор в нескольких потоках



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

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


что этот тест класс делает ?

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

статья для начанающих
https://habrahabr.ru/post/169381/

Сайт http://junit.org/junit4/

В примере вызов рекурсивный, коллекция передается как параметр но можно обращаться к ней как к полю.
По тест классу - iмейте в виду (в будущем) что запуск тест методов может делаться как из одного потока (последовательно) так и параллельно, поэтому расшаренные статические ресурсы в тест классе делать нежелательно (лочить придется). Тест методы должны быть thread safe (поддерживать многопоточность)

Поставьте простой мавен проект и работайте в нем, будет проще прогонять тесты и тд
http://www.apache-maven.ru/
https://habrahabr.ru/post/77382/

Учитесь сразу делать правильно, нет ничего затратнее чем переучивание в будущем (двойная работа).
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39370383
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonandron81зачем ? в чем выигрыш ?
Это мой старый добрый рефакторинг который я юзаю уже много лет.
В основном он эффективен в растровой графике. Задавать картинку
и работать с ней удобнее через int[] rgbColors чем через int[][] rgbColors.
Так скорость выше. Это я знаю еще со времен С++. В некоторых случаях
длину строки выравнивают на число байт кратных машинному WORD
процессора. Типа padding строки. Плюс есть еще много нюансов
связанных с тем как аллокатор int[][] размещает суб-массивы в куче.
При удачном стечении обстоятельств (обходим массив слева направо
и сверху вниз) канал памяти получает тразнакции чтения по линейным
адресам. Это благоприятный кейс. Но возможно будет и не-благоприятный.

Когда я задаю матрицу или куб (или гиперкуб) через линейный массив
то я сам вручную обеспечиваю линейный порядок доступа к элементам
памяти.

Некий господин выше не поленился и даже привел бенчмарк с использованием JMH
и с прогревом компиллятора как положено. Что-ж. Я не буду с ним спорить.
Мои последние бенчмарки я делал еще во время JDK6 а тогда
и деревья были выше и оптимизатор был попроще.

Возможно сейчас и нет острой необходимости выключать int[][] но я
лишний раз замечу что наша задача выгодно отличается от других.
У нас - квадратное поле (а не зубчатое) и ширина строки заведомо известна.



ну понял вас.
по самому алгоритму всё же неясность. Вы говорите , что как-то удавалось получать решения (видимо используя поточную технологию) . бродить по возможным ходам вы предлагаете случайно, а вот Варнсдорф предлагает брать сначала ветки с наименьшим кол-вом ходов и довольно успешный метод (проверял), в любом случае выходим на уровень выше в случае исчерпания.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39370634
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron81ну понял вас.
по самому алгоритму всё же неясность. Вы говорите , что как-то удавалось получать решения (видимо используя поточную технологию) . бродить по возможным ходам вы предлагаете случайно, а вот Варнсдорф предлагает брать сначала ветки с наименьшим кол-вом ходов и довольно успешный метод (проверял), в любом случае выходим на уровень выше в случае исчерпания.
Так. Стоп-машина. Давай вернемся в самое начало. Я не знаю алгоритма Варнсдорфа. Но мне это и не важно.
Я утверждаю. Что почти все (99.9%) алгоритмов поиска в шахматах можно запускать параллельно.
Отсюда мы имеем в нашем топике 4 возможных варианта реализации.

1. Обычный (он-же - "поиск в глубину")
2. Варнсдорф.
3. Обычный многопточный (при условии что все потоки старуют из одной точки A1)
4. Варнсдорф многопоточный (при условии что все потоки старуют из одной точки A1)

Ты согласен этим?
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39370691
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonandron81ну понял вас.
по самому алгоритму всё же неясность. Вы говорите , что как-то удавалось получать решения (видимо используя поточную технологию) . бродить по возможным ходам вы предлагаете случайно, а вот Варнсдорф предлагает брать сначала ветки с наименьшим кол-вом ходов и довольно успешный метод (проверял), в любом случае выходим на уровень выше в случае исчерпания.
Так. Стоп-машина. Давай вернемся в самое начало. Я не знаю алгоритма Варнсдорфа. Но мне это и не важно.
Я утверждаю. Что почти все (99.9%) алгоритмов поиска в шахматах можно запускать параллельно.
Отсюда мы имеем в нашем топике 4 возможных варианта реализации.

1. Обычный (он-же - "поиск в глубину")
2. Варнсдорф.
3. Обычный многопточный (при условии что все потоки старуют из одной точки A1)
4. Варнсдорф многопоточный (при условии что все потоки старуют из одной точки A1)

Ты согласен этим?

согласен.
1. - работает крайне очень медленно. терпения дождаться хотя бы одного решения не хватает.
2. - вышло .
3. - вот этот хочу реализовать.
Вы тут предлагаете поиск в глубину используя потоки ?
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39370698
andron81
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron81,

тогда как будем строить алгоритм ?
допустим у нас 8 потоков в каждом свой массив с полем - x[].
предположим мы находимся в одной из вершин как Вы предлагаете будем двигаться от ветки к ветке ? Выше обсуждалось , что будем случайно выбирать по какой ветке двигаться .
На уровень выше переходим только в случае исчерпания веток куда можно ступить или же плюс к этому на уровень выше делаем тоже как возможный 9-ый ход кот тоже может выбраться случайно ?
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39370749
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron813. - вот этот хочу реализовать.
Вы тут предлагаете поиск в глубину используя потоки ?
Я предлагаю еще раз описать условие задачи (новое условие). Потому-как я и другие мемберы не понимают
конечную цель.

Типа:
Код: java
1.
2.
3.
4.
5.
Реализовать мультипоточный алгоритм Варнсдорфа. Исходные данные. N - количество потоков,
M - минимальное число маршрутов коня которые нужно найти. Стартовая координата - A1 
для всех маршрутов.

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

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

Формулирую.

Реализовать мультипоточный (4 - потока = const) алгоритм методом обхода в глубину .
Исходные данные:
4 потока(константа) - задано жестко в программе.
M - минимальное число маршрутов коня которые нужно найти.
i,j - стартовая точка.

M,i,j - задаются в виде аргументов командной строки.
...
Рейтинг: 0 / 0
рекурсивная функция делает переполнение кучи.
    #39371078
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andron81, надо написать полное условие задачи в т ч что речь идёт о шахматном коне
...
Рейтинг: 0 / 0
25 сообщений из 132, страница 5 из 6
Форумы / Java [игнор отключен] [закрыт для гостей] / рекурсивная функция делает переполнение кучи.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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