File I/O in C++ - Having some trouble writing back data? - c++

This project is a basic ATM program. I'm using a file to store all the account details. So, every time I run the .exe file, It will read the data from the file and insert it into an AVL tree. And when I close the program, all the data in the AVL nodes will be inserted back into the file.
Data is stored in the file in this order (Each separated by a newline char) ID, Password, Name, Add, City, Pin, Balance.
Sample file --
12
4576
Vert
No_999,GoLane
Dallas
89777
50000
16
2342
Nerd
No_888,FoLane
Chicago
89999
30000
The problem is I cannot write back data into the file. Any suggestions please?
P.S. Please excuse my inline class methods please...
Program--
#include<iostream>
#include<conio.h>
#include<string.h>
#include<fstream>
using namespace std;
fstream file("one2.txt",ios::in|ios::out);//Opening the file 'one2.txt' in global scope
//AVL tree code starts here
class avl
{
struct node //The structure node which is going to hold the data sets in the tree
{
int id,pwd;
char name[15],add[30],city[10];
int pn;
double bal;
node *left, *right;
int height;
//node constructors
node(int i,int p,char nam[15], char a[30], char c[10],int pin,double b, node * l,node * r,int h)
{
id=i;
pwd=p;
strcpy(name,nam);
strcpy(add,a);
strcpy(city,c);
pn=pin;
bal=b;
left=l;
right=r;
height=h;
}
node()
{
left=right=NULL;
id=pwd=pn=0;
bal=0;
height=-1;
}
};
node *root;
node *nullnode;
int Height(node *t)const //Func to return the height of a node
{
return((t==NULL)? -1:t->height);
}
int max(int a,int b)
{
return(a>b)?a:b;
}
//Beginning of Insert() -- To create and insert data into the nodes
void insert(const int &x,int p, char nam[15], char a[30], char c[10],int pin,double b, node *&t)
{
if(t==NULL)
t = new node(x,p,nam,a,c,pin,b,NULL,NULL,-1);
else if(x<t->id)
{
insert(x,p,nam,a,c,pin,b,t->left);
if(Height(t->left) - Height(t->right)==2)
{
if(x<t->left->id)
single_rotate_with_left(t);
else
double_rotate_with_left(t);
}
}
else if(x>t->id)
{
insert(x,p,nam,a,c,pin,b,t->right);
if(Height(t->right)-Height(t->left)==2)
{
if(x>t->right->id)
single_rotate_with_right(t);
else
double_rotate_with_right(t);
}
}
else
t->height=max(Height(t->left),Height(t->right)+1);
}
//End of insert()
//Func to print the node data. Just a sample to check if all the data
// were inserted into the tree
//Inorder traversal
void print(node *&t)
{
if(t!=NULL)
{
print(t->left);
cout<<endl;
cout<<"ID "<<t->id<<" Name "<<t->name;
cout<<endl<<t->pwd<<endl<<t->add<<"\n"<<t->city;
cout<<"-"<<t->pn<<endl<<t->bal<<endl;
print(t->right);
}
}
//Think there's gonna be no problem with the rotation and other AVL tree func codes.
//Beginning of AVL rotations
void single_rotate_with_left(node *&k2)
{
node *k1=k2->left;
k2->left=k1->right;
k1->right=k2;
k2->height=max(Height(k2->right),Height(k2->left))+1;
k1->height=max(Height(k1->left),(k2->height))+1;
k1=k2;
}
void single_rotate_with_right(node *&k2)
{
node *k1=k2->right;
k2->right=k1->left;
k1->left=k2;
k2->height=max(Height(k2->left),Height(k2->right))+1;
k1->height=max(Height(k1->right),(k2->height))+1;
k1=k2;
}
void double_rotate_with_left(node *&a)
{
single_rotate_with_right(a->left);
single_rotate_with_left(a);
}
void double_rotate_with_right(node *&a)
{
single_rotate_with_left(a->right);
single_rotate_with_right(a);
}
//End of AVL rotations
//Function to return the node. The 'id' variable to be searched is passed as a param
node*& search(int x,node *&t)
{
if(t->id>x)
return search(x,t->left);
else if(t->id<x)
return search(x,t->right);
else if(t->id==x)
{
return t;
}
else
return nullnode;
}
//End of search. I'm using this in the loadnode() function.
//This is where I try to write data back into the file.
void update1(node *&t,int x) // x is the control variable
{
if(x==1)
//This block will be executed only once when the function is called for the
//first time. Used to seek to the beginning of the file
{
file.seekg(0,ios::beg);
x++;
}
if(t!=NULL)// Inorder traversal in the tree
{
update1(t->left,x);
//writing the data in the same order as it was stored.
file<<t->id<<endl;
file<<t->pwd<<endl;
file<<t->name<<endl;
file<<t->add<<endl;
file<<t->city<<endl;
file<<t->pn<<endl;
file<<t->bal<<endl;
update1(t->right,x);
}
}
public:
//Avl Constructor - This one is the one which is actually used.
avl(int x,int p,char nam[15], char a[30], char c[10],int pin,double b)
{
root= new node(x,p,nam,a,c,pin,b,NULL,NULL,-1);
nullnode=new node;
}
avl()
{
root->left=root->right=NULL;
root->height=-1;
}
//Call to the private insert function
void insert1(const int &x,int p,char nam[15], char a[30], char c[10],int pin,double b)
{
insert(x,p,nam,a,c,pin,b,root);
}
//Call to the private print() function
void display()
{
cout<<endl;
print(root);
}
//Function to write a new value for 'bal' variable to a node.
//I'm actually using this to update a node anconfirm whether the value of the updated node
//is reflected back at the node
void loadnode(int x)
{
node *&t=search(x,root);
cout<<"\nLoaded node...\n";
cout<<t->id;
cout<<" "<<t->name;
t->bal=40000;
cout<<"\nUpdated Bal.."<<t->bal;
}
void update()
{
//file.seekp(0);
update1(root,1);
}
};//End of AVL Class
main()
{
cout<<"The output..\n";
int i, p, pn;
char n[15],a[30],c[10];
double b;
int prev_id=0;
file>>i>>p>>n>>a>>c>>pn>>b;
prev_id=i;
avl list(i,p,n,a,c,pn,b);
while(file)
{
file>>i>>p>>n>>a>>c>>pn>>b;
if(prev_id!=i)
// I'm using this because i got a weird scenario in which the last record was repeated twice.
{
list.insert1(i,p,n,a,c,pn,b);
}
prev_id=i;
}
cout<<endl<<"The elements in AVL tree are...\n\n";
list.display();
list.loadnode(12);//12 is the id i used for one of my records.
//Calling to write back the data into the file.
list.update();
file.close();
getch();
return 0;
}
//End of program

