0

Basically I am making a graph that represents movie data. I have a class called Vertice and a class called Actor. Vertice contains a vector of Actors and in my main function I have a vector of Vertices which is the graph.

Basically, as I parse through the movie data file my code is working properly and storing neighborhood size. However, once I exit the initial while loop that goes through the data file, all the information about neighbors and neighborhood size is getting lost. I am not resetting anything and I am not sure why this is happening.

I have a function called addToNeighborhood that adds a new actor to a neighborhood and this is where neighborhood size gets increased. As a test, I called addToNeighborhood on a random neighborhood once I was outside of the while loop. Now, this particular actor's neighborhood size was 2 inside the while loop. Then when I inserted a random name to it's neighborhood outside the while loop it returned that it's size was 1, showing that it reverted back to zero for some reason outside the while loop.

I wouldn't normally ask about something so specific as this but I've been trying to find the problem all day and I think maybe I am just understanding vectors incorrectly or something.

Image of output

#include <iostream>
#include <fstream>
#include "ctype.h"
#include <string>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <stack>
#include <queue>
#include <unordered_map>
using namespace std;

class Actor
{
public:
    int name; 
    string nameStr; 
    string title; 
};

class Vertice 
{
    public: 
    string name; 
    int neighborhood_size; 
    vector<class Actor> neighborhood; 
    void printNeighborhood(); 
    void addToNeighborhood(int, string, string);    
};


void Vertice::addToNeighborhood(int actor_name, string actor_string, string movie_title)
{
    Actor to_add; 
    to_add.name = actor_name; 
    to_add.title = movie_title; 
    to_add.nameStr = actor_string; 
    neighborhood.push_back(to_add); 
    neighborhood_size++; 

    Actor print = neighborhood.back(); 

    cout << "Just added " << print.nameStr << " to " << name << "'s neighborhood.\n"; 
    cout << "The size of the neighborhood is now: " << neighborhood_size << ".\n\n"; 
}

void Vertice::printNeighborhood()
{

    cout << "The neighborhood of " << name << " is: ";
    for(int j = 0; j < neighborhood_size; j++)
    {
         cout << (neighborhood[j]).nameStr << " ";  
    }
}




int main(int argc, char** argv)
{ 
    ifstream data_dump; 
    data_dump.open("cleaned.txt");

    string line;
    char *buffer, *piece; 
    string actor; 

    vector<class Vertice> myGraph; 
    vector<string> nameArray; 
    queue<int> Q; 
    unordered_map<string, int> actorMap; 
    int actor_count = 0; 
    int loop_count = 0; 
    string movie_title; 

    while(getline(data_dump, line)) { // each line of movie file
        buffer = strdup(line.c_str());
        piece = strtok(buffer, " "); 
        movie_title = piece; // get the first token, that is the movie title
        piece = strtok(NULL, " "); // get the next token, that will be first actor     
        while (piece != NULL) { // while more actors to get
            actor = piece; //string name of actor
            if (actorMap.find(actor) == actorMap.end()) { // we haven't seen this actor before
                // add to the map
                // add to the graph
                // add to nameArray
                // increment total actors 
            }
             int to_queue = actorMap[actor]; 
             Q.push(to_queue); 
             loop_count++; // actors in just this movie
             piece = strtok(NULL, " "); // grab the next actor
        } 
        //second pass through updates neighborhoods
        for(int i=0; i < loop_count; i++) {
            int top = Q.front(); 
            Q.pop(); 
            Vertice to_update = myGraph[top]; 
            for (int j = 0; j < loop_count-1; j++) {
                int next = Q.front(); 
                // add next to top's neighborhood
                // enqueue next back into Q
            }
            Q.push(top); 
        }   

         while (!Q.empty()) Q.pop(); // make Q empty 
         loop_count = 0; 
    } // go on to the next line of the movie file

 // just printing a random neighborhood to test
 Vertice temp = myGraph[0]; 
 temp.printNeighborhood(); 

}
amandaraen
  • 23
  • 5
  • just added includes, I'll add in a printNeighborhood too, had that coded up already but it doesn't seem to work – amandaraen Mar 06 '20 at 23:09
  • Save yourself a lot of nuisance and replace the `strdup` and `strtok` with a [`std::stringstream`](https://en.cppreference.com/w/cpp/io/basic_stringstream). [Option 2 of this answer](https://stackoverflow.com/a/7868998/4581301) shows how to do that. – user4581301 Mar 06 '20 at 23:11
  • Thanks for the updates. – user4581301 Mar 06 '20 at 23:11
  • thank you for your help! just added printNeighborhood @user4581301 – amandaraen Mar 06 '20 at 23:12
  • There should be no need for `neighborhood_size`. `neighborhood` is a vector, and you can get the size of a vector with its `size` method. Often it's better to use a range-based for loop: `for (const auto & val: neighborhood) { cout << val << " "; }`. the `const auto & val` means "Give me a reference to whatever is in `neighborhood`. I promise not to change it." – user4581301 Mar 06 '20 at 23:24
  • Not sure what you mean to do here: `actorMap[actor] = actor_count;`. Each actor has a mapped unique number? – user4581301 Mar 06 '20 at 23:26
  • @user4581301 yes actorMap takes a string as a key and returns an int that is specific to that actor. Initially I was using the size method instead of neighborhood_size. I was still having this problem though so I added neighborhood_size just to try and see if that would fix the problem – amandaraen Mar 06 '20 at 23:35
  • that line actorMap[actor] = actor_count; is just inserting the new actor into the map – amandaraen Mar 06 '20 at 23:36
  • @user4581301 later I am going to use the graph to output a shortest path between two actors using Breadth First Search, that is why I want to have an integer associated with the actor names. makes it easier for me to be like destination, pred[destination], pred[pred[destination]]....source later – amandaraen Mar 06 '20 at 23:50
  • That's what I figured. Just didn't want to waste time running down a bad path. – user4581301 Mar 06 '20 at 23:59
  • Note: the `strdup`s are dynamically allocating arrays that are never `free`ed, so they are doing more damage than simply complicating the code. – user4581301 Mar 07 '20 at 00:42

1 Answers1

0

In

Vertice to_update = myGraph[top]; 

to_update is a copy of the Vertice in myGraph. That means

to_update.addToNeighborhood(next, nameArray[next], movie_title); 

updates a copy not the original in the graph, and the copy is discarded after it has been fully updated with the new actors from the movie. Since the graph is not updated, nothing changes and the compiler will discard all of this code for a huge performance gain.

Vertice &to_update = myGraph[top]; 

Will fix that by taking a references to the Vertice in the graph.

Note: You may still have a problem as there is no code to prevent an actor in the neighborhood from being added again.

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • thank you! yes this fixed the problem I actually want actors to be added to neighborhood again with different movie titles if that actor has acted in different movies with the same Vertice At least I think that is how I will want the logic to work later on. Am still working through everything. This helps so much though ty! – amandaraen Mar 07 '20 at 01:23