Implementing a Suffix Trie using OOP/C++ - c++

I am trying to implement a suffix trie in C++ for a programming assignment. Now I think I have the right idea, but I keep getting a segmentation fault and I haven't been able to find what's causing it.
For this assignment, we are encouraged to use VIM/some other basic text editor, and compile programs from the console. Nevertheless, I've downloaded CLion to try and debug the code so I can find the error.
Now when running in CLion I get the message
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Trying to run the debugger gives the message
Error during pretty printers setup:
Undefined info command: "pretty-printer". Try "help info".
Some features and performance optimizations will not be available.
I'm new to CLion and I'm not sure what to do about this (The only JetBrains IDE I use is Pycharm). Can you help me resolve this?
Now the program itself consists of three classes, Trie, Edge and Node, whose implementations can be seen below. The main idea behind the implementation of the Trie is in the constructor of Trie.cpp.
The code is detailed in full below. I appreciate any help.
Main.cpp
#include <iostream>
using namespace std;
#include "Trie.hpp"
int main(){
string s = "Stef";
Trie trie(s);
return 0;
}
Trie.hpp
#ifndef TRIE_HPP
#define TRIE_HPP
#include <string>
#include "Node.hpp"
#include "Edge.hpp"
using namespace std;
class Trie{
private:
string T;
vector<Node> nodes;
void addWord(Node*, string);
public:
Trie(string);
};
#endif
Trie.cpp
#include <iostream>
#include <cstring>
#include "Trie.hpp"
using namespace std;
Trie::Trie(string T){
T += "#"; //terminating character
this->T = T;
vector<string> suffix; //array of suffixes
for(unsigned int i = 0; i < T.length(); i++)
suffix.push_back(T.substr(i, T.length()-i));
//Create the Root, and start from it
nodes.push_back(Node("")); //root has blank label
Node* currentNode = &nodes[0];
//While there are words in the array of suffixes
while(!suffix.empty()){
//If the character under consideration already has an edge, then this will be its index. Otherwise, it's -1.
int edgeIndex = currentNode->childLoc(suffix[0].at(0));
//If there is no such edge, add the rest of the word
if(edgeIndex == -1){
addWord(currentNode, suffix[0]); //add rest of word
suffix.erase(suffix.begin()); //erase the suffix from the suffix array
break; //break from the for loop
}
//if there is
else{
currentNode = (currentNode->getEdge(edgeIndex))->getTo(); //current Node is the next Node
suffix[0] = suffix[0].substr(1, suffix[0].length()); //remove first character
}
}
}
//This function adds the rest of a word
void Trie::addWord(Node* parent, string word){
for(unsigned int i = 0; i < word.length(); i++){ //For each remaining letter
nodes.push_back(Node(parent->getLabel()+word.at(i))); //Add a node with label of parent + label of edge
Edge e(word.at(i), parent, &nodes.back()); //Create an edge joining the parent to the node we just added
parent->addEdge(e); //Join the two with this edge
}
}
Node.hpp
#ifndef NODE_HPP
#define NODE_HPP
#include <string>
#include <vector>
#include "Edge.hpp"
using namespace std;
class Node{
private:
string label;
vector<Edge> outgoing_edges;
public:
Node();
Node(string);
string getLabel();
int childLoc(char);
void addEdge(Edge);
Edge* getEdge(int);
};
#endif
Node.cpp
#include "Node.hpp"
using namespace std;
Node::Node(){
}
Node::Node(string label){
this->label = label;
}
string Node::getLabel(){
return label;
}
//This function returns the edge matching the given label, returning -1 if there is no such edge.
int Node::childLoc(char label){
int loc = -1;
for(unsigned int i = 0; i < outgoing_edges.size(); i++)
if(outgoing_edges[i].getLabel() == label)
loc = i;
return loc;
}
void Node::addEdge(Edge e){
outgoing_edges.push_back(e);
}
Edge* Node::getEdge(int n){
return &outgoing_edges[n];
}
Edge.hpp
#ifndef EDGE_HPP
#define EDGE_HPP
#include <string>
using namespace std;
class Node; //Forward definition
class Edge{
private:
char label;
Node* from;
Node* to;
public:
Edge(char, Node*, Node*);
char getLabel();
Node* getTo();
Node* getFrom();
};
#endif
Edge.cpp
#include "Edge.hpp"
using namespace std;
Edge::Edge(char label, Node* from, Node* to){
this->label = label;
this->from = from;
this->to = to;
}
char Edge::getLabel(){
return label;
}
Node* Edge::getFrom(){
return from;
}
Node* Edge::getTo(){
return to;
}