If file.good() returned false, some previous operation on the file failed (maybe even a read operation) and raised one of the error flags of the file object. An ugly way to solve it is to use file.clear() which will clear the error flag and allow next actions to execute successfully. A better way to solve it will be to check after each operation if there's an error (file.good() is false) and understand why this operation fails and fix it.

call seekp() to move the write pointer to the begining of the stream (fstream). seekg() moves the get pointer - not going to help when writing...

Related

Traversing general nodes class, listing all nodes results in a infinite loop

I am practicing traversing trees/nodes and i came to the current problem. I want to be able to connect one node to itself. Connect node 1 to node 2. Nodes can be connected to as many nodes as desirable. This is the current class that i wrote and practicing with.
My problem is that i cannot check if i already traversed a past node. What i get is an infinite loop of one -> two -> three -> four -> one -> two ... and so on.
Would be possible to be given a tip to the right direction?
I want nodeN.list_connections() to be able to print all nodes that nodeN connects to.
class Node {
private:
std::vector<Node*> nodes;
std::string data;
public:
Node()
{
printf("Status: Created [%d]\n", this);
}
void connect(Node& node)
{
nodes.push_back(&node);
printf("Status: Node [%d] Connected To [%d]\n", this, &node);
}
void input_data(std::string str_in)
{
data = str_in;
}
void list_connections()
{
printf("List: Start\n");
printf("Node[this][%d]: %s\n", this, data.c_str());
for (size_t i = 0; i < nodes.size(); i++)
{
printf("Node[i=%d][%d]: %s\n", i, nodes[i], nodes[i]->data.c_str());
if (this != nodes[i])
nodes[i]->list_connections();
}
}
};
void test_list()
{
Node one;
one.input_data("ONE");
Node two;
two.input_data("TWO");
Node three;
three.input_data("THREE");
Node four;
four.input_data("FOUR");
// one -> two <-> three -> four -> one
// one -> one
// two -> two
one.connect(two);
one.connect(one);
two.connect(two);
two.connect(three);
three.connect(four);
four.connect(one);
three.connect(two);
one.list_connections();
//two.list_connections();
//three.list_connections();
//four.list_connections();
}
This is my code above.
My test_list function tests all possible connection scenarios.
EDIT:
The current idea of my nodeOne.list_connections(), is that it will loop through all the nodes connected to nodeOne. Those nodes will also use nodeOther.list_connections() only if the current node is not connected to other node.
EDIT:
All the nodes are connected in some way. When listing the connections it will only list connections from that node down. Listing nodes will not go back to the root/first node.
EDIT:
by using only one.list_connections(); the output should be
List: Start
Node[this][7731340]: ONE
Node[i=0][7731288]: TWO
Node[i=1][7731340]: ONE
List: Start
Node[this][7731288]: TWO
Node[i=0][7731288]: TWO
Node[i=1][7731236]: THREE
List: Start
Node[this][7731236]: THREE
Node[i=0][7731184]: FOUR
Node[i=1][7731288]: TWO
List: Start
Node[this][7731184]: FOUR
Node[i=0][7731340]: ONE
Thank you StephanH for pointing it out.
You have to tackle a common place problem (avoid cycles) in graph theory. You may create a simple Path class to track if a node was already/or is currently printed in the current recursion stack. Therefore, you have to check if the new node is already in the recursion stack. Let's use the standard std::find() applied to an integer vector storing node ids. For readability and easier useage I wrapped it in bool Path::closeCycle(int nid). Since a path could consist at most of |N| elements the Path class could also represented by a n-dimensional vector<bool> which would avoid using std::find(). This could increase performance, but this perhaps depends on the structure of your graph (long paths+few nodes vs. short paths+hugh amount of nodes vs. something between vs. extrems).
In node.h
#include <cstdlib>
#include <string>
#include <vector>
#include <algorithm>
class Path
{
std::vector<int> vals;
public:
Path();
bool closeCycle(int nid)const;
void add(int nid);
};
class Node {
private:
int id;
std::vector<Node*> nodes;
std::string data;
public:
Node(int id) : id(id)
{
printf("Status: Created [%d]\n", this);
}
void connect(Node& node)
{
nodes.push_back(&node);
printf("Status: Node [%d] Connected To [%d]\n", this, &node);
}
void input_data(std::string str_in)
{
data = str_in;
}
void list_connections(const Path& path = Path());
inline int getId()const { return id; }
};
In node.cpp
#include "header.h"
void Node::list_connections(const Path& path)
{
printf("List: Start\n");
printf("Node[this][%d]: %s\n", this, data.c_str());
Path npath(path);
npath.add(id);
for (size_t i = 0; i < nodes.size(); i++)
{
if (!npath.closeCycle(nodes[i]->id))
{
printf("Node[i=%d][%d]: %s\n", i, nodes[i], nodes[i]->data.c_str());
nodes[i]->list_connections(npath);
}
}
printf("List: %s End\n", data.c_str());
}
Path::Path()
{
}
bool Path::closeCycle(int nid) const
{
return std::find(vals.begin(), vals.end(), nid) != vals.end();
}
void Path::add(int nid)
{
vals.push_back(nid);
}
Your main.cpp
void main()
{
Node one(1);
one.input_data("ONE");
Node two(2);
two.input_data("TWO");
Node three(3);
three.input_data("THREE");
Node four(4);
four.input_data("FOUR");
one.connect(two);
one.connect(one);
two.connect(two);
two.connect(three);
three.connect(four);
four.connect(one);
three.connect(two);
one.list_connections();
std::cout << "\n\n";
two.list_connections();
std::cout << "\n\n";
three.list_connections();
std::cout << "\n\n";
four.list_connections();
std::cout << "\n\n";
system("pause");
}

