Заливка через узел поиска в глубину, связывающийся сам с собой. С++

Работа над программой решения задачи заливки:

Я считаю, что я до одного последнего вопроса. Моя структура данных выглядит следующим образом: у меня есть вектор указателей узлов, и каждый узел содержит массив целых чисел и адрес следующего узла. При тестировании все работает исправно. Цель этой структуры данных состоит в том, чтобы в основном функционировать как список смежности. Где каждый узел связан с узлами, с которыми у него будет ребро.

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

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

Извините, если это немного запутанно. Любая помощь будет принята с благодарностью.

p.s. Я знаю, что есть лучшие способы решить эту проблему, такие как BFS, я бы хотел придерживаться DFS.

#ifndef _POURINGLIST_H_
#define _POURINGLIST_H_
#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
 struct Node{
    int state[3];
    Node* next = NULL;
  };
class PouringList{
  Node* init;
  vector<Node*> Head;
  int max[3];
  int steps;
public:
  PouringList(){
    //max values for comaprison
    max[0] = 10;
    max[1] = 7;
    max[2] = 4;
    //init values to begin DFS
    init = new Node;
    init->state[0] = 0;
    init->state[1] = 7;
    init->state[2] = 4;
  };
//private methods not to be called by user
private:
  //pours some good old h2o
  Node pour(Node* curr_state, int A, int B){
    int a = curr_state->state[A];
    int b = curr_state->state[B];
    int change = min(a, max[B]-b);
    Node newState = *curr_state;
    newState.state[A] = (a-=change);
    newState.state[B] = (b+=change);
    return newState;
  }
  //O(n) complexity used to check if a node is already in head 
  bool isIn(Node* find_me){
    for(vector<Node*>::iterator i = Head.begin(); i != Head.end(); i++) {
      if (equal(begin(find_me->state), end(find_me->state), begin((*i)->state)))
        return true;
      }
    return false;
  }
  void printNode(Node* print){
    for(int i = 0; i < 3; i++){
      cout << print->state[i] << " ";
    }
    cout << endl;
  }

  int locate(Node* find_me){
    for(vector<Node*>::iterator i = Head.begin(); i != Head.end(); i++) {
      if (equal(begin(find_me->state), end(find_me->state), begin((*i)->state)))
        return distance(Head.begin(), i);
      }
    return -1;
  }
  void LinkState(Node* head, Node * nxt){
    Node* vert = Head[locate(head)];
    while(vert->next != NULL){
      vert = vert->next;
    }
    vert->next = nxt;
  }
public:
  void DFS(){
    steps = 0;
    //start exploring at initial value
    explore(init);
  }
  void explore(Node* vertex){
    //base case to end
    if(!isIn(vertex)){
      Head.push_back(vertex);
      if(vertex->state[1] == 2 || vertex->state[2] == 2){
        cout << steps << endl;
        printNode(vertex);
        return;
      }
      //generate all possible states and connects them to Head vertex
      else{
        for(int i = 0; i < 3; i++){
          for(int j = 0; j < 3; j++){
            Node conn1 = pour(vertex,i,j);
            Node *conn = &conn1;
            if(i!=j && !isIn(conn)){
              cout << i << " adds water to " << j << endl;
              LinkState(vertex, conn);
            }
          }
        }
      }

      Node* Nextex = vertex;
      //printNode(vertex);
      while(Nextex != NULL){
        //new neighbor
        if(!isIn(Nextex)){
          //printNode(Nextex);
          explore(Nextex);
        }
        Nextex = Nextex->next;
      }
    }
        //printNode(Nextex);
    else{
      cout <<"Dead end" << endl;
    }
  }

  //start from init node and show path to solution
  void display(){
    Node *output;
    for(int i = 0; i < Head.size(); i++){ 
      output = Head[i];
      while ( output != NULL){
        printNode(output);
        output = output->next;
      }
      cout << '#'  <<endl;
    }
  }
};
#endif  // _POURINGLIST_

основной драйвер:

#include "PouringList.h"
int main(){
    PouringList s1;
    s1.DFS();

}

Изменить

Я пробовал предложенное исправление раньше (это то, что я предполагаю, что вы имеете в виду). Это по-прежнему приводит к тому, что программирование работает вечно. Кроме того, я недостаточно знаю о смартпойнтах, чтобы пойти и пересмотреть приложение!

Node conn1 = pour(vertex,i,
Node *conn = new Node;
conn = &conn1;

person Deandre Yuself Bauswell    schedule 11.03.2017    source источник


Ответы (1)


Вы сохраняете адрес локальной переменной в своем списке.

В explore у вас есть

        Node conn1 = pour(vertex,i,j);
        Node *conn = &conn1;

затем позже передайте conn в LinkState, который сохранит этот указатель в вашем PouringList. Все добавленные вами узлы будут указывать на один и тот же адрес памяти.

Что вы должны делать, так это выделять новый Node и использовать его (предпочтительно использовать какой-то умный указатель, а не хранить необработанные указатели, чтобы очистка происходила автоматически).

person 1201ProgramAlarm    schedule 11.03.2017
comment
@DeandreYuselfBauswell Нет, это ничего не улучшает. Вместо conn = &conn1 используйте *conn = conn1, что скопирует conn1 в новый узел. (Или избавиться от conn1 и получить *conn = pour(vertex, i, j) после выделения узла для conn). - person 1201ProgramAlarm; 11.03.2017
comment
Я понимаю! предложенная модификация сделана. Теперь получаю бесконечную рекурсию в функции исследования, что намного лучше, чем то, где я был. Спасибо. - person Deandre Yuself Bauswell; 11.03.2017