So I created a Binary tree class and I want to separate the class definition from its member function definition by putting the class def in the .h file and the function definitions in the .cpp file. Then I would include the .h file into the .cpp file. Now I got this to all work and it works fine. the problem is when I want to put the name including guards. Because I need to include the .h file in the member function .cpp file and in another .cpp that uses the binary tree class, I have to include these guards. But for some reason, once I include them both .cpp files don't seem to "see" the contents of the header file. I'm new to using to ifndef so I'm so sure what I'm doing wrong. thank you
Here's the header file called node.h:
#ifndef NODE_H
#define NODE_H
#include <iostream>
#include <string>
#include <vector>
#include <stdbool.h>
using std::cout;
using std::endl;
typedef std::vector<std::string> vectorString;
class BST
{
vectorString data;
BST *left, *right;
public:
// Default constructor.
BST();
// Parameterized constructor.
BST(std::string);
// Insert function.
BST* Insert(BST*, std::string);
// Inorder traversal.
void Inorder(BST*);
// PreOrder Traversal.
void PreOrder(BST*);
// PostOrder Traversal
void PostOrder(BST*);
// string slicer
std::string strSlice(std::string);
// boolean isDuplicate
bool isDuplicate(std::string, vectorString);
// print vector
void printVector(vectorString);
};
#endif
and here's the member definition file called node.cpp
#include <iostream>
//#include "node.h"
#include <string>
#include <vector>
using std::cout;
using std::endl;
// Default Constructor definition.
BST ::BST()
: data(0)
, left(NULL)
, right(NULL)
{
}
// Parameterized Constructor definition.
BST ::BST(std::string value)
{
if(data.empty()){
data.push_back(strSlice(value));
}
data.push_back(value);
left = right = NULL;
}
// String slicing function definition
std::string BST ::strSlice(std::string word){
std::string word2 = "";
word2 += word[0];
word2 += word[1];
return word2;
}
// print vector function definition
void BST ::printVector(std::vector<std::string> dataVector){
for(int i = 0; i < dataVector.size(); i ++){
cout << dataVector.at(i) << " ";
}
}
// Insert function definition.
BST* BST ::Insert(BST* root, std::string value)
{
if (!root)
{
// Insert the first node, if root is NULL.
return new BST(value);
}
// Insert data.
if (strSlice(value).compare(root->data.at(0)) > 0)
{
// Insert right node data, if the 'value'
// to be inserted is greater than 'root' node data.
cout << value << " is being put in the right node " << value << " > " << root->data.at(0) << endl;
// Process right nodes.
root->right = Insert(root->right, value);
} else if (strSlice(value).compare(root->data.at(0)) == 0) {
cout << value << " is being put in the same node " << value << " = " << root->data.at(0) << endl;
root->data.push_back(value);
}
else
{
// Insert left node data, if the 'value'
// to be inserted is greater than 'root' node data.
cout << value << " is being put in the left node " << value << " < " << root->data.at(0) << endl;
// Process left nodes.
root->left = Insert(root->left, value);
}
// Return 'root' node, after insertion.
// cout << "after insert root is " << root << endl;
return root;
}
// Inorder traversal function.
// This gives data in sorted order.
void BST ::Inorder(BST* root)
{
if (!root) {
return;
}
Inorder(root->left);
printVector(root->data);
cout << endl;
Inorder(root->right);
}
void BST::PreOrder(BST* root){
if(!root){
return;
}
root->printVector(root->data);
cout << endl;
PreOrder(root->left);
PreOrder(root->right);
}
void BST::PostOrder(BST* root){
if(!root){
return;
}
PostOrder(root->left);
PostOrder(root->right);
root->printVector(root->data);
cout << endl;
}
errors:
C:\Users\14jjo\C++ Projects\Project 0\node.cpp:12:1: error: 'BST' does not name a type
BST ::BST()
^~~
C:\Users\14jjo\C++ Projects\Project 0\node.cpp:20:1: error: 'BST' does not name a type
BST ::BST(std::string value)
^~~
and here's the class that is trying to implement the binary tree class called P0.cpp:
#include <iostream>
//#include "tree.h"
#include "cleanString.h"
#include "node.h"
#include <fstream>
#include <string>
using std::cout;
using std::endl;
int main(int argc, char** argv) {
std::ifstream fileRead;
std::string word;
fileRead.open(argv[1]);
if(!fileRead){
cout << "this is not a file\n";
} else { cout << "this is a file\n"; }
fileRead >> word;
word = cleanString(word);
BST tree, *root = nullptr;
root = tree.Insert(root, word);
while (fileRead >> word) {
word = cleanString(word);
tree.Insert(root, word);
}
tree.Inorder(root);
fileRead.close();
return 0;
}
errors:
C:/Users/14jjo/C++ Projects/Project 0/P0.cpp:22: undefined reference to `BST::BST()'
C:/Users/14jjo/C++ Projects/Project 0/P0.cpp:23: undefined reference to `BST::Insert(BST*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
just #include "node.h" and make sure to compile all cpp files
Related
I'm trying to implement insertion and searching of information in files using b+tree, while doing so im getting an error as undefined reference
I've made changes from the original code whose link is given below only the main.cpp and header file has been changed
main.cpp
#include <iostream>
#include <vector>
//#include <algorithm>
#include <fstream>
#include <string>
//#include <filesystem>
#include "BPTree.h"
void insertionMethod(BPTree** bPTree) {
int rollNo;
int age, marks;
std::string name;
std::cout << "Please provide the rollNo: ";
std::cin >> rollNo;
std::cout << "\nWhat's the Name, Age and Marks acquired?: ";
std::cin >> name >> age >> marks;
std::string fileName = "DBFiles/";
fileName += std::to_string(rollNo) + ".txt";
FILE* filePtr = fopen(fileName.c_str(), "w");
std::string userTuple = name + " " + std::to_string(age) + " " + std::to_string(marks) + "\n";
fprintf(filePtr, userTuple.c_str());
//fclose(filePtr);
(*bPTree)->insert(rollNo, filePtr);
fclose(filePtr);
std::cout << "Insertion of roll No: " << rollNo << " Successful"<<std::endl;
}
void searchMethod(BPTree* bPTree) {
int rollNo;
std::cout << "What's the RollNo to Search? ";
std::cin >> rollNo;
bPTree->search(rollNo);
}
int main() {
bool flag = true;
int option;
int maxChildInt = 4, maxNodeLeaf = 3;
std::cout << "Please provide the value to limit maximum child Internal Nodes can have: ";
std::cin >> maxChildInt;
std::cout << "\nAnd Now Limit the value to limit maximum Nodes Leaf Nodes can have: ";
std::cin >> maxNodeLeaf;
BPTree* bPTree = new BPTree(maxChildInt, maxNodeLeaf);
std::cout<<bPTree->getMaxLeafNodeLimit()<<std::endl;
do {
std::cout << "\nPlease provide the queries with respective keys : " << std::endl;
std::cout << "\tPress 1: Insertion \n\tPress 2: Search<< std::endl;
std::cin >> option;
switch (option) {
case 1:
insertionMethod(&bPTree);
break;
case 2:
searchMethod(bPTree);
break;
default:
flag = false;
break;
}
}while (flag);
return 0;
}
BPTree.h
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <string>
#ifndef NODE_H
#define NODE_H
class Node {
public:
bool isLeaf;
std::vector<int> keys;
Node* ptr2next;
union ptr {
std::vector<Node*> ptr2Tree; //Array of pointers to Children sub-trees for intermediate Nodes
std::vector<FILE*> dataPtr; // Data-Pointer for the leaf node
ptr(); // To remove the error !?
~ptr(); // To remove the error !?
} ptr2TreeOrData;
friend class BPTree; // to access private members of the Node and hold the encapsulation concept
public:
Node(){
this->isLeaf = false;
this->ptr2next = NULL;
}
};
class BPTree {
private:
int maxIntChildLimit; //Limiting #of children for internal Nodes!
int maxLeafNodeLimit; // Limiting #of nodes for leaf Nodes!!!
Node* root; Node* pparent = NULL; //Pointer to the B+ Tree root
void insertInternal(int x, Node** cursor, Node** child); //Insert x from child in cursor(parent)
Node** findParent(Node* cursor, Node* child){
if (cursor->isLeaf || cursor->ptr2TreeOrData.ptr2Tree[0]->isLeaf)
return NULL;
for (int i = 0; i < cursor->ptr2TreeOrData.ptr2Tree.size(); i++) {
if (cursor->ptr2TreeOrData.ptr2Tree[i] == child) {
pparent = cursor;
} else {
Node* tmpCursor = cursor->ptr2TreeOrData.ptr2Tree[i];
findParent(tmpCursor, child);
}
}
return &pparent;
}
public:
BPTree();
BPTree(int degreeInternal, int degreeLeaf){
this->maxIntChildLimit = degreeInternal;
this->maxLeafNodeLimit = degreeLeaf;
this->root = NULL;
}
int getMaxIntChildLimit();
int getMaxLeafNodeLimit()
{
return maxLeafNodeLimit;
}
void search(int key);
void insert(int key, FILE* filePtr);
};
#endif
Search and Insert code
The error im getting is
C:\Users\admin\AppData\Local\Temp\cctqZ0YA.o:insert.cpp:(.text$_ZN4NodeC1Ev[__ZN4NodeC1Ev]+0x20): undefined reference to `Node::ptr::ptr()'
collect2.exe: error: ld returned 1 exit status
I'm not so sure what Node::ptr::ptr() is could someone help out
The error message you get after deleting those declared but undefined constructor and destructor points to the actual problem. Why unions might need a constructor and destructor is better explained elsewhere, e.g. here and here.
You can get your code compiling by providing a trivial empty implementation.
ptr() {};
~ptr() {};
I am using a function to read strings from a normalized file in order to push each string to the top of a stack that is being implemented dynamically using a linked list.
the normalized file is using data like this:
racecar
rotator
rotor
civic
when i call my function i expect my output to look the same after it uses get line to push each string to the stack, however, the actual out put is erasing the first character in the first string in a manner that looks like this:
acecar
rotator
rotor
civic
i have tried to use the ignore(), sync(), and clear functions before each iteration of get line() but i still keep coming up with the same problem.
i need some real help with this one and i hope one of you code masters can help me find the solution since i have yet to be able to get ignore() and the rest of them to ever work correctly!!! :/
here is the code to my function:
void createStack(fstream &normFile, ostream &outFile)
{
string catchNewString;
do
{
DynStrStk stringStk;
getline(normFile,catchNewString,'\n');
stringStk.push(catchNewString);
//tracer rounds
cout << endl;
outFile << catchNewString << endl;
cout << "test: " << catchNewString << endl;
} while(!normFile.eof());
}
this is the entirety of my main function:
//
#include <iostream>
#include <fstream>
#include <ostream>
#include <sstream>
#include <string>
#include "DynStrStk.h"
using namespace std;
void processFile();
void parseFile(ifstream&, fstream&);
void createStack(fstream&, ostream&);
int main()
{
//call function to open file and process
cout << "processing file" << endl;
processFile();
return 0;
}
void processFile()
{
ifstream inFile;
fstream normFile;
ofstream outFile;
cout << "opening files" << endl;
// open files
inFile.open("inFile.txt");
normFile.open("normFile.txt");
outFile.open("outFile.txt");
cout << "parsing file" << endl;
//parse file for capitalization & punctuation
parseFile(inFile, normFile);
//create stack with parsed and normalized normFile
createStack(normFile, outFile);
//close files
outFile.close();
normFile.close();
inFile.close();
}
void parseFile(ifstream &inFile, fstream &normFile)
{
//create and initialize variables
string newString;;
int i;
if(!inFile)
{
cout << "ERROR!!! Cannot read file.";
}
else
{
do
{
//read each line in the input file until EOF
getline(inFile, newString, '\n');
i = 0;
//parse each string for punctuation
while(newString[i])
{
if(isalpha(newString[i])) //check each char in each
//string for punctuation
{
if(isupper(newString[i])) //check each string for
//capitalization
{
newString[i] = tolower(newString[i]); //convert
//string to lower case
}
normFile << newString[i]; //output each line tofile
cout << newString[i];
}
i++;
}
normFile << '\n';
cout << '\n';
} while(!inFile.eof());
}
}
void createStack(fstream &normFile, ostream &outFile)
{
string catchNewString;
do
{
DynStrStk stringStk;
getline(normFile,catchNewString,'\n');
stringStk.push(catchNewString);
//tracer rounds
cout << endl;
outFile << catchNewString << endl;
cout << "test: " << catchNewString << endl;
} while(!normFile.eof());
}
this is my push function in my header file:
//function that pushes the argument onto the list
void DynStrStk::push(string newString)
{
StackNode *newNode = nullptr; //Pointer to a node
//Allocate a new node and store string
newNode = new StackNode;
newNode->newString = newString;
//if there are no nodes in the list make newNode the first node
if(isEmpty())
{
top = newNode;
newNode->next = nullptr;
}
else //otherwise insert NewNode before top
{
newNode->next = top;
top = newNode;
}
}
this is my header file:
#ifndef DynStrStk_h
#define DynStrStk_h
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class DynStrStk
{
private:
//struct stack nodes
struct StackNode
{
string newString; //string held in the node
StackNode *next; //pointer to the next node
};
StackNode *top; //pointer to the top of the stack
public:
//Constructor
DynStrStk()
{top = nullptr;}
//Destructor
~DynStrStk();
//Stack Operations
void push(string);
void pop(string &);
bool isEmpty();
};
#endif
Your code is almost correct, with couple of exceptions.
you should not test for eof as a loop condition, see Why is iostream::eof inside a loop condition considered wrong?
Declaring DynStrStk stringStk; inside the loop seems very fishy, as at the exit from the loop the variable cease to exist.
Here is a very simple program that uses a std::stack<std::string> instead, and which works, so the problem is probably in your DynStrStk implementation. There is no need to use cin.clear or cin.ignore as long as you're not mixing up cin and getline (in this latter case cin leaves a new line in the buffer which may end up "eaten" by `getline" in case you don't clear the stream).
#include <iostream>
#include <stack>
#include <string>
#include <fstream>
int main()
{
std::stack<std::string> stringStk; // stack of strings
std::ifstream normFile("test.txt"); // input file
std::ofstream output("out.txt"); // output file
std::string catchNewString;
while(getline(normFile,catchNewString)) // read and push to stack
{
stringStk.push(catchNewString); // push to stack
}
while(!stringStk.empty()) // dump the stack into the file
{
output << stringStk.top() << std::endl; // write it
stringStk.pop(); // remove
}
}
Again, you are not losing anything with the getline, nothing is lost in the buffer. There is an error probably when you loop over the individual characters in the string, in void parseFile(ifstream &inFile, fstream &normFile). One more thing: you use parseFile(inFile, normFile); then immediately createStack(normFile, outFile);. However, the normFile will have its position at the end (this is done by parseFile()), don't you need to rewind it before invoking createStack()?
try normFile.seekg(0, ios::beg); adter parseFile() and before createStack(). If it's not working, then try moving as much code as possible in independent functions and test each function step by step, or use a debugger and see live what's going on.
I have been working on this project for several days. This project contains 3 classes. The first is a DNA class that stores a DNA object. The second is a database class that reads a file and parses commands and data and deals with it accordingly. The last is a DNA list class that is a linked list of nodes that have pointers to DNA objects.
I've completed my linked list building method. It is required to be a push_back method that adds nodes at the end of the list. My problem arises when I try to search the list for a certain node. This has to be a method that returns a DNA* if a DNA object with id exists in the list; otherwise it returns NULL.
My plan is to use this method to print and also delete the node. I can't seem to get this method to work. Obviously I'm a little shaky with pointers. It took me several hours to implement my push_back method. Here is my code. Any guidance or help is appreciated.
DNA.h
#ifndef DNA_H
#define DNA_H
#include <string>
class DNA{
public:
// overloaded constructor for DNA class
DNA(std::string, int, std::string, int, int);
// print function
void print();
int getID();
private:
std::string m_label; // variable to hold label
int m_id; // variable to hold id
std::string m_sequence; // variable to hold sequence
int m_length; // variable to hold length
int m_index; // variable to hold index
};
#endif
DNA implementation
#include "DNA.h"
#include <iostream>
#include <string>
using namespace std;
DNA::DNA(string label, int id, string sequence, int length, int index){
m_label = label;
m_id = id;
m_sequence = sequence;
m_length = length;
m_index = index;
}
void DNA::print(){
cout << "DNA:" << '\t' << "label: " << m_label << '\t' << "ID: " << m_id << '\t' << "Sequence: " << m_sequence << endl << "Length: " << m_length << '\t' << "cDNAStartIndex: " << m_index << endl << endl;
}
int DNA::getID(){
return m_id;
}
Database class
#ifndef SEQUENCEDATABASE_H
#define SEQUENCEDATABASE_H
#include <string>
#include <fstream>
#include "DNA.h"
#include "DNAList.h"
class SequenceDatabase {
public:
SequenceDatabase();
// function to import the data file, parse the data, and perform the required output
void importEntries(std::string);
private:
DNAList list;
};
#endif
Database implemenation
#include "SequenceDatabase.h"
#include "DNA.h"
#include "DNAList.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
SequenceDatabase::SequenceDatabase(){
DNAList list;
}
// function reads in the filename creates a data stream and performs the requested actions
void SequenceDatabase::importEntries(string inputFile){
ifstream dnaFile(inputFile);
char command;
string label, sequence;
int id, length, index;
while(dnaFile >> command){
DNA* p;
if(command == 'D'){
dnaFile >> label >> id >> sequence >> length >> index;
DNA data(label, id, sequence, length, index);
p = new DNA(label, id, sequence, length, index);
list.push_back(p);
}
if(command == 'P'){
dnaFile >> id;
cout << "Printing " << id << " ..." << endl << endl;
p = list.findId(id);
if(p == nullptr)
cout << "Can not find item " << "(" << id << ")!" << endl << endl;
else
p-> print();
}
}
dnaFile.close();
}
Finally my list class
#ifndef DNALIST_H
#define DNALIST_H
#include "DNA.h"
#include "sequenceDatabase.h"
struct DNANode{
DNA* data;
DNANode* next;
DNANode* prev;
};
class DNAList{
public:
DNAList();
DNAList(DNA* newDNA);
void push_back(DNA* newDNA);
DNA* findId(int);
void obliterate(int id);
int size();
private:
DNANode* head;
int list_size;
};
#endif
List implementation
#include "DNA.h"
#include "sequenceDatabase.h"
#include "DNAList.h"
#include <iostream>
using namespace std;
DNAList::DNAList(){
head = new DNANode;
head->next = nullptr;
list_size = 0;
}
DNA* DNAList::findId(int id){ // this function is my problem
DNANode* current;
current = head;
while(current->next != nullptr){
if(current->data->getID() == id){
return current->data;
}
current = current->next;
}
return nullptr;
}
int DNAList::size(){
return list_size;
}
void DNAList::push_back(DNA* newDNA){
DNANode* current;
DNANode* last;
DNANode* p;
p = new DNANode;
p->data = newDNA;
last = nullptr;
current = head;
cout << "Adding " << newDNA->getID() << " ..." << endl << endl;
while(current != nullptr){
last = current;
current = current->next;
}
if(current == head->next){
p->next = nullptr;
p->prev = head;
head->next = p;
}
else{
p->next = current;
p->prev = last;
last->next = p;
}
list_size++;
}
I wasn't sure if I should post the whole code, but i felt it was needed to understand the problem. My problem arises when i try to call the find function to print the data in the node.
Your head member variable of DNAList is initialized with new DNANode. Since DNANode doesn't have an explicit constructor, its compiler generated one will not initialize the pointers data, next and prev. next is initialized on the next line, but data is left as a garbage value.
Inside findId, this line is executed:
if (current->data->getID() == id){
However the first time around the loop, current is pointing head. This means you are trying to look at the garbage value, which will possibly crash.
One solution is to change the findId function to start at head->next, another is to initialise the data pointer in head to nullptr and check that data is not nullptr before you access it.
A better solution might be to just have head as nullptr to start with, rather than having a dummy DNANode at the top. This would involve changing some of the code in push_back, but might make it easier to understand.
Aha. I think what is causing the problem is that towards the end of your SequenceDatabase::importEntries() method you are setting if(p=nullptr) instead of making the comparison if(p == nullptr). This is no doubt causing the error you see. This is a common mistake.
I am attempting to read data from a .txt file and put its contents into a linked list that holds two strings per node. Because some of the strings in the .txt file contain spaces, and I'd rather leave them as is than kill the spaces, I am using std::getline().
I have the .txt file formatted as so:
"Tourism, Recreation & Sports Management"
“TRS”
"Anthropology"
“ANT”
And so on but without the blank lines between each line. The linked list has a print() method that prints the data in this format : data1 / data2 ; data1 / data2:
So, when I print a node with data1 == "Tourism, Recreation & Sports Management" and data2 == "TRS" the desired output is:
"Tourism, Recreation & Sports Management" / "TRS";
HOWEVER, what I actually get is:
"TRS"ism, Recreation & Sports Management"
However, when I read the lines and assign them to strings, and then print out those strings without inserting them into the linked list, I get correct output. That is
std::cout << data1 << std::endl;
std::cout << data2 << std::endl;
Will correctly output:
"Tourism, Recreation & Sports Management"
"TRS"
What gives?
Edit:
Linked List header:
#ifndef _2DLL_H_
#define _2DLL_H_
#include <iostream>
#include <string>
class Llist{
struct node{
//node member var
std::string department;
std::string abv;
node * next;
//node member methods
std::string search(std::string dep);
void print();
void remove(const std::string dep);
void clear();
//constructer
node(const std::string dep , const std::string a):department(dep), abv(a), next(NULL){}
};// end node
public:
//Llist member var
node * head;
//LList constructer & destructor
Llist():head(NULL){}
~Llist(){clear();}
//Llist member functions
std::string search(const std::string dep);
void insert(const std::string dep , const std::string a);
void print();
void remove(const std::string dep);
void clear();
const int operator[](unsigned int index)const;
};// end Llist
#endif //_2DLL_H_
Linked List .cpp
#include "2DLL.h"
#include <algorithm>
//=========INSERT==============
void Llist::insert(const std::string dep, const std::string a){ //will just prepend. Fuck the police;
node * n = new node(dep , a);
n->next = head;
head = n;
}
//========PRINT=================
void Llist::print(){
if(head==NULL){
std::cout << "ERROR: List is empty" << std::endl;
}
else{
head->print();
}
}
void Llist::node::print(){
if(next==NULL){
std::cout << department << ";" << abv << std::endl;
}
else{
std::cout << department << ";" << abv << " / " ;
std::cout << std::endl;
next->print();
}
}
//=======REMOVE========
void Llist::remove(const std::string dep){
if(head==NULL){
std::cout << "ERROR: List is empty" << std::endl;
}
else{
head->remove(dep);
}
}
void Llist::node::remove(const std::string dep){
if(next->department == dep){
node * n = next;
next = n->next;
delete n;
}
else{
next->remove(dep);
}
}
//===========CLEAR()==================
void Llist::clear(){
if(head==NULL){
std::cout << "ERROR:List is empty" << std::endl;
}
else{
head->clear();
head = NULL;
}
}
void Llist::node::clear(){
if( this==NULL){
return;
}
else{
next->clear();
delete this;
}
}
//=========OPERATOR=============
/*
const int Llist:: operator[] (unsigned int index) const{
node * n = head;
for(int i = 0 ; i < index && n!=NULL ; ++i){
n=n->next;
}
return n->data;
}
*/
//========SEARCH====================
std::string Llist::search(std::string dep){
if(head == NULL){
std::cout << "ERROR: List is empty" << std::endl;
return "ERROR";
}
else{
//dep.erase(std::remove(dep.begin(),dep.end(),' '),dep.end());
//std::cout << dep << std::endl;
return head->search(dep);
}
}
std::string Llist::node::search(std::string dep){
if(department == dep){
return abv;
}
else{
return next->search(dep);
}
}
Implementation of the Reading
#include "genCollege.cpp"
#include "genDepartment.cpp"
#include "2DLL.cpp"
#include <ctime>
#include <fstream>
using namespace std;
int main(){
std:: ifstream file;
file.open("DepList.txt");
std::string department;
std::string abv;
srand(time(0));
/*for (int i = 0 ; i < 30 ; i++){
std::string college = genCollege();
std::string department = genDepartment(college);
std::cout << "College: "<< college << std::endl;
std::cout << "\t" << "Department: " << department << std::endl;
std::cout << std::endl;
} */
Llist list;
while(file.is_open()){
if(file.eof()){break;};
std::getline(file , department);
std::getline(file, abv);
list.insert(department , abv);
}
//file.close();
list.print();
return 0 ;
}
As the user n.m suggested, it seemed that because I was reading a text file for Windows and running program on Ubuntu, the output looked wrong. His answer word for word:
"You have a text file created for Windows that has \r\n as the line terminator. Your program either runs on a un*x or fails to open the file in text mode. Thus you are getting \r at the end of each string, which messes your terminal window. "
He suggested I check to see if the the last character in the string after I've used std::getline() is \r and, if it is, to remove it from the string. I did this by simply making a substring of the strings in question after I acquired them with std::getline()
I then inserted the new substrings into the linked list and the print() method now outputs as desired.
I'm working on a program that uses a binary tree. The program reads from a text file, storing each word in a binary tree alphabetically and finds how many times the word appeared in the file.
The problem I'm having is that my insert function is not working (the program crashes when attempting to run it). I don't know what's exactly wrong, but I suspect it has to do with my else statement towards the end of the function that deals with the right side of the tree.
Any help with fixing it would be appreciated.
Header File
#include <iostream>
#include <string>
using namespace std;
#ifndef TREE_H
#define TREE_H
class Tree
{
public:
Tree();
Tree(string str);
void traversal (Tree *);
void read_file();
void insert(string str);
~Tree();
private:
Tree *left;
Tree *right;
string word;
int count;
};
#endif // TREE_H
Cpp File
#include <iostream>
#include <string>
#include <fstream>
#include "tree.h"
using namespace std;
Tree::Tree()
{
left = NULL;
right = NULL;
count = 0;
}
Tree::Tree(string s)
{
word = s;
}
Tree::~Tree() { }
void Tree::read_file()
{
ifstream myfile;
myfile.open("input.txt", ios::out | ios::in | ios::binary);
if(myfile.is_open()){
while(myfile.good()) {
string buffer;
while(true) {
char c = myfile.get();
if(c == '-' || c == '\'' || isalpha(c) ){
if(isupper(c)) c = tolower(c);
buffer+=c;
}
else break;
}
if(buffer.length() >= 4){
insert(buffer);
}
}
myfile.close();
traversal(this);
}
else { cout << "Unable to open file!" << endl; }
}
void Tree::insert(string str) {
if(str.empty()){ // Also I'm debating whether I need this or not since the string
// cannot possibly be empty as it's part of the condition before
//insert is even called.
this->word = str;
count++;
}
else if(this->word == str) count++;
else if(str < this->word){
if(this->left == NULL) this->left = new Tree(str);
else this->left->insert(str);
}
else {
if(this->right == NULL) this->right = new Tree(str);
else this->right->insert(str);
}
}
void Tree::traversal(Tree *T) {
if(T != NULL) {
traversal(T->left);
cout << T->word << " (" << count << ")" << endl;
traversal(T->right);
}
}
Main
#include <iostream>
#include "tree.h"
using namespace std;
int main()
{
Tree tree;
tree.read_file();
return 0;
}
the problem is that you have 2 constructors, and the second one doesn't initialize pointers left/right to NULL.
edit you are showing properties from different objects: use
cout << T->word << " (" << T->count << ")" << endl;
since the recursive procedure doesn't works calling the member function of the received T. You could do it static, or change it
void Tree::traversal() {
if(this) {
traversal(left);
cout << word << " (" << count << ")" << endl;
traversal(right);
}
}
Personally, I do prefer this last 'style'.
Tree::Tree()
{
word.clear();
left = NULL;
right = NULL;
count = 0;
}
Tree::Tree(string s)
{
word = s;
left = NULL;
right = NULL;
count = 0;
}