Seg fault at the specified line: Hash table insert/search functions

I am getting a EXC_BAD_ACCESS error. I'm trying to insert words into a hash table and am using separate chaining. Here is my class Hash.h that has, within it, class wordData to store the word and pageNumbers the word appears on:
class Hash
{
private:
class wordData
{
public:
string word;
vector < int >pageNum;
wordData *nextWord;
// Initializing the next pointer to null in the constructor
wordData()
{
nextWord = nullptr;
}
// Constructor that accepts a word and pointer to next word
wordData(string word, wordData * nextWord)
{
this->word = word;
this->nextWord = nextWord;
}
// Getting and setting the next linked word
wordData *getNext()
{
return nextWord; //-------------------> BAD_ACCESS ERROR
}
void setNext(wordData * newInfo)
{
nextWord = newInfo;
}
// Setting info for the word node.
void setInfo(string & w, int pNum)
{
this->word = w;
this->pageNum.push_back(pNum);
}
// ******************* Gives a thread-bad access error************************
string getWord()
{
return word;
}
void addPageNums(int x)
{
this->pageNum.push_back(x);
}
};
private:
// Head to point to the head node of the linked list for a particular word
wordData ** head;
int size;
int *bucketSize;
int totalElements;
public:
// Class hash function functions
Hash();
// Function to calculate bucket number based on string passed
int hashFunction(string key);
// search if word is present
bool Search(string);
// Insert word
void Insert(string, int);
int bucketNumberOfElements(int index);
};
#endif /* Hash_h */
After running the debugger I found the value of nextWord to be 0x00000000000 which I understand is not the same as nullptr but is due to a NULL assignment although I can't seem to figure out where and why. I haven't included the Hash.cpp file because I think there is an obvious pointer manipulation that I'm doing wrong in the .h file.
Any help will be appreciated. Thanks.

