Sorry for the code dump
The code is being typed into a command line.
Graph.cpp
#ifndef GRAPH_CPP
#define GRAPH_CPP
#include <map>
#include <set>
#include <queue>
#include "Graph.h"
#include <iostream>
using namespace std;
template <typename T>
Graph<T>::Graph(){
}
//check if an edge exists between v and w
template <typename T>
bool Graph<T>::hasEdge(T v, T w) const
{
if (adjMap.find(v) == adjMap.end())
return false;
if (adjMap.at(v).find(w) != adjMap.at(v).end())
return true;
else
return false;
}
template <typename T>
void Graph<T>::addEdge(T v, T w) {
adjMap[v].insert(w);
adjMap[w].insert(v);
}
template <typename T>
int Graph<T>::BFS(T s, T t, map<T,int>& distance, map<T,T>& go_through) const
{
if (adjMap.find(s) == adjMap.end() || adjMap.find(t) == adjMap.end())
{
cout << "Invalid source vertex or/and destination vertex!" << endl;
return INVALID_VERTEX;
}
//Mark all the vertices with current distance to s: -1
for (auto it = adjMap.begin(); it != adjMap.end(); it++) {
distance[it->first] = NOPATH;
}
//Create queue for bfs
queue<T> bfs;
bfs.push(s);
//mark distance from source s to s:0
distance[s] = 0;
//mark shortest path to given source s going through s
go_through[s] = s;
T current = bfs.front();
while (!bfs.empty() && current != t) {
current = bfs.front();
set<T> adjVertices = adjMap.at(current);
for (auto i = adjVertices.begin(); i != adjVertices.end(); i++) {
if (distance[*i] == NOPATH) {
distance[*i] = distance[current] + 1;
go_through[*i] = current;
bfs.push(*i);
}
}
bfs.pop();
}
return distance[t];
}
#endif
Graph.h
#ifndef GRAPH_H
#define GRAPH_H
#include <map>
#include <set>
 
using namespace std;
 
const int NOPATH = -1;
const int INVALID_VERTEX = -2;
template <class T>
class Graph
{
   public:
    // default constructor
    Graph();
    
    // to check if an edge exists between v and w
    bool hasEdge(T v, T w) const;  
    
    // to add an edge beween v and w to the graph
    void addEdge(T v, T w);
    // Apply BFS traversal to find the shortest path from the given source s to destination t
    // return the distnace from s to t
    // if s or t does not exist, return INVALID_VERTEX (=-2) 
    // if there is no path from s to t, return NOPATH (=-1)
    // store the shortest path distance from the given source s  to vertex w in distance map<w, distance>
    // store which next vertex to go through on the shortest path to the given source s in go_through map<w, v>. 
    // Here a pair <w, v> in go_through map represents on the shortest path from w to the given source s, it needs to take the path: w-->v...-->s  
    int BFS(T s, T t, map<T, int>& distance, map<T, T>& go_through) const;
   