&nodes[0];, &nodes.back() - you're storing pointers into a vector for later use, and these become invalid when the vector's underlying storage is relocated as you add elements to it.
Read about pointers in general, and dynamic allocation in particular, in your favourite C++ book.
If you don't yet have a favourite C++ book, pick one from this list.

Related

Redefine a Node of linked list: std::string

I am currently working on a school project, the material is new to me at the moment, basically, we are creating a Robot Guider that tracks their movement, distance, speed, etc... one of the functions that we are required to make is renaming a robot, however, they are stored in Node.
I have spent some time looking around for a quick solution and I am a little confused by the examples online. If someone could please help but also explain their logic that would be greatly appreciated.
we are using two different classes to track all of the information
-----CLASS #1:
#ifndef RobotList_hpp
#define RobotList_hpp
#include "Robot.hpp"
#include <stdio.h>
#include <iostream>
class RobotList{
private:
class Node{
public:
Robot* val;
Node* next = nullptr;
Node(std::string aName) {
val = new Robot;
val->setName(aName);
}
};
Node* head = nullptr;
Node* tail = nullptr;
public:
RobotList() = default;
~RobotList();
void display() const;
bool isEmpty();
Robot* find_nth();
void updateList();
void addNode(std::string name);
void deleteNode(std::string name);
void rename();
void robotDist() const;
};
#endif /* RobotList_hpp */
---CLASS #2:
#ifndef Robot_hpp
#define Robot_hpp
#include <stdio.h>
#include <iostream>
#include <algorithm>
class Robot{
private:
int x, y, curSpeed, totDist;
std::string name; char lastCommand;
bool stop_; int off_or_on;
public:
std::string getName() { return name; }
void setName(std::string a) {
this->name = a;
}
int getTotDist() { return totDist; }
void moveRobot();
int findRobot();
};
#endif /* Robot_hpp */
void RobotList::rename(){
std::string new_name;
std::cout << "Which robot do you want to rename?"<< std::endl;
std::cin >> new_name;
Node* temp = head;
while(!head){
if(temp->val->getName() == new_name){
// update list with user input new_name
// reassign a node that holds a string value
}
}
temp = temp->next; // rest of list til nullptr
}
This is what I tried to do but it was not operating properly.
I wrote out two comments on what I am trying to do. Thanks.
The problem is the while loop.
Head is a pointer to the first element so !head is true only when the list is empty, which is not what you want. Head should not be modified because we will lose the start of the list, that's why we have the temp.
The loop should stop at the end of the list, we know we reached the end when temp is nullptr. This is convenient because it makes sure we never dereference a null pointer. temp = temp->next; should be placed inside the loop so that it doesn't get stuck at the first element.
std::string old_name, new_name;
std::cout << "Which robot do you want to rename?"<< std::endl;
std::cin >> old_name; // name to search for
std::cout << "Enter new name:"<< std::endl;
std::cin >> new_name; // new name for the robot with old_name
Node* temp = head; // temp = first element(node) of the list
while(temp){ // while we haven't reached the end of the list
if(temp->val->getName() == old_name){
temp->val->setName(new_name);
break; // break if you only want to modify the first occurrence
}
temp = temp->next; // move to the next node
}
Also try to use const references for passing objects whenever possible, otherwise you create a lot of unwanted copies.

Using class object in different cpp file

