/* * graphShell.cpp * * (c) 2004 Daniel Jackson. * CIS 11 Data Structures & Algorithms * Class Invariant: notDone is true until user chooses quit. Then it is false, and the menu quits. graphExists is true while myGraph points to a graph. is false while myGraph does not point to a graph. Used to track creation and deletion. Also to ensure member functions are not called while there is no graph. myGraph is a pointer to the graph currently being tested. void DoMenu(); Runs a menu for the graph class. Displays the menu, then performs the operation chosen. void PrintMenu(); Prints out a menu. void DijkstraAlgorithm(std::size_t start); Runs a menu based test of the Dijkstra class, which implements Dijkstra's Algorithm. bool noGraph(); Postcondition: Returns true and displays an error message if there is no graph currently. Returrns false if there is a graph. */ #include <iostream> // Provides cout and cin #include <cctype> // Provides tolower() #include <iomanip> // Provides setw() #include <string> // Provides string #include <fstream> // Provides ifstream #include <vector> // Provides vector #include "Dijkstra.h" // Provides Dijkstra template <class Item> graphShell<Item>::graphShell() { notDone = true; graphExists = false; PrintMenu(); while (notDone) DoMenu(); if (graphExists) delete myGraph; } template <class Item> void graphShell<Item>::PrintMenu() { std::cout << "Please make a choice:" << std::endl << " n - Make a new graph" << std::endl << " d - Delete the current graph" << std::endl << " p - Print the current graph" << std::endl << " l - Load a graph from a file" << std::endl << " f - Save the graph to a file" << std::endl << " ** Filename for both is theFile.txt." << std::endl << " v - Add a Vertex" << std::endl << " e - Add an Edge" << std::endl << " x - Remove an Edge" << std::endl << " r - Resize the graph" << std::endl << " s - Show the size of the graph" << std::endl << " b - Display the neighbors" << std::endl << " g - Get a vertex" << std::endl << " c - Change a vertex" << std::endl << " a - Dijkstra's Algorithm" << std::endl << " q - Quit" << std::endl << " ? - Print this menu again" << std::endl << std::endl; } template <class Item> void graphShell<Item>::DoMenu() { char choice; int integer; std::ifstream infile; std::ofstream outfile; std::size_t vertices, i, j; Item nothing, label; std::set<std::size_t> theSet; std::set<std::size_t>::iterator theIterator; std::cout << "Which choice? "; std::cin >> choice; choice = std::tolower(choice); switch (choice) { case 'n': std::cout << "How big do you want the graph's initial capacity (0 or negative for default): "; std::cin >> integer; if (graphExists) delete myGraph; if (integer > 0) myGraph = new graph<Item>(integer); else myGraph = new graph<Item>; graphExists = true; break; case 'd': if (noGraph()) break; delete myGraph; graphExists = false; std::cout << "The graph has been deleted." << std::endl << std::endl; break; case 'p': if (noGraph()) break; for (i = 0; i < myGraph->size(); ++i) { std::cout << std::setw(2) << i; for (j = 0; j < myGraph->size(); ++j) { std::cout << setw(4) << myGraph->EdgeWeight(i, j); } std::cout << endl; } break; case 'l': if (noGraph()) break; infile.open("theFile.txt"); if (infile) { infile >> vertices; for (i = 0; i < vertices; ++i) { myGraph->AddVertex(nothing); } for (i = 0; i < vertices; ++i) { for (j = 0; j < vertices; ++j) { infile >> integer; if (integer >= 0) myGraph->AddEdge(i, j, integer); } } infile.close(); } else std::cout << "That file was not able to be opened." << std::endl; break; case 'f': if (noGraph()) break; outfile.open("theFile.txt"); if (outfile) { outfile << myGraph->size() << std::endl; for (i = 0; i < myGraph->size(); ++i) { for (j = 0; j < myGraph->size(); ++j) outfile << myGraph->EdgeWeight(i, j) << " "; outfile << std::endl; } } else std::cout << "That file was not able to be opened." << std::endl; break; case 'v': if (noGraph()) break; std::cout << "Please enter the label to give the vertex: "; std::cin >> label; myGraph->AddVertex(label); break; case 'e': if (noGraph()) break; std::cout << "What is the source vertex? "; std::cin >> i; std::cout << "What is the target vertex? "; std::cin >> j; std::cout << "What is the weight? "; std::cin >> integer; myGraph->AddEdge(i, j, integer); break; case 'x': if (noGraph()) break; std::cout << "What is the source vertex? "; std::cin >> i; std::cout << "What is the target vertex? "; std::cin >> j; myGraph->RemoveEdge(i, j); break; case 'r': if (noGraph()) break; std::cout << "What is the new size? "; std::cin >> i; myGraph->Resize(i); break; case 's': if (noGraph()) break; std::cout << myGraph->size() << std::endl; break; case 'b': if (noGraph()) break; std::cout << "What vertex? "; std::cin >> vertices; theSet = myGraph->Neighbors(vertices); for (theIterator = theSet.begin(); theIterator != theSet.end(); ++theIterator) std::cout << std::setw(4) << *theIterator; std::cout << std::endl; break; case 'g': if (noGraph()) break; std::cout << "What vertex? "; std::cin >> vertices; label = (*myGraph)[vertices]; std::cout << label << std::endl; break; case 'c': if (noGraph()) break; std::cout << "What vertex? "; std::cin >> vertices; std::cout << "What is the new value? "; std::cin >> label; (*myGraph)[vertices] = label; break; case 'a': if (noGraph()) break; std::cout << "What vertex is the start vertex? "; std::cin >> vertices; DijkstraAlgorithm(vertices); break; case 'q': notDone = false; break; case '?': PrintMenu(); break; default: std::cout << "Try again, that is not a valid choice." << std::endl; } } template <class Item> bool graphShell<Item>::noGraph() { if (graphExists) return false; std::cout << "There is no graph. Create a new one." << std::endl; return true; } template <class Item> void graphShell<Item>::DijkstraAlgorithm(std::size_t start) { bool notDone = true; char choice; int* distances = new int[myGraph->size()]; int dist; std::size_t vertex; std::size_t* previous = new std::size_t[myGraph->size()]; std::vector<std::size_t> path; std::vector<std::size_t>::iterator theIterator; std::size_t i; Dijkstra<Item> test(myGraph, start); while (notDone) { std::cout << std::endl << " d - Print the distance array" << std::endl << " p - Print the path array" << std::endl << " v - Print the distance and path to a vertex" << std::endl << " s - Change to a new start vertex" << std::endl << " q - quit" << std::endl << std::endl << "Enter your choice: "; std::cin >> choice; switch (choice) { case 'd': test.GetDistances(distances); for (i = 0; i < myGraph->size(); ++i) std::cout << std::setw(6) << distances[i]; break; case 'p': test.GetPaths(previous); for (i = 0; i < myGraph->size(); ++i) std::cout << std::setw(3) << previous[i]; break; case 'v': std::cout << "What vertex? "; std::cin >> vertex; dist = test.Distance(vertex); path = test.Path(vertex); if (!path.empty()) { std::cout << std::setw(2) << dist; for (theIterator = path.begin(); theIterator != path.end(); ++theIterator) std::cout << std::setw(3) << *theIterator; } else std::cout << "It is impossible to get from the start vertex to that vertex." << std::endl; break; case 's': std::cout << "What vertex? "; std::cin >> vertex; test.ChangeStart(vertex); break; case 'q': notDone = false; break; default: std::cout << "I don't understand, try again." << std::endl; } } delete [] distances; delete [] previous; }