   private:    
    //represent the mapping from a Vertex, say u (key) to a set of vertices (value) which directly connect to u 
    map<T, set<T> > adjMap;        
};
#endif   /* GRAPH_H */
PA3Part2.cpp
#include <vector>
#include <iostream>
#include <string>
#include <fstream>
#include <stack>
#include <algorithm>     // for transform() function
#include "Graph.h"
using namespace std;
// declare global variable (constant only)
const int ARGUMENTS = 2;   // define the required command line arguments
// define a function to decide the collection of edges for a graph
// using "Word Buckets Approach"
Graph<string> WordBuckets_addEdges(const vector<string>& words);
int main(int argc, char* argv[])
{
    // Check whether the number of command line arguments match the required one 
    if (argc != ARGUMENTS)
    {
        cout << "Warning: need exactly " << ARGUMENTS-1 << " command line argument." << endl;
        cout << "Usage: " << argv[0] << " inputfile_name" << endl;
        return 1;
    }
    ifstream in_file;
    in_file.open(argv[1]);
    // Check whether the input file can be open successfully or not
    if (!in_file.good())
    {
        cout << "Warning: cannot open file named " << argv[1] << "!" << endl;
        return 2;
    }
    
    // Read data from the input file, assume "good data" from the input file
    // each line of the input file constains one word from English dictionary
    string word;
    vector<string> words;
    while (in_file >> word)
    {
        // convert word to all lower-case letters
        // if assume that each word from the input file is in lower-case letters, this step can be ignored
        transform(word.begin(), word.end(), word.begin(), ::tolower);
        words.push_back(word);
    }
    // close the input file
    in_file.close();
    // build the graph based on the collection of words
    // each word in the collection represents a Vertex in the graph
    // there is an edge from one word to another if these two words are only different by a single letter
    Graph<string> wordsG = WordBuckets_addEdges(words);
    string word1, word2;
    while (true)
    {
        cout << endl << endl;
        cout << "Welcome to CS216 Word Ladder!" << endl;
        cout << "Please give me two English words, and I will convert the first into the second by modifying one letter at a time." << endl;
        cout << "For the Demo purpose, let us try four-letter words only." << endl;
        cout << "Please type the FIRST four-letter word (or type Enter to quit): " << endl;
        getline(cin, word1);
        
        if (word1 == "")
            break;
        
        cout << "Please type the SECOND four-letter word (or type Enter to quit): " << endl;
        getline(cin, word2);
        
        if (word2 == "")
            break;
        // convert both word1 and word2 to all lower-case letters
        transform(word1.begin(), word1.end(), word1.begin(), ::tolower);
        transform(word2.begin(), word2.end(), word2.begin(), ::tolower);
        map<string,int> distance;
            map<string, string> go_through;
        int dis = wordsG.BFS(word1, word2, distance, go_through);
        // Display the ladder distance from word1 to word2
        // Display the shortest path on the word ladder from word1 to word2
        // the ladder distance is defined as the number of edges on the shortest path from one vertex to another
        // the ladder distance of the same vertex to itself is 0 
        // if word1 and word2 are the same word, your program should display "Two words should be different." 
        // there is no path from word1 to word2 if its ladder distance is -1
        // there is no path from word1 to word2 if its ladder distance is -2, which means either word1 or/and word2 is invalid
        if ( dis == NOPATH || dis == INVALID_VERTEX)
            cout << "There is no path from [" << word1 << "] to [" << word2 << "]" << endl;
        else if ( dis == 0)
        {
            cout << "Two words should be different." << endl;
        }
        else
        {
            cout << "The ladder distance from [" << word1 << "] to [" << word2 << "] is " << dis << "-step away." << endl;
            cout << "A ladder from [" << word1 << "] to [" << word2 << "]:" << endl;
        string nextVertex = word2;
            cout << word2;
            while (go_through[nextVertex] != word1)
            {
                cout << " ---> " << go_through[nextVertex];
                nextVertex = go_through[nextVertex];
            }
            cout << " ---> " << word1 << endl;
        }
    }
    cout << "Thank you for using this program, bye..." << endl;
    return 0;
}
/* define a function to decide the collection of edges for a graph
 * using "Word Buckets Approach"
 * Purpose: build a graph based on the collection of vertices
 *          each word stored in the vector, represents a Vertex in the graph
 *          there is an edge from one word to another 
 *          if these two words are only different by a single letter
 *@param words vector<string>: representing the collection of vertices, each string stored in the vector forms a vertex
 *@return Graph<string>: representing the graph built by
 *                       (1) the collection of vertices from words;
 *                       (2) the collection of edges are decided by if any two words are only different by a single letter
 *                         e.g. there is an edge between "cool" and "pool", but there is no edge between "cool" and "poll"
 *
 */
Graph<string> WordBuckets_addEdges(const vector<string>& words)
{    
    // build the graph
    // there is an edge from one word to another if the two words are only different by a single letter.
    // use "Word Bucket" solution described in Lab11 to efficiently decide whether an edge between two vertices
    Graph<string> wordsG;
    
    // provide your code here 
    // implement "Word Buckets Approach" to decide if you need to call addEdge() member function between two vertices
    map<string, vector<string> > bucket;
    for (int i = 0; i < words.size(); i++) {
        for (int j = 0; j < words[i].length(); j++) {
            string key = words[i];
            key[j] = '?';
            bucket[key].push_back(words[i]);
        }
    }
    for (auto k = bucket.begin(); k != bucket.end(); k++) {
        for (int s = 0; k->second.size(); s++) {
            for (int m = 0; m<k->second.size(); m++) {
                if (k->second[s] != k->second[m]) {
                    wordsG.addEdge(k->second[s],k->second[m]);
                }
            }
        }
    }
    return wordsG;
}
So after I completed the code and fixed all the errors, I tried compiling PA3Part2.cpp and Graph.cpp together into an executable program, which gave me this error below.
Error when attempting to compile:
/usr/bin/ld: /tmp/ccHsDrH9.o: in function main': PA3Part2.cpp:(.text+0x4ef): undefined reference to Graph<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >::BFS(std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::map<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, int, std::less<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, std::allocator > const, int> > >&, std::map<std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::less<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, std::allocator > const, std::__cxx11::basic_string<char, std::char_traits, std::allocator > > > >&) const' /usr/bin/ld: /tmp/ccHsDrH9.o: in function WordBuckets_addEdges(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&)': PA3Part2.cpp:(.text+0x9f0): undefined reference to Graph<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >::Graph()' /usr/bin/ld: PA3Part2.cpp:(.text+0xcca): undefined reference to `Graph<std::__cxx11::basic_string<char, std::char_traits, std::allocator > >::addEdge(std::__cxx11::basic_string<char, std::char_traits, std::allocator >, std::__cxx11::basic_string<char, std::char_traits, std::allocator >)' collect2: error: ld returned 1 exit status
I'm stuck on what to do here, please help and thank you.
I recall having this problem before and not having as much trouble as I am with this.