I was starting to learn to use class object in different .cpp file..
What I did:
Created a class of node in one file and saved it with node.h
Created another file with name node_pair.cpp and included node.h
Created a function named pair() and called it from main()
Now, I want to ask two things:
I am getting error: reference to ‘pair’ is ambiguous
Here is the code for node.h file
#include "iostream"
#include"stdlib"
using namespace std;
class node
{
int data;
public:
node *next;
int insert(node*);
node* create();
int display(node *);
} *start = NULL, *front, *ptr, n;
int node::insert(node* np)
{
if (start == NULL)
{
start = np;
front = np;
}
else
{
front->next = np;
front = np;
}
return 0;
}
node* node::create()
{
node *np;
np = (node*)malloc(sizeof(node)) ;
cin >> np->data;
np->next = NULL;
return np;
}
int node::display(node* np)
{
while (np != NULL)
{
cout << np->data;
np = np->next;
}
return 0;
}
int main_node()
{
int ch;
cout << "enter the size of the link list:";
cin >> ch;
while (ch--)
{
ptr = n.create();
n.insert(ptr);
}
n.display(start);
cout << "\n";
return 0;
}
and here is the code for node_pair.cpp
#include"iostream"
#include"node.h"
using namespace std;
node obj;
int pair()
{
node* one, *two, *save;
one = start;
two = start->next;
while (two != NULL)
{
save = two->next;
two->next = one;
one->next = save;
}
}
int main()
{
main_node();
pair();
obj.display(start);
return 0;
}
What should I do to resolve this error
And now the second problem
2. I want to keep node* next pointer to be private in node class but if I do so then I will not get access for it in pair() function.
Please answer, thanks in advance.
Some tips:
Your function pair clashes with std::pair.
Don't use using namespace std;. It's a bad practice and creates errors like this.
Mixing node.js and C++ is an advanced topic. If you just begun to learn OOP, I recommend that you stick to pure C++.
You have a name collision with your pair() and std::pair.
Best practice is to avoid using the entire namespace std -- just use what you need. For example, if you only need std::cin you can use using std::cin; to add it to the global namespace but not std::pair. You can also replace all instances of cin with std::cin instead.
If you really want to use the entire namespace std you can also create your own namespace to put your code in -- in particular, you'd need to put your pair() in this new namespace. You do it like this:
namespace mynamespace {
int pair() {
// ...
}
// ... other code in mynamespace
} // end mynamespace

Adjacency list implementation in C++