Hash table implementation in C++

I am trying the following code for Hash table implementation in C++. The program compiles and accepts input and then a popup appears saying " the project has stopped working and windows is checking for a solution to the problem. I feel the program is going in the infinite loop somewhere. Can anyone spot the mistake?? Please help!
#include <iostream>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
/* Definitions as shown */
typedef struct CellType* Position;
typedef int ElementType;
struct CellType{
ElementType value;
Position next;
};
/* *** Implements a List ADT with necessary functions.
You may make use of these functions (need not use all) to implement your HashTable ADT */
class List{
private:
Position listHead;
int count;
public:
//Initializes the number of nodes in the list
void setCount(int num){
count = num;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
//Inserts an element after Position p
int insertList(ElementType data, Position p){
Position temp;
temp = p->next;
p->next = new CellType;
p->next->next = temp;
p->next->value = data;
return ++count;
}
//Returns pointer to the last node
Position end(){
Position p;
p = listHead;
while (p->next != NULL){
p = p->next;
}
return p;
}
//Returns number of elements in the list
int getCount(){
return count;
}
};
class HashTable{
private:
List bucket[10];
int bucketIndex;
int numElemBucket;
Position posInsert;
string collision;
bool reportCol; //Helps to print a NO for no collisions
public:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
}
collision = "";
reportCol = false;
}
int insert(int data){
bucketIndex=data%10;
int col;
if(posInsert->next==NULL)
bucket[bucketIndex].insertList(data,posInsert);
else { while(posInsert->next != NULL){
posInsert=posInsert->next;
}
bucket[bucketIndex].insertList(data,posInsert);
reportCol=true;}
if (reportCol==true) col=1;
else col=0;
numElemBucket++;
return col ;
/*code to insert data into
hash table and report collision*/
}
void listCollision(int pos){
cout<< "("<< pos<< "," << bucketIndex << "," << numElemBucket << ")"; /*codeto generate a properly formatted
string to report multiple collisions*/
}
void printCollision();
};
int main(){
HashTable ht;
int i, data;
for (i=0;i<10;i++){
cin>>data;
int abc= ht.insert(data);
if(abc==1){
ht.listCollision(i);/* code to call insert function of HashTable ADT and if there is a collision, use listCollision to generate the list of collisions*/
}
//Prints the concatenated collision list
ht.printCollision();
}}
void HashTable::printCollision(){
if (reportCol == false)
cout <<"NO";
else
cout<<collision;
}
The output of the program is the point where there is a collision in the hash table, thecorresponding bucket number and the number of elements in that bucket.
After trying dubbuging, I come to know that, while calling a constructor you are not emptying the bucket[bucketIndex].
So your Hash Table constructor should be as follow:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
bucket[i].makeEmptyList(); //here we clear for first use
}
collision = "";
reportCol = false;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
what you can do is you can get posInsert using
bucket[bucketIndex].end()
so that posInsert-> is defined
and there is no need to
while(posInsert->next != NULL){
posInsert=posInsert->next;
because end() function is doing just that so use end() function

How to use Doubly Linked List with Dynamic Array?

My homework is about making a schedule with doubly-linked list. We can create a dynamic array for keeping days. But every day has to have a doubly-linked list which contains time slots. Vectors and arrays are forbidden from use, instead of linked lists. I have difficulty about functions.
This is my header file:
#ifndef _SCHEDULE_H
#define _SCHEDULE_H
#include <string>
using namespace std;
struct Node
{
string courseName;
int time;
Node *next; //forward direction
Node *prev; //backward direction
Node::Node() {}
Node::Node(const string &cName,const int&time, Node * pRight, Node * pLeft)
: courseName(cName),time(time),next(pRight), prev(pLeft)
{}
};
class Schedule
{
public:
Schedule(); //Constructor
//adding new course depend on time
void addCourse(string courseName, char day, int time,Node *Days[6]);
// delete course depend on time
void deleteCourse(char day, int time,Node *Days[6]);
// display a particular course's time
void displayCourse(string courseName,Node *Days);
//prints schedule
void print(Node *Days);
private:
Node *head; //Head node, start of a linked list based on Day
Node *tail; //Tail node, end of a linked list based on Day
};
#endif
Here's my implementation file:
#include <iostream>
#include "Schedule.h"
using namespace std;
Schedule::Schedule()
{
head=new Node(" ",0,NULL,NULL);
tail = NULL;
}
void Schedule::addCourse(string courseName, char day, int time,Node *Days[6])
{
int i;
if (day=='M')
{i=0;}
else if(day=='T')
{i=1;}
else if(day=='W')
{i=2;}
else if(day=='R')
{i=3;}
else if(day=='F')
{i=4;}
else if(day=='S')
{i=5;}
Node*cur=Days[i]->next=head;
if(Days[i]->next==NULL)
{
Days[i]=new Node;
Days[i]->next->courseName=courseName;
Days[i]->time=time;
Days[i]->next=NULL;
Days[i]->prev=NULL;
cout<<"The course "<<courseName<<" is added on "<<day<<" "<<time<<endl;
}
else if(time<Days[i]->next->time && time!=Days[i]->next->time)
{
Node*newcourse=new Node;
//Days[i]=new Node;
Days[i]->next->courseName=courseName;
Days[i]->next->time=time;
Days[i]->next=head;
Days[i]->prev=NULL;
Days[i]->next=newcourse;
cout<<"The course "<<courseName<<" is added on "<<day<<" "<<time<<endl;
}
else if(time>Days[i]->next->time)
{
while(Days[i]->next!=NULL && Days[i]->next->time<time && Days[i]->next->time!=time)
{
Days[i]->next=Days[i]->next->next;
}
if(Days[i]->next->time==time)
{
cout<<"Time conflict"<<endl;
}
else
{
Node*newcourse=new Node;
Days[i]->next->courseName=courseName;
Days[i]->next->time=time;
Days[i]->next=Days[i]->next->next;
Days[i]->prev=Days[i]->next;
Days[i]->next->next=newcourse;
cout<<"The course "<<courseName<<" is added on "<<day<<" "<<time<<endl;
}
}
}
void Schedule::deleteCourse(char day, int time,Node *Days[6])
{
int d;
if (day=='M')
{d=1;}
else if(day=='T')
{d=1;}
else if(day=='W')
{d=2;}
else if(day=='R')
{d=3;}
else if(day=='F')
{d=4;}
else if(day=='S')
{d=5;}
Node*cur=Days[d]->next=head;
if(Days[d]->next==NULL)
{
cout<<"Schedule is empty for this day"<<endl;
}
else
{
}
}
void Schedule::displayCourse(string courseName,Node *Days)
{
}
void Schedule::print(Node *Days)
{
}
Here is my main:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "Schedule.h"
using namespace std;
Node *Days = new Node[6];
void CoutSelection()
{
cout<<endl<<endl;
cout<<"Welcome to Schedule Maker. Please select an option:"<<endl;
cout<<" 1) Load the course schedule from a known file"<<endl;
cout<<" 2) Add a time slot manually"<<endl;
cout<<" 3) Remove a time slot manually"<<endl;
cout<<" 4) Print a particular course's time slot"<<endl;
cout<<" 5) Print all schedule"<<endl;
cout<<" 6) Exit" <<endl;
cout<<endl;
cout<<" Please enter your selection as 1-2-3-4-5-6"<<endl;
cout<<endl;
}
int main()
{
int selection;
CoutSelection();
cin>>selection;
Schedule list;
while (selection!=6)
{
if (selection==1)
{ string fileName;
cout<<"Please enter the filename that you want to load"<<endl;
cin>>fileName;
ifstream input;
input.open(fileName);//open file
if(!input.is_open())//control if correctly open
{
cout<<"Couldn't open input file: "<<fileName<<endl;
}
else
{
string cname,line; //course name and day identifier
char day;
int time; //time
while(!input.eof())
{getline(input, line);
stringstream ss(line);
int num;
ss>>cname>>day>>num;
list.addCourse(cname,day,time,*Days[6]);
}
}
}
else if (selection==2)
{
int timeAdded;
string cnameAdded;
char dayAdded;
cout<<"Please enter course name,day and it's time that you want to add like : coursename dayidentifier time"<<endl;
cout<<"Enter the day as M/T/W/R/F/S. (MONDAY:M, TUESDAY:T, WEDNESDAY:W, THURSDAY:R, FRIDAY:F, SATURDAY:S)"<<endl;
cin>>cnameAdded>>dayAdded>>timeAdded;
list.addCourse(cnameAdded,dayAdded,timeAdded,*Days[6]);
}
else if(selection==3)
{
char dayDeleted;
int timeDeleted;
cout<<"Please enter the day and time that you want to delete like : dayidentifider time"<<endl;
cout<<"Enter the day as M/T/W/R/F/S. (MONDAY:M, TUESDAY:T, WEDNESDAY:W, THURSDAY:R, FRIDAY:F, SATURDAY:S)"<<endl;
cin>>dayDeleted>>timeDeleted;
list.deleteCourse(dayDeleted,timeDeleted,*Days[6]);
}
else if(selection==4)
{
string coursedisplayed;
cout<<"Please enter course name that you want to display"<<endl;
cin>>coursedisplayed;
list.displayCourse(coursedisplayed,*Days);
}
else if(selection==5)
{
list.print(*Days);
}
CoutSelection();
cin>>selection;
}
return 0;
}
What is wrong with my code? If I handle one of the functions, I'm sure I can do other functions.
Errors :
error C2664: 'Schedule::addCourse' : cannot convert parameter 4 from 'Node' to 'Node *[]'
IntelliSense: no operator "*" matches these operands
operand types are: * Node
Aside from all the problems presented by #WhozCraig, which I think you should tackle for your own good. Your compiler is talking to you, and it is telling you that your addCourse method receives a pointer to a Node Array.
But in your main you called it with the following list.addCourse(cname,day,time,*Days[6]);. By doing *Days[6] you are telling the method you want to send what is pointed by Days[6]. Thus your compiler is receiving a Node object and not a pointer to a node array.
Try it with the following list.addCourse(cname,day,time,Days);, this will send the pointer to the first element in days.
One pointer to keep in mind, which you'll teacher will likely notice:
You have memory leaks, which is another VERY important subject.

How store class objects in vector<vector<class *>> and access and pass them to function either by reference or value

#ifndef BINARY_TREE_H
#define BINARY_TREE_H
#include<iostream>
#include<vector>
using namespace std;
class Binary_Tree;
static int levelCount=0;
extern vector<vector<Binary_Tree*>> vec;
extern vector<Binary_Tree*> tempVec;
class Binary_Tree
{
public:
Binary_Tree()
{
childNum=0;
data=0;
level=0;
prev=NULL;
next[0]=NULL;
next[1]=NULL;
};
Binary_Tree(int d)
{
childNum=0;
data=d;
level=0;
prev=NULL;
next[0]=NULL;
next[1]=NULL;
levelCount++;
}
void insert_node(int,int,int);
int get_level();
int get_childCount();
friend int set_childNum(Binary_Tree*);
private:
int childNum;
int data;
int level;
Binary_Tree *prev;
Binary_Tree *next[2];
};
#endif // BINARY_TREE_H
Here is the implementation file
#include<iostream>
#include<cmath>
#include "Binary_Tree.h"
using namespace std;
void Binary_Tree::insert_node(int lev, int d, int sib)
{
if(vec.empty())
{
cout<<"You Have to create Root first";
}
else
{
if(set_childNum(vec[lev][sib-1])==0)
{
cout<<"Child cant be created parent Node already has two childs.";
}
else
{
childNum=set_childNum(vec[lev][sib-1]);
data=d;
level=lev+1;
prev=vec[lev][sib];
next[0]=NULL;
next[1]=NULL;
tempVec.clear();
for(int i=0; i<pow(2,(lev+1)); i++)
{
if(i==childNum-1)
{
tempVec.push_back(this);
}
else
tempVec.push_back(vec[lev][i]);
}
vector<vector<Binary_Tree*>>::iterator itr=vec.begin()+(lev+1);
vec.erase(itr);
vec.insert(itr,tempVec);
}
}
}
int set_childNum(Binary_Tree *lstNdAdr)
{
if(lstNdAdr->get_childCount()==0)
return 1;
else if(lstNdAdr->get_childCount()==1)
return 2;
else
return 0;
}
int Binary_Tree::get_level()
{
return level;
}
int Binary_Tree::get_childCount()
{
if(next[0]==NULL)
{
return 0;
}
else if(next[0]!=NULL && next[1]==NULL)
{
return 1;
}
else
{
return 2;
}
}
MAIN.cpp
#include <iostream>
#include<cmath>
#include"Binary_Tree.h"
using namespace std;
vector<vector<Binary_Tree*>> vec;
vector<Binary_Tree*> tempVec;
int main()
{
Binary_Tree tree;
here:
cout<<"Enter your Choice:1.Create Root Of Tree\n"
<<"2.Insert node\n"<<endl;
int choice;
cin>>choice;
switch(choice)
{
case 1:
{
int d;
cout<<"Enter Data to insert: ";
cin>>d;
Binary_Tree treeDummy(d);
tree=treeDummy;
tempVec.push_back(&tree);
vec.push_back(tempVec);
}
break;
case 2:
{
int lev;
int sibbling;
int d;
cout<<"Enter at which level and data and parent's sibling-no.: ";
cin>>lev;
cin>>d;
cin>>sibbling;
if(sibbling>pow(2,lev))
cout<<"Illegal Sibbling Number."<<endl;
else
tree.insert_node(lev,d,sibbling);
}
break;
}
int x;
cin>>x;
if(x==5)
{
cout<<endl<<endl;
goto here;
}
return 0;
}
in above code i am trying to create a binary tree type structure which can be manipulated and traversed dynamically that is any node can be inserted and can be removed at run time (although its incomplete because i am stuck at a problem). While pushing back the tempVec vector the code produces a segmentation fault and i am also doubtful in passing the object stored in vetcor> vec to the functions in the implementation (I am new to Stl and first time dealing with vector of vectors containing pointer to the class types)
The nested vector's entries are only filled if i is set to 1. But you attempt to access its element [0][0] regardless. You have out of bounds access when i is not 1.
There are numerous problems present in your code, that and combined with the poor style and formatting makes it not so fun to debug.
Binary_Tree treeDummy(d);
tree = treeDummy;
tempVec.push_back(&tree);
I'm not sure what you're trying to do here but the above looks wrong. You are shallow copying treeDummy's data over to tree. You'll lose the link to whatever child node tree points to. Afterwards you're pushing that same tree instance into your temporary vector. That means all the elements in your vector ends up pointing to the local variable tree in main. So even if no segfault occurred you would run into aliasing problems since they all refer to the same tree object and not a separate unique BinaryTree instance.
vector< vector<Binary_Tree*> >::iterator itr=vec.begin()+(lev+1);
vec.erase(itr);
vec.insert(itr,tempVec);
Your BinaryTree::insert_node is using an invalidated iterator after performing erase which is undefined behavior.
childNum = set_childNum(vec[lev][sib-1]);
// ...
prev = vec[lev][sib];
The above can access an out-of-bound index in your vector. eg. You push_back a tempVec with only 1 element in it and then call insert_node with sib = 1.
// ...
if(x == 5)
{
cout<<endl<<endl;
goto here;
}
The use of goto is also completely unnecessary here and should be replaced with a traditional while loop that checks for condition != 5.
The higher level problem in your program, however, is that there's no clear constraints and invariants in its design. What assumptions and preconditions do each of those functions need to work? Why use vectors to hold BinaryTree nodes when the class itself should be dealing with that. You should get the overall design sorted out first, otherwise you'll just play whack-a-mole as other bugs crop up.