Binary Tree insert function not working correctly C++ - c++

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;
}

Related

#ifndef not letting my files see what's in the header (C++)

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

Stack ADT C++ Functions

So recently i started to getting into stacks ADT in c++ and i am trying to create a small program which the user inserts a string and the output should be in reverse order
But something is going wrong with my code or i am missing something but i cant figure it out
My output so far is that i can insert the string but then it just output the couts "Reverse string" and nothing else
i tried several ways like to change the pop function but nothing changed
Thank you for any help
#include <iostream>
#include <string>
using namespace std;
class ReverseString {
public:
string str[13];
int topStack;
ReverseString() {
topStack = -1;
}
string Push() {
//char item;
string str("");
cout << "Enter a string " << endl;
cin >> str;
for (char ch : str) {
topStack++;
// str[topStack] = item;
return str;
}
}
string Pop() {
string temp= str[topStack];
for (int i = 0; i <= 13; i++) {
str[i] = temp;
//temp = str[i - 1];
cout << "Reverse String: " << str[topStack] << endl;
return temp;
}
}
};
// main function
int main() {
ReverseString str;
str.Push();
str.Pop();
return 0;
}

How do I make my for loop go to the end of the char* array and put every city in a linked list(The citys are divided by a whitespace)

So in my homework I need to sort cities alphabetically by the first letter, if there are more citys with the same starting letter, then output them in the reverse order.
I have managed to get the the input from a file into the buffer char array.
But when I try to to sort it(go through the array it doesnt work)
#include <iostream>
#include <fstream>
using namespace std;
class List
{
struct Node
{
char* input;
Node* next;
};
Node* head;
Node* tail;
public:
List()
{
head = NULL;
tail = NULL;
}
void createnode(char* city)
{
Node* temp = new Node;
temp->input= city;
temp->next = NULL;
if (head == NULL)
{
head = temp;
tail = temp;
}
else
{
Node* point = new Node;
point->input= city;
point->next = head;
head = point;
}
}
void display()
{
Node* point = head;
if (point == NULL)
{
cout << endl << "====================================" << endl << "List Doesnt exist/is deleted" << endl << "====================================" << endl;
return;
}
cout << endl << "your list:" << endl;
while (point != NULL)
{
cout << point->input<< "\t";
point = point->next;
}
cout << endl;
}
};
int main()
{
////////////////THE PART WHERE I EXTRACT INFORMATION FROM THE INPUT FILE
ifstream file("paldies.in", ifstream::binary);
fstream file2;
file2.open("paldies.out", ios::out);
if (!file)
{
cout << "Error desune!";
return 0;
}
file.seekg(0, file.end);
int length = file.tellg();
file.seekg(0, file.beg);
char * buffer = new char[length];
cout << "Reading " << length << " characters....." << endl;
file.read(buffer, length);
if (length == 0)
{
char nothing[8] = "Nothing";
file2.write(reinterpret_cast<char*>(nothing), 8 * sizeof(char));
file.close();
file2.close();
return 0;
}
if (file)
{
cout << "all characters read succesfully.";
}
else
{
cout << "error: only " << file.gcount() << " could be read";
}
file.close();
////////////////////////////THIS IS THE PART THATS NOT WORKING FOR ME
List a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
for (buffer; *buffer != '\0'; buffer++)
{
if (buffer[0] == 's')
{
char s_begining[255] = "";
for (int i = 0; buffer[0] != ' '; i++)
{
s_begining[i] = buffer[0];
buffer++;
}
s.createnode(s_benining);
}
buffer++;
}
cout << endl<<buffer<<endl;
s.display();
file2.close();
return 0;
}
Input: springfield philadelphia detroit cleveland miami denver springfield seattle jacksonville
Correct output: cleveland denver detroit jacksonville miami philadelphia seattle springfield springfield
Actual output: since im just testing with the letter s it comes out as springfield only once, if I change the char s_begining declaration to outside of the if statement or the loop it gives different results.
I have a feeling that the problem is somewhere in the first for loop because when I take it out the first element goes into the list just fine, but when I put back in sometimes theres an exception, nothing happens(Empty list), or the list has 4 inputs with also garbage data in them.
Also if I delete the buffer++; at the end of the first for loop it also breaks stuff.
So far I have gotten 1 city name in the list correctly and thats the first one (springfield).
EDIT: I forgot to mention that I am only allowed to use the fstream library, everything elese has to be coded by myself!
A lot of what you’re trying to do can be achieved using the STL:
#include <algorithm>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
int main() {
// 0. Set up variables
std::ifstream inFile("pladies.in");
std::ofstream outFile("pladies.out");
std::vector<std::string> cities;
// 1. Read each line of the input file to a vector
std::string line;
while (std::getline(inFile, line)) {
cities.push_back(line);
}
// 2. Sort the vector alphabetically
std::sort(cities.begin(), cities.end());
// 3. Write the vector to the output file
std::copy(cities.begin(), cities.end(), std::ostream_iterator<std::string>(outFile, "\n"));
}
(repl.it)