I am looking for a concise and precise adjacency list representation of a graph in C++. My nodes are just node ids. Here is how I did it. Just want to know what experts think about it. Is there a better way?
This is the class implementation (nothing fancy, right now don't care about public/private methods)
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;
class adjList {
public:
int head;
vector<int> listOfNodes;
void print();
};
void adjList :: print() {
for (int i=0; i<listOfNodes.size(); ++i) {
cout << head << "-->" << listOfNodes.at(i) << endl;
}
}
class graph {
public:
vector<adjList> list;
void print();
};
void graph :: print() {
for (int i=0; i<list.size(); ++i) {
list.at(i).print();
cout << endl;
}
}
My main function parses an input file line by line. Where each line is interpreted as following:
<source_node> <node1_connected_to_source_node> <node2_connected_to_source_node <node3_connected_to_source_node> <...>
Here is the main:
int main()
{
fstream file("graph.txt", ios::in);
string line;
graph g;
while (getline(file, line)) {
int source;
stringstream str(line);
str >> source;
int node2;
adjList l;
l.head = source;
while (str >> node2) {
l.listOfNodes.push_back(node2);
}
g.list.push_back(l);
}
file.close();
g.print();
getchar();
return 0;
}
I know I should add addEdge() function inside adjList class instead of directly modifying its variable from main() however, right now I just wonder about the best structure.
EDIT:
There is one shortcoming in my approach. For a complicated graph with large number of nodes, node will indeed be a struct/class and in that case I will be duplicating values by storing the whole object. In that case I think I should use pointers. For example for an undirected graph, I will be storing copies of node objects in the adjList (connection between node 1 and 2 means 1's adjacency list will have 2 and vice versa). I can avoid that by storing pointers of node objects in the adjList instead of the whole object. Check the dfs implementation which get benefited by this approach. There I need to insure that each node gets visited only once. Having multiple copies of the same node will make my life harder. no?
In this case my class definitions will change like this:
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <map>
using namespace std;
class node {
public:
node() {}
node(int id, bool _dirty): node_id(id), dirty(_dirty) {}
int node_id;
bool dirty;
};
class adjList {
public:
node *head;
vector<node*> listOfNodes;
void print();
~adjList() { delete head;}
};
void adjList :: print() {
for (int i=0; i<listOfNodes.size(); ++i) {
cout << head->node_id << "-->" << listOfNodes.at(i)->node_id << endl;
}
}
class graph {
public:
vector<adjList> list;
void print();
void dfs(node *startNode);
};
void graph::dfs(node *startNode) {
startNode->dirty = true;
for(int i=0; i<list.size(); ++i) {
node *stNode = list.at(i).head;
if (stNode->node_id != startNode->node_id) { continue;}
for (int j=0; j<list.at(i).listOfNodes.size(); ++j) {
if (!list.at(i).listOfNodes.at(j)->dirty) {
dfs(list.at(i).listOfNodes.at(j));
}
}
}
cout << "Node: "<<startNode->node_id << endl;
}
void graph :: print() {
for (int i=0; i<list.size(); ++i) {
list.at(i).print();
cout << endl;
}
}
And this is how I implemented main() function. I am using a map<> to avoid duplication of objects. Creating a new object only when its not defined earlier. Checking existence of an object by its id.
int main()
{
fstream file("graph.txt", ios::in);
string line;
graph g;
node *startNode;
map<int, node*> nodeMap;
while (getline(file, line)) {
int source;
stringstream str(line);
str >> source;
int node2;
node *sourceNode;
// Create new node only if a node does not already exist
if (nodeMap.find(source) == nodeMap.end()) {
sourceNode = new node(source, false);
nodeMap[source] = sourceNode;
} else {
sourceNode = nodeMap[source];
}
adjList l;
l.head = sourceNode;
nodeMap[source] = sourceNode;
while (str >> node2) {
// Create new node only if a node does not already exist
node *secNode;
if (nodeMap.find(node2) == nodeMap.end()) {
secNode = new node(node2, false);
nodeMap[node2] = secNode;
} else {
secNode = nodeMap[node2];
}
l.listOfNodes.push_back(secNode);
}
g.list.push_back(l);
startNode = sourceNode;
}
file.close();
g.print();
g.dfs(startNode);
getchar();
return 0;
}
SECOND EDIT
After Ulrich Eckhardt suggestion to put adjacency list in node class, here is what I think is a better data structure to store a graph and perform dfs(), dijkstra() kind of operations. Please note that adjacency list is merged in node class.
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <map>
using namespace std;
class node {
public:
node() {
}
node(int id, bool _dirty): node_id(id), dirty(_dirty) {
//cout << "In overloaded const\n";
}
int node_id;
bool dirty;
vector<node*> listOfNodes;
};
class graph {
public:
vector<node*> myGraph;
void dfs(node* startNode);
};
void graph::dfs(node* startNode) {
startNode->dirty = true;
for (int j=0; j<startNode->listOfNodes.size(); ++j) {
if (!startNode->listOfNodes.at(j)->dirty) {
dfs(startNode->listOfNodes.at(j));
}
}
cout << "Node: "<<startNode->node_id << endl;
}
Can we do better than this?
There are a few things that could be improved, but in general your approach is reasonable. Notes:
You are using int as index into a container, which will give you warning from some compilers, because the size of a container could exceed the size representable as int. Instead, use size_t.
Rewrite your for (int i=0; i<list.size(); ++i) to for(size_t i=0, size=list.size(); i!=size; ++i). Using != instead of < will work with iterators. Reading and storing the size once makes it easier to debug and possibly even more efficient.
Inside the loop to print, you have list.at(i).print();. The list.at(i) will verify the index is valid and raise an exception when not. In this very simple case, I am sure that the index is valid, so using list[i] instead is faster. Also, it implicitly documents that the index is valid and not that you expect it to be invalid.
The print() functions should be constant.
I don't understand what the int head is. Is this some kind of ID for the node? And isn't the ID simply the index inside graph::list? If it is the index, you could compute that on demand using the address of the element minus the address of the first element, so there's no need to store it redundantly. Also, consider validating that index when reading, so you don't have any edges going to a vertex that doesn't exist.
If you don't care about encapsulation on a node-level (which is reasonable!), you could also make this a struct, which saves some typing.
Storing pointers instead of indices is tricky but could improve speed. The problem is that for reading, you might need a pointer to a vertex that doesn't exist yet. There is a hack that allows doing that without using additional storage, it requires first storing the indices in the pointer values (using reinterpret_cast) and after reading, making a second pass on the data where you adjust these values to the actual addresses. Of course, you can also use the second pass to validate that you don't have any edges going to vertices that don't exist at all (which is a place where the at(i) function becomes useful) so this second pass to verify some guarantees is a good thing anyway.
On explicit request, here's an example for how to store an index in a pointer:
// read file
for(...) {
size_t id = read_id_from_file();
node* node_ptr = reinterpret_cast<node*>(id);
adjacency_list.push_back(node_ptr);
}
/* Note that at this point, you do have node* that don't contain
valid addresses but just the IDs of the nodes they should finally
point to, so you must not use these pointers! */
// make another pass over all nodes after reading the file
for(size_t i=0, size=adjacency_list.size(); i!=size; ++i) {
// read ID from adjacency list
node* node_ptr = adjacency_list[i];
size_t id = reinterpret_cast<size_t>(node_ptr);
// convert ID to actual address
node_ptr = lookup_node_by_id(id);
if(!node_ptr)
throw std::runtime_error("unknown node ID in adjacency list");
// store actual node address in adjacency list
adjacency_list[i] = node_ptr;
}
I'm pretty sure that this works in general, though I'm not 100% sure if this is guaranteed to work, which was why I'm reluctant to post this here. However, I hope this also makes clear why I'm asking what exactly "head" is. If it is really just the index in a container, there is little need for it, neither inside the file nor in memory. If it is some kind of name or identifier for a node that you retrieved from a file, then you absolutely need it, but then you can't use it as index, the values there could as well start their IDs with 1 or 1000, which you should catch and handle without crashing!

Struct defined in header and included in two source codes is only defined in one

I have a struct defined in a header file with three other files that #include that header file. One is another header(queue.h) file that defines a very basic hash table and the other two are source codes where one is defining the functions from the hash table header(queue.cpp) and the other contains main(p2.cpp).
The problem that I'm having is that the struct seems to work fine in p2.cpp but in queue.h the compiler is telling me that the struct is undefined.
Here is p2.h containing the struct definition.
#ifndef __P2_H__
#define __P2_H__
#define xCoor 0
#define yCoor 1
#include <iostream>
#include <string>
#include "queue.h"
#include "dlist.h" //linked list which I know works and is not the problem
using namespace std;
struct spot {
float key[2];
string name, category;
};
#endif /* __P2_H__ */
I have queue.h included in this header so that I only have to include p2.h in p2.cpp.
Here is p2.cpp
#include <iostream>
#include <string>
#include <iomanip>
#include "p2.h"
using namespace std;
int main () {
cout << fixed;
cout << setprecision (4);
Queue hashTable;
spot *spot1 = new spot;
spot1->key[xCoor] = 42.2893;
spot1->key[yCoor] = -83.7391;
spot1->name = "NorthsideGrill";
spot1->category = "restaurant";
hashTable.insert(spot1);
Dlist<spot> test = hashTable.find(42.2893, -83.7391);
while (!test.isEmpty()) {
spot *temp = test.removeFront();
cout << temp->key[xCoor] << " " << temp->key[yCoor] << " " << temp->name << " " << temp->category << endl;
delete temp;
}
return 0;
}
Places and item in the hash table and takes it back out.
Here is queue.h
#ifndef __QUEUE_H__
#define __QUEUE_H__
#include <iostream>
#include <string>
#include "dlist.h"
#include "p2.h"
using namespace std;
class Queue {
// OVERVIEW: contains a dynamic array of spaces.
public:
// Operational methods
bool isEmpty();
// EFFECTS: returns true if list is empy, false otherwise
void insert(spot *o);
// MODIFIES this
// EFFECTS inserts o into the array
Dlist<spot> find(float X, float Y);
// Maintenance methods
Queue(); // ctor
~Queue(); // dtor
private:
// A private type
int numInserted;
int maxElts;
Dlist <spot>** queue;
// Utility methods
//Increases the size of the queue.
void makeLarger();
int hashFunc(float X, float Y, int modNum);
};
#endif /* __QUEUE_H__ */
Here is queue.cpp
#include <iostream>
#include <string>
#include <cstdlib>
#include "queue.h"
using namespace std;
bool Queue::isEmpty() {
return !numInserted;
}
void Queue::insert(spot *o) {
if (numInserted >= maxElts) {
makeLarger();
}
int index = hashFunc(o->key[xCoor], o->key[yCoor], maxElts);
queue[index] -> insertFront(o);
}
Queue::Queue() {
numInserted = 0;
maxElts = 1000;
queue = new Dlist<spot>*[maxElts];
for (int i = 0; i < maxElts; i++) {
queue[i] = new Dlist<spot>;
}
}
Queue::~Queue() {
for (int i = 0; i < maxElts; i++) {
delete queue[i];
}
delete[] queue;
}
void Queue::makeLarger() {
Dlist <spot>** temp = queue;
queue = new Dlist <spot>*[maxElts*2];
for (int i = 0; i < maxElts*2; i++) {
queue[i] = new Dlist<spot>;
}
for (int i = 0; i < maxElts; i++) {
while (!temp[i] -> isEmpty()) {
spot *spotTemp = temp[i] -> removeFront();
int index = hashFunc(spotTemp->key[xCoor], spotTemp->key[yCoor], maxElts*2);
queue[index] -> insertFront(spotTemp);
}
}
for (int i = 0; i < maxElts; i++) {
delete temp[i];
}
delete[] temp;
maxElts *= 2;
}
int Queue::hashFunc(float X, float Y, int modNum) {
return ((int)(10000*X) + (int)(10000*Y))%modNum;
}
Dlist<spot> Queue::find(float X, float Y) {
Dlist<spot> result;
Dlist<spot> *temp = new Dlist<spot>;
int index = hashFunc(X, Y, maxElts);
while (!queue[index] -> isEmpty()) {
spot *curSpot = queue[index] -> removeFront();
if ((curSpot->key[xCoor] == X) && (curSpot->key[yCoor] == Y)) {
result.insertFront(new spot(*curSpot));
}
temp -> insertFront(curSpot);
}
delete queue[index];
queue[index] = temp;
return result;
}
I believe that the problem is in my queue.h file because it's where I get all of the errors like "spot has not been declared". Every time spot appears in queue.h I have at least one error. I searched around for anything like this but all I could find was people trying to share one instance of a struct across multiple source files, or the obvious question of putting a struct in a header and including that header across multiple source files(which is what I'm doing but my problem seems to be a rather unique one).
You are including queue.h within the header that actually defines spot, so by the point the file is actually included spot has not been defined yet.
For your scope guards, note that identifiers starting with a double underscore are reserved by the implementation, don't use them.
And this is a poor choice even in plain C:
#define xCoor 0
#define yCoor 1
use this instead:
enum {
xCoor = 0
, yCoor = 1
};
Ok first never ever using "using" clauses in header files (it destroys the purposes of namespaces)
2nd provide a complete example that fails to compile
In addition to what others have said, you also have a circular reference error, which can also lead to similar undefined symbol errors. You have queue.h include p2.h, which includes queue.h.

help with insert on first BST

EDIT there a small thing that I am missing!! the error is still there
So I am attempting to learn how to code my first BST, and it is hard.... I am already having trouble with just a few lines of codes. the problem is in the insert, but I have included everything so that I could get some feedback on my style/other errors. I was suggested to use a pointer to pointer implementation, but we havent learned it yet, so I dont feel comfort/know how to code it yet. the
error is
[trinhc#cs1 Assignment_3]$ g++ movieList.cpp -o a.out
/tmp/ccLw6nsv.o: In function `main':
movieList.cpp:(.text+0x7a): undefined reference to `Tree::Tree()'
movieList.cpp:(.text+0xa7): undefined reference to `Tree::insert(int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
collect2: ld returned 1 exit status
the tree.h file
#ifndef TREE_H
#define TREE_H
#include <string>
#include <iostream>
using namespace std;
class Tree
{
public:
Tree();
bool insert(int k, string s);
private:
struct Node
{
int key;
string data;
Node *left;
Node *right;
};
Node* root;
bool insert(Node*& root, int k, string s);
};
#endif
tree.cpp
#include <iostream>
#include "tree.h"
#include <stack>
#include <queue>
#include <string>
using namespace std;
Tree::Tree()
{
root = NULL;
}
bool Tree::insert(int k, string s)
{
return insert(root, k, s);
}
bool Tree::insert(Node*& current_root, int k, string s)
{
if(root == NULL){
current_root = new Node;
current_root->key = k;
current_root->data = s;
current_root->left = NULL;
current_root->right = NULL;
return true;
}
else if (current_root->key == k)
return false;
else if (current_root->key > k)
insert(current_root->left, k, s);
else
insert (current_root->right,k, s);
}
movieList.cpp
#include <iostream>
#include <stack>
#include <queue>
#include <string>
#include "tree.h"
using namespace std;
int main()
{
Tree test;
test.insert(100, "blah");
return 0;
}
Tree test(); is not how define an object of class Test, This acutally declare function named test which returns Tree.
try
Tree test;
test.instert(100, "blah");
return 0;
I copied some of your code and this is working fine for me:
main:
#include <iostream>
#include <stack>
#include <queue>
#include <string>
#include "tree.h"
int main()
{
Tree test;
test.insert(100, "blah");
test.insert(50, "fifty");
test.insert(110, "one hundred ten");
return 0;
}
Insert function:
bool Tree::insert(Node*& currentRoot, int k, string s)
{
if(currentRoot == NULL){
currentRoot = new Node;
currentRoot->key = k;
currentRoot->data = s;
currentRoot->left = NULL;
currentRoot->right = NULL;
return true;
}
else if (currentRoot->key == k)
return false;
else if (currentRoot->key > k)
insert(currentRoot->left, k, s);
else
insert (currentRoot->right,k, s);
}
Other than that you have syntax errors all over the place. I also changed the name because as someone pointed out there was a bit of a naming problem. CurrentRoot makes sense because you are passing it the root of the left or right subtree on every recursion.
Couple of points:
You need to change the name of your member variable root to something else– I'd recommend m_root, or my_root, or tree_root, or something of those sorts. Right now you've got a little bit of a namespace clash in any function where you include root as an argument. This will also let you keep track of which root you're referring to.
bool Tree::insert(Node*& root, int k, string s)
{
if(root == NULL){
root = new Node;
root->key = k;
root->data = s;
root->left = NULL;
root->right = NULL;
return true;
} else
if (root == k) //Comparison between pointer and number.
return false;
else
if (root->key > k)
insert(root->left, k, s);
else
insert (root->right,k, s);
}
You need to change root on the commented line to root->key.
Other than that, it looks like it'll work.
EDIT: Also, what the other guy said. You declare an object as
TYPE name ()
if you are calling the default constructor (), so your code in your main function should be
Tree test;
test.insert(...)
Shouldn't you add tree.cpp to your build command?
[trinhc#cs1 Assignment_3]$ g++
movieList.cpp -o a.out
Would become
[trinhc#cs1 Assignment_3]$ g++
tree.cpp movieList.cpp -o a.out