Я работал над проектом, который, вкратце, сгенерирует двумерную матрицу чисел, где «пустые» пробелы будут представлены нулями. Каждый номер связан списком узлов. Узлы содержат значение числа, положение X и Y числа и список всех пространств, прилегающих к нему (его «соседей»), за исключением пространств, диагонально смежных с точкой, поскольку алгоритм допускает только перемещения вверх вниз, влево и вправо. Проблема, с которой я столкнулся, заключается в том, что, как следует из названия, у меня возникают некоторые проблемы переполнения стека. Я опубликую свой код ниже, если кто-то может помочь, я был бы очень признателен.
CoordList* Puzzle::GeneratePath(CoordList* Path, int GoalX, int GoalY)
{
int CurrX;
int CurrY;
CurrX = Path->NeighborX;
CurrY = Path->NeighborY;
if(CurrX == GoalX && CurrY == GoalY)
{
return(Path);
}
else
{
int NewX;
int NewY;
double NewDistance;
int OldX;
int OldY;
double OldDistance;
CoordList* PointNeighbors = NULL;
CoordList* BestChoice = NULL;
for(int i = 0; i < NumDirections; i++)
{
CoordList* NewNeighbor = new CoordList;
NewX = CurrX + DirectsX[i];
NewY = CurrY + DirectsY[i];
if(IsPossible(NewX, NewY))
{
NewNeighbor->NeighborX = NewX;
NewNeighbor->NeighborY = NewY;
if(PointNeighbors == NULL)
{
NewNeighbor->next = NULL;
PointNeighbors = NewNeighbor;
}
else
{
NewNeighbor->next = PointNeighbors;
PointNeighbors = NewNeighbor;
}
}
//delete NewNeighbor;
}
while(PointNeighbors != NULL)
{
if(BestChoice == NULL)
{
CoordList* AChoice = new CoordList;
AChoice->next = NULL;
NewX = PointNeighbors->NeighborX;
NewY = PointNeighbors->NeighborY;
AChoice->NeighborX = NewX;
AChoice->NeighborY = NewY;
BestChoice = AChoice;
PointNeighbors = PointNeighbors->next;
//delete AChoice;
}
else
{
NewX = PointNeighbors->NeighborX;
NewY = PointNeighbors->NeighborY;
NewDistance = DetermineDistance(NewX, NewY, GoalX, GoalY);
OldX = BestChoice->NeighborX;
OldY = BestChoice->NeighborY;
OldDistance = DetermineDistance(OldX, OldY, GoalX, GoalY);
if(NewDistance < OldDistance)
{
BestChoice->NeighborX = NewX;
BestChoice->NeighborY = NewY;
}
PointNeighbors = PointNeighbors->next;
}
}
BestChoice->next = Path;
Path = BestChoice;
return(GeneratePath(Path, GoalX, GoalY));
}
}
Меня попросили предоставить мою функцию определения расстояния. Это просто простая реализация традиционной формулы расстояния до точки. Предоставлено ниже.
double Puzzle::DetermineDistance(int OneX, int OneY, int TwoX, int TwoY)
{
int DifX;
int DifY;
double PointSum;
DifX = (TwoX - OneX);
DifY = (TwoY - OneY);
DifX = (DifX * DifX);
DifY = (DifY * DifY);
PointSum = (DifX + DifY);
return (sqrt(PointSum));
}
Ниже приведена функция IsPossible, которая определяет, находятся ли значения X и Y в пределах возможного пространства сетки.
bool Puzzle::IsPossible(int x, int y)
{
if(x + 1 > Size - 1 || x - 1 < 0
|| y + 1 > Size - 1 || y - 1 < 0)
{
return false;
}
return true;
}
У вас может быть бесконечный цикл рекурсии, который вызывает переполнение стека, поскольку вы создаете новые локальные переменные при каждой рекурсии, особенно с вашим наблюдаемым поведением колебаний. Я предполагаю, что у вас нет этой проблемы с маленькими матрицами. Это просто выстрел в темноте 🙂
Проблема колебаний показывает, что вы не проверяете, были ли вы уже на одном месте?
В любом случае, может быть, вы хотите пересмотреть, используя другой алгоритм поиска пути. Я бы предложил решение на основе агента. Я использовал следующее решение для решения лабиринта аналогичной структуры: я запустил агент с «PositionsList» точек, где он был, поэтому в начале только с начальной точки. Затем он копировал себя в каждую достижимую позицию, не находящуюся в его собственном PositionList, добавляя новую позицию в этот список и уничтожая себя. Повторяйте этот шаблон со всеми новыми агентами, пока первый агент не достигнет цели. Таким образом, вы гарантированно найдете оптимальный путь. Но для больших матриц это может привести к большой памяти, особенно когда есть много разных способов добраться до цели и много возможных направлений на позицию! Но есть множество других очень хороших алгоритмов поиска пути. Может быть, один из них вам подходит 🙂
Удачи!
Других решений пока нет …