How do you initialize template class members that uses other template classes?

I'm having trouble correctly setting up and accessing my member functions of a class. This node class is being used to build a Max Heap Tree. However, when the tree is being initialized, I'm getting garbage data and not what I am initializing it to.
#ifndef HEAPNODE_H_INCLUDED
#define HEAPNODE_H_INCLUDED
#include <iostream>
#include <cstdlib>
#include <array>
using namespace std;
template <class Type> class HeapNode {
private:
int key;
Type value;
public:
HeapNode(int key, Type const &value) {
this->key = key;
this->value = value;
}
// Returns the key of the node
int getKey() {
return key;
}
// Returns the value of the node
Type getValue() {
return value;
}
// Displays the node
void displayNode() {
cout << "Key: " << key << "\tValue: " << value << endl;
}
};
#endif
Here is the class that builds my Heap Tree. I've tried setting the initializations in the constructor every which way, and I'm still getting junk data. In addition, I set the constructor to take an integer, but when I'm creating a tree in my driver program, it won't let me put an argument for it which initiates an array of that size.
#ifndef MAXHEAPTREE_H_tINCLUDED
#define MAXHEAPTREE_H_INCLUDED
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <string>
#include "HeapNode.h"
using namespace std;
template <class Type> class MaxHeapTree {
private:
HeapNode<Type> *array;
HeapNode<Type> *root;
int elementSize;
int height;
int leafCounter;
public:
// Constructor
MaxHeapTree(int n = 10) : elementSize(0), height(0), leafCounter(0) {
this->elementSize = elementSize;
this->height = height;
this->leafCounter = leafCounter;
HeapNode<Type> *array = new HeapNode<Type>[n];
}
// Destructor
~MaxHeapTree();
void arrayDisplay() {
cout << "Original array size: " << sizeof(array)/4 << endl;
}
// Returns the number of elements in the tree
int getSize() {
return elementSize;
}
// Returns the height of the tree
int getHeight() {
return height;
}
// Returns the number of leaves in the tree
int leaves() {
return leafCounter;
}
int countLines(const string fileName) {
string line;
int lineCount = 0;
ifstream myFile (fileName.c_str());
if (myFile.is_open()) {
while (getline(myFile, line)) {
lineCount++;
}
}
else {
cout << "Error opening file" << endl;
}
myFile.close();
return lineCount;
}
// Reads structure from a text file and builds a max heap
void buildTree(const string fileName) {
string line;
string key;
string value;
int lines = countLines(fileName);
int i = 0;
cout << "Lines: " << lines << endl;
HeapNode<Type> *newArray[lines];
cout << "Size of newArray: " << sizeof(newArray)/4 << endl;
ifstream myFile (fileName.c_str());
if (myFile.is_open()) {
while (getline(myFile, line)) {
key = line.substr(0, 1);
int x = atoi(key.c_str());
value = line.substr(1);
HeapNode<Type> *hNode = new HeapNode<Type>(x, value);
newArray[i] = hNode;
cout << "newArray[" << i << "] = ";
newArray[i]->displayNode();
i++;
}
}
else {
cout << "2 - Error opening file." << endl;
}
myFile.close();
}
};
#endif
How do you initialize template class members that uses other template classes?
In the same way you initialize members of non templates that don't use other templates.
when the tree is being initialized, I'm getting garbage data and not what I am initializing it to.
I was using MaxHeap<string> *heapTree1;
Well, there's your problem. Apparently you never created an instance of MaxHeap<string>.

std::getline "blends" strings together

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.