Search code examples
c++graphlinked-listdepth-first-searchadjacency-list

Pouring via Depth First Search node linking to itself. C++


Working on a program to solve the pouring problem:

I believe I am down to one last issue. My data structure is as follows: I have an vector of Node pointers and each node contains a int array, and an address to the next node. In testing everything functions properly. The goal of this data structure is to basically function as an adjacency list. Where each node is linked to the nodes that it would have an edge to.

Currently my problem is when I am attempting to link these nodes to one another: the LinkState function that I have should accomplish this, however it is instead resulting in the program running...forever.

The function should simply iterate through the individual nodes linked list and find where to connect the new node. Instead it is causing a node to constantly be leak to itself..which is leading to the runtime issue.

Sorry if this is a bit confusing. Any help would be greatly appreciated.

p.s. I know there are better ways to solve this problem like BFS, I'd like to stick to 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_

basic driver:

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

}

Edit

I've attempted the suggested fix before (This is what I'm assuming you mean). It still lead to the programming running forever. Also I do not know enough about smartpointers to go and overhaul the application!

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

Solution

  • You are storing the address of a local variable in your list.

    In explore, you have

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

    then later pass conn to LinkState, which stores that pointer in your PouringList. All your added nodes will point at the same memory address.

    What you should be doing is allocating a new Node and using that (preferably using some sort of smart pointer rather than storing raw pointers so the clean up will happen automatically).