i am having an infinite loop after it tries to insert "b" into the list.
based on my output when i run "make test | more", it inserts "a" just fine, but when it reaches "b" and tries to call the copy constructor again, thats when it gets into an infinite loop
here is my header file
#define DLIST_HEADER
#include <string>
struct DListNodeT;
class DListT{
public:
DListT();
DListT(const DListT & src);
~DListT();
DListT & operator = (const DListT & rhs);
void Home();
void Left();
void Right();
std::string Data() const;
size_t Size() const;
void Insert(std::string newData);
void InsertAfter(std::string newData);
void Delete();
private:
DListNodeT* head;
DListNodeT* current;
size_t nodeCount;
};
#endif
here is my cpp file
#include "DListT.h"
using namespace std;
void DeleteList(DListNodeT * list);
DListNodeT * CopyList(DListNodeT * src);
void AdjustCurrent(DListNodeT * srcList, DListNodeT * destList, DListNodeT * srcCurrent, DListNodeT * & destCurrent);
struct DListNodeT
{
string data;
DListNodeT * next{nullptr};
DListNodeT * prev{nullptr};
};
DListT::DListT()
{
//DListNodeT * tmp{nullptr};
//tmp.data = "hi";
//tmp = new DListNodeT;
head = nullptr;
current = nullptr;
nodeCount = 0;
}
DListT::DListT(const DListT & src)
{
cout << "calling copy constructor" << endl;
//this was added after this was graded
nodeCount = src.nodeCount;
head = CopyList(src.head);
AdjustCurrent(src.head, head, src.current, current);
cout << "exiting copy constructor" << endl;
/*DListNodeT * travel{nullptr};
DListNodeT * tmp{nullptr};
DListNodeT * tail{nullptr};
head = nullptr;
travel = src.head;
while (travel != nullptr)
{
tmp = new DListNodeT;
tmp->data = travel->data;
tmp->next = nullptr;
//tmp->prev = nullptr;
if (head == nullptr)
{
head = tmp;
}
else
{
tail->next = tmp;
//tail->prev = tmp;
}
tail = tmp;
travel = travel->next;
//travel = travel->prev;
}
nodeCount = src.nodeCount;*/
}
DListT::~DListT()
{
DeleteList(head);
}
DListT & DListT::operator = (const DListT & rhs)
{
if (this != &rhs)
{
DeleteList(head);
head = CopyList(rhs.head);
nodeCount = rhs.nodeCount;
AdjustCurrent(rhs.head, head, rhs.current, current);
}
return *this;
}
void DeleteList(DListNodeT * list)
{
DListNodeT * tmp{nullptr};
DListNodeT * garbage{nullptr};
if (list != nullptr)
{
tmp = list;
do
{
garbage = tmp;
tmp = garbage->next;
delete garbage;
} while (tmp != list);
}
}
DListNodeT * CopyList(DListNodeT * src)
{
DListNodeT * head{nullptr};
DListNodeT * trace1{nullptr};
DListNodeT * trace2{nullptr};
DListNodeT * tmp{nullptr};
if (src == nullptr)
{
head = nullptr;
}
else
{
//set up head pointer
cout << "setting up new head" << endl;
head = new DListNodeT;
cout << "set new head" << endl;
cout << "setting head's data to src's data" << endl;
head->data = src->data;
cout << "set head's data to src's data" << endl;
cout << "setting head's next to head" << endl;
head->next = head;
cout << "set head's next to head" << endl;
cout << "setting head's prev to head" << endl;
head->prev = head;
cout << "set head's prev to head" << endl;
//copy rest of list
cout << "setting trace1 to src's next" << endl;
trace1 = src->next;
cout << "set trace1 to src's next" << endl;
cout << "setting trace2 to head" << endl;
trace2 = head;
cout << "set trace2 to head" << endl;
while (/*trace1 != head*/ trace1 != src)
{
cout << "in copylist while loop" << endl;
//build new nodes
cout << "creating a new tmp node" << endl;
tmp = new DListNodeT;
cout << "created the tmp node" << endl;
cout << "setting tmp's data to trace1's data" << endl;
tmp->data = trace1->data;
cout << "set tmp's data to trace1's data" << endl;
cout << "setting tmp's next to null" << endl;
tmp->next = nullptr;
cout << "set tmp's next to null" << endl;
cout << "data is: " << tmp->data << endl;
//link into list
cout << "setting trace2's next to tmp" << endl;
trace2->next = tmp;
cout << "set trace2's next to tmp" << endl;
cout << "settings tmp's prev to trace2" << endl;
tmp->prev = trace2;
cout << "set tmp's prev to trace2" << endl;
cout << "data is: " << tmp->data << endl;
//make it circular
cout << "setting tmp's next to head" << endl;
tmp->next = head;
cout << "set tmp's next to head" << endl;
cout << "setting head's prev to tmp" << endl;
head->prev = tmp;
cout << "set head's prev to tmp" << endl;
cout << "data is: " << tmp->data << endl;
//advance next two pointers
cout << "setting trace2 to tmp" << endl;
trace2 = tmp;
cout << "set trace2 to tmp" << endl;
cout << "setting trace1 to trace1's next" << endl;
trace1 = trace1->next;
cout << "set trace1 to trace1's next" << endl;
cout << "data is: " << tmp->data << endl;
//cout << "nodecount is: " << nodeCount << endl;
}
}
return head;
}
void AdjustCurrent(DListNodeT * srcList, DListNodeT * destList, DListNodeT * srcCurrent, DListNodeT * & destCurrent)
{
DListNodeT * tmp{nullptr};
if (srcCurrent == nullptr)
{
destCurrent = nullptr;
}
else
{
tmp = srcList;
destCurrent = destList;
while (tmp != nullptr and tmp != srcCurrent)
{
tmp = tmp->next;
destCurrent = destCurrent->next;
}
}
}
void DListT::Insert(string newData)
{
cout << "entering insert function" << endl;
DListNodeT * tmp{nullptr};
DListNodeT * tail{nullptr};
tmp = new(DListNodeT);
tmp->data = newData;
tmp->next = nullptr;
tmp->prev = nullptr;
cout << "inserting an element into list" << endl;
nodeCount++;
// ASSUME
// INVARIANT: (head == nullptr) == (current == nullptr)
// if head is null, current is null.
// if head is NOT null, current is NOT null
if (head == nullptr)
{
cout << "entering if statement for empty list" << endl;
// we have an empty list, there are no nodes.
// the node we just created becomes the head/tail/current
tmp->next = tmp;
tmp->prev = tmp;
current = tmp;
head = tmp;
cout << "exiting if statment for empty list" << endl;
}
else if (current == head)
{
cout << "enterting if state where current is equal to the head of the list" << endl;
// this is a special case: when current points to the head,
// we will insert the new node _before_ the current one (head of the list)
tmp->next = head;
tmp->prev = head->prev;
head->prev = tmp;
current = tmp;
head = tmp;
cout << "exiting if statement where current is equal to the head of the list" << endl;
}
else
{
cout << "entering else statment from insert function" << endl;
// we have a non-empty list and we want to append to the end
// so we insert the new node at the current node
tail = current->prev;
tmp->prev = tail;
tmp->next = current;
tail->next = tmp;
current->prev = tmp;
current = tmp;
cout << "exiting else statement from insert function" << endl;
}
cout << "exiting insert function" << endl;
}
void DListT::Delete()
{
DListNodeT * tmp{nullptr};
DListNodeT * next{nullptr};
DListNodeT * prior{nullptr};
if (current == nullptr)
{
cout << "Error: Attempt to delete in an Empty List.";
}
else if (nodeCount == 1)
{
//USELESS current = tmp;
current = nullptr;
head = nullptr;
delete tmp;
}
else
{
// the node we're about to delete is also the head...
// reposition the head to the node after; otherwise it would
// point to the node we just deleted.
if (current == head) {
head = current->next;
}
// unlink the current node
prior = current->prev;
next = current->next;
prior->next = next;
next->prev = prior;
tmp = current;
current = prior;
delete tmp;
}
}
size_t DListT::Size() const
{
return nodeCount;
}
void DListT::Home()
{
if (head != nullptr)
{
current = head;
}
}
void DListT::Right()
{
if (current != nullptr)
{
current = current->next;
}
}
void DListT::Left()
{
if (current != nullptr)
{
current = current->prev;
}
}
void DListT::InsertAfter(string newData)
{
DListNodeT * tmp{nullptr};
DListNodeT * seek{nullptr};
tmp = new(DListNodeT);
tmp->data = newData;
tmp->next = nullptr;
tmp->prev = nullptr;
nodeCount++;
if (head == nullptr)
{
tmp->next = tmp;
tmp->prev = tmp;
current = tmp;
head = tmp;
}
else
{
// node after current; will now be after tmp
seek = current->next;
tmp->next = seek;
tmp->prev = current;
current->next = tmp;
seek->prev = tmp;
current = tmp;
}
}
string DListT::Data() const
{
string data;
if (current != nullptr)
{
data = current->data;
}
else
{
cout << "Error: Attempt to access Empty List.";
data = "NO DATA";
}
return data;
}
here is my professor's test code
#include<boost/test/included/unit_test.hpp>
#include<boost/test/unit_test.hpp>
#include <boost/test/output_test_stream.hpp>
#include <vector>
#include "DListT.h"
using namespace std;
using boost::test_tools::output_test_stream;
void Header(string s) {
cout << endl;
cout << "******* Running " << s << " *******" << endl;
}
void Footer(string s) {
cout << "******* Finished with " << s << " *******" << endl;
cout << endl;
}
BOOST_AUTO_TEST_SUITE( DListTTest )
BOOST_AUTO_TEST_CASE(constructor_test) {
DListT list;
Header("Constructor Test");
BOOST_CHECK_MESSAGE(list.Size() == 0, "Constructor Test, Size not 0");
Footer ("Constructor Test");
}
void Compare(DListT list, vector<string> check) {
size_t i;
cout << "in compare" << endl;
if (list.Size() != check.size()) {
BOOST_FAIL("Sizes not the same in Compare");
} else {
for(i = 0; i < check.size(); i++) {
BOOST_CHECK(list.Data() == check[i]);
list.Right();
}
}
cout << "exiting compare" << endl;
return;
}
void CompareHome(DListT list, vector<string> check) {
// we don't know that current is pointing to the right thing.
list.Home();
cout << "entering comparehome" << endl;
Compare(list, check);
cout << "exiting comparehome" << endl;
}
// not really checking current directly.
// since both are at the "same" value of current, they should be the same.
// this will not work if the pattern repeats and the current pointer is at
// a offset
//
void CompareLists(DListT & a, DListT & b) {
size_t i;
if (a.Size() != b.Size()) {
BOOST_FAIL("Sizes not the same in CompareLists");
} else {
for(i = 0; i < a.Size(); i++) {
BOOST_CHECK(a.Data() == b.Data());
a.Right();
b.Right();
}
BOOST_CHECK(a.Data() == b.Data());
}
}
BOOST_AUTO_TEST_CASE(insert_test) {
DListT list;
vector<string> check;
Header("Insert Test");
CompareHome(list, check);
// head->A
list.Insert("A");
cout << "inserting a" << endl;
check = {"A"};
CompareHome(list, check);
// head->B<->A
list.Insert("B");
cout << "inserting b" << endl;
for (size_t i = 0; i <= list.Size(); i++)
{
cout << "list has: " << list.Data() << endl;
cout << "i is: " << i << endl;
list.Right();
}
list.Home();
check = {"B","A"};
CompareHome(list, check);
// head->B<->C<->A
list.Home();
list.Right();
list.Insert("C");
check = {"B","C","A"};
CompareHome(list, check);
// head->D<->B<->C<->A
list.Home();
list.Insert("D");
check = {"D","B","C","A"};
CompareHome(list, check);
// head->D<->B<->C<->E<->A
list.Home();
list.Left();
list.Insert("E");
check = {"D","B","C","E","A"};
CompareHome(list, check);
// head->D<->B<->C<->E<->A
list.Home();
list.Left();
list.Left();
list.Left();
list.Insert("F");
check = {"D","B","F","C","E","A"};
CompareHome(list, check);
Footer("Insert Test");
}
BOOST_AUTO_TEST_CASE(copy_test) {
DListT list1, list2;
Header("Copy-Copy Constructor Test");
// check empty lists
// the first case should have an output error for now. Just supress it
output_test_stream output;
streambuf * old = cout.rdbuf(output.rdbuf());
CompareLists(list1, list2);
cout.rdbuf(old);
// check list with single element
list1.Insert("A");
list2 = list1;
CompareLists(list1, list2);
DListT list3(list1);
CompareLists(list1, list3);
// check lists with two elements
list1.Insert("B");
list2 = list1;
CompareLists(list1, list2);
DListT list4(list1);
CompareLists(list1, list4);
// let's try a handful of elements.
list1.Insert("C");
list1.Insert("D");
list1.Insert("E");
list2 = list1;
CompareLists(list1, list2);
DListT list5(list1);
CompareLists(list1, list5);
// did we get the current pointer right?
list1.Right();
list1.Right();
list1.Right();
list2 = list1;
CompareLists(list1, list2);
DListT list6(list1);
CompareLists(list1, list6);
Footer("Copy-Copy Constructor Test");
}
BOOST_AUTO_TEST_CASE(empty_data_access_test) {
DListT list;
Header("Empty Data Access Test");
// set up a stream buffer to capture the output
output_test_stream output;
// cause output to occur.
streambuf * old = cout.rdbuf(output.rdbuf());
string x = list.Data();
// restore the stdout buffer
cout.rdbuf(old);
BOOST_CHECK( !output.is_empty( false ) );
BOOST_CHECK( output.is_equal( "Error: Attempt to access Empty List.\n" ) );
BOOST_CHECK( x == "NO DATA");
Footer("Empty Data Access Test");
}
BOOST_AUTO_TEST_CASE(left_right_home_test) {
Header("Movement Test");
DListT list, listCopy;
vector<string> check;
list.Insert("D");
list.Insert("C");
list.Insert("B");
list.Insert("A");
list.Home();
check = {"A","B","C","D"};
listCopy = list;
Compare(listCopy,check);
list.Right();
check = {"B","C","D","A"};
listCopy = list;
Compare(listCopy,check);
list.Right();
check = {"C","D","A","B"};
listCopy = list;
Compare(listCopy,check);
list.Right();
check = {"D","A","B","C"};
listCopy = list;
Compare(listCopy,check);
list.Right();
check = {"A","B","C","D"};
listCopy = list;
Compare(listCopy,check);
list.Home();
list.Left();
check = {"D", "A","B","C"};
Compare(list,check);
list.Left();
check = {"C", "D", "A","B"};
Compare(list,check);
list.Left();
check = {"B", "C", "D", "A"};
Compare(list,check);
list.Left();
check = {"A", "B", "C", "D"};
Compare(list,check);
Footer("Movement Test");
}
BOOST_AUTO_TEST_CASE(delete_test) {
Header("Delete Test");
DListT list;
vector<string> check;
list.Insert("G");
list.Insert("F");
list.Insert("E");
list.Insert("D");
list.Insert("C");
list.Insert("B");
list.Insert("A");
check = {"A","B","C","D","E","F","G"};
CompareHome(list,check);
// delete the head of the list
list.Home();
list.Delete();
// delete the last item in the list;
list.Home();
list.Left();
list.Delete();
check = {"B","C","D","E","F"};
CompareHome(list,check);
// delete the second to last item
list.Home();
list.Left();
list.Left();
list.Delete();
check = {"B","C","D","F"};
CompareHome(list,check);
// delete the second item
list.Home();
list.Right();
list.Delete();
check = {"B","D","F"};
CompareHome(list,check);
list.Home();
list.Delete();
check = {"D","F"};
CompareHome(list,check);
list.Home();
list.Delete();
check = {"F"};
CompareHome(list,check);
list.Delete();
check = {};
CompareHome(list,check);
Footer("Delete Test");
}
BOOST_AUTO_TEST_SUITE_END()
here is my makefile
CXXFLAGS = -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion -Werror -std=c++17
OBJS = DListTTest
all: ${OBJS}
test: DListTTest
./DListTTest
memcheck: DListTTest
valgrind --leak-check=summary ./DListTTest
DListTTest: DListT.o
clean:
rm -f ${OBJS} *.o
I'm implementing a Red Black Tree in C++ and I'm stuck on fixing color violations after insertion.
My left and right rotations seem to work fine but the colors in right branches of the tree are never getting fixed correctly. I think I covered all the cases in my fixViolation(Node*n) method but maybe I'm wrong.
I will also appreciate all other advice and tips on my code. pastebin link to my code
My code:
#include "pch.h"
#include <iostream>
#include <random>
#include <string>
#include <functional>
using namespace std;
enum Color { Black, Red };
template<typename T>
class RBTree;
template <typename T>
class Node
{
friend class RBTree<T>;
T data;
Color color;
Node* parent;
Node* leftChild;
Node* rightChild;
public:
Node()
{
this->parent = nullptr;
this->leftChild = nullptr;
this->rightChild = nullptr;
color = Red;
}
void gibColor(Node<T>*x)
{
if (x->color == Black)
cout << "black";
else
cout << "red";
}
};
template <typename T>
class RBTree
{
Node<T>* root;
int size;
public:
RBTree()
{
root = nullptr;
size = 1;
}
void leftRotate(Node<T>*child, Node<T>*parent)
{
child = parent->rightChild;
parent->rightChild = child->leftChild;
if (child->leftChild != nullptr)
{
child->leftChild->parent = parent;
}
child->parent = parent->parent;
if (parent->parent == nullptr)
{
root = child;
}
else if (parent == parent->parent->leftChild)
{
parent->parent->leftChild = child;
}
else {
parent->parent->rightChild = child;
}
child->leftChild = parent;
parent->parent = child;
}
void rightRotate(Node<T>*child, Node<T>*parent)
{
child = parent->leftChild;
parent->leftChild = child->rightChild;
if (child->rightChild != nullptr)
{
child->rightChild->parent = parent;
}
child->parent = parent->parent;
if (parent->parent == nullptr)
{
root = child;
}
else if (parent == parent->parent->rightChild)
{
parent->parent->rightChild = child;
}
else
{
parent->parent->leftChild = child;
}
child->rightChild = parent;
parent->parent = child;
}
void fixViolation(Node<T>*n)
{
Node<T>*grandparent;
Node<T>*parent;
//Node<T>*uncle;
parent = n->parent;
while (parent != nullptr&& parent->color == Red)
{
Node<T>*uncle;
grandparent = n->parent->parent;
if (grandparent->leftChild == parent)
{
uncle = grandparent->rightChild;
if (uncle != nullptr&&uncle->color == Red)
{
parent->color = Black;
uncle->color = Black;
grandparent->color = Red;
n = grandparent;
parent = n->parent;
}
else
{
if (parent->rightChild == n)
{
n = parent;
leftRotate(n->parent, n);
}
parent->color = Black;
grandparent->color = Red;
rightRotate(parent, grandparent);
}
}
else
{
uncle = grandparent->leftChild;
if (uncle != nullptr&&uncle->color == Red)
{
uncle->color = Black;
parent->color = Black;
grandparent->color = Red;
n = grandparent;
parent = n->parent;
}
else
{
if (parent->leftChild == n)
{
n = parent;
rightRotate(n->parent, n);
}
parent->color = Black;
grandparent->color = Red;
leftRotate(parent, grandparent);
}
}
}
root->color = Black;
}
void addElement(T el)
{
Node<T>*n = new Node<T>();
n->data = el;
n->leftChild = nullptr;
n->rightChild = nullptr;
n->color = Red;
Node<T>*temp = this->root;
Node<T>*y = nullptr;
if (root == nullptr)
{
n->color = Black;
root = n;
}
else
{
while (temp != nullptr)
{
y = temp;
if (temp->data < n->data)
{
temp = temp->rightChild;
}
else
{
temp = temp->leftChild;
}
}
n->parent = y;
if (y->data == n->data)
{
cout << "Duplikaty won!" << endl;
return;
}
if (y->data < n->data)
{
y->rightChild = n;
size = size + 1;
}
else
{
y->leftChild = n;
size = size + 1;
}
//InsertFixUp(n);
fixViolation(n);
}
}
void print(Node<T>*x)
{
//cout << "size: " << size << endl;
if (x == nullptr)
{
return;
}
if (x->parent == nullptr)
{
cout << "(" << x->data << ")";
cout << "[" << "kolor:";
x->gibColor(x);
cout << ", parent: NULL," << " l.child: ";
if (x->leftChild == nullptr)
{
cout << "NIL";
}
else
cout << x->leftChild->data;
cout << ", r.child: ";
if (x->rightChild == nullptr)
{
cout << "NIL";
}
else
cout << x->rightChild->data;
cout << "]";
cout << "-root " << endl;
//rodzic, l.dziecko, p.dziecko
}
else if (x->parent->leftChild == x)
{
//int c = x->gibColor(x);
cout << "(" << x->data << ")";
cout << "[" << "kolor:";
x->gibColor(x);
cout << ", parent: " << x->parent->data << ", l.child: ";
if (x->leftChild == nullptr)
{
cout << "NIL";
}
else
cout << x->leftChild->data;
cout << ", r.child: ";
if (x->rightChild == nullptr)
{
cout << "NIL" << "]" << endl;
}
else
cout << x->rightChild->data << "]" << endl;
}
else
{
cout << "(" << x->data << ")";
cout << "[" << "kolor:";
x->gibColor(x);
cout << ", parent: " << x->parent->data << ", l.child: ";
if (x->leftChild == nullptr)
{
cout << "NIL";
}
else
cout << x->leftChild->data;
cout << ", r.child: ";
if (x->rightChild == nullptr)
{
cout << "NIL" << "]" << endl;;
}
else
cout << x->rightChild->data << "]" << endl;
}
print(x->leftChild);
print(x->rightChild);
}
void printTree()
{
if (root == nullptr)
{
cout << "Empty tree!" << endl;
}
else
print(root);
}
};
int randomInt()
{
uniform_int_distribution<int> rozklad{ 0, 11000000 };
default_random_engine generator{ 11 };
function<int()> los{ bind(rozklad, generator) };
int l = los();
return l;
}
int main()
{
RBTree<int>* d1 = new RBTree<int>();
d1->addElement(55);
d1->addElement(69);
d1->addElement(62);
d1->addElement(71);
d1->addElement(70);
d1->addElement(14);
d1->printTree();
}
In the reverse function, I'm trying to swap the first 2 nodes only in a doubly linked list without swapping the data. It runs but it's not swapping the first 2 nodes in the list. Can someone point me in the right direction as to what I'm doing wrong?
struct node {
int data;
node * p; // FORWARD LINK
node * rp; // REVERSE LINK
};
ostream & operator<<(ostream &, const node *);
void addFront(node * & start, int);
void cleanUp(node *);
void reverse(node * &);
void main()
{
node * a = NULL;
cout << "EMPTY LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
a = NULL;
addFront(a, 10);
cout << "\nONE ELEMENT LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
a = NULL;
addFront(a, 30);
addFront(a, 20);
cout << "\nTWO ELEMENT LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
a = NULL;
addFront(a, 60);
addFront(a, 50);
addFront(a, 40);
cout << "\nTHREE ELEMENT LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
a = NULL;
addFront(a, 400);
addFront(a, 300);
addFront(a, 200);
addFront(a, 100);
cout << "\nFOUR ELEMENT LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
}
void reverse(node * & s)
{
node * n1 = s;
node * n2 = s;
if (n1 == NULL) return;
node * temp = new node;
temp->rp = n1->rp;
temp->p = n1->p;
n1->rp = n2->rp;
n1->p = n2->p;
n2->rp = temp->rp;
n2->p = temp->p;
if (n1->p != NULL)
n1->p->rp = n1;
if (n1->rp != NULL)
n1->rp->p = n1;
if (n2->p != NULL)
n2->p->rp = n2;
if (n2->rp != NULL)
n2->rp->p = n2;
delete temp;
}
void addFront(node * & start, int x)
{
node * t = new node;
t->data = x;
if (start != NULL)
{
t->p = start;
t->rp = NULL;
start->rp = t;
}
else
{
t->p = NULL;
t->rp = NULL;
}
start = t;
}
void cleanUp(node * s)
{
node * walker, *prev;
walker = s;
while (walker != NULL)
{
prev = walker;
walker = walker->p;
delete prev;
}
}
ostream & operator<<(ostream & w, const node * s)
{
const node * walker = s;
const node * trailer = walker;
w << "Forward Print " << endl;
if (s == NULL)
{
w << "EMPTY LIST";
}
else
{
while (walker != NULL)
{
w << walker->data << ' ';
trailer = walker;
walker = walker->p;
}
}
w << endl << "Reverse Print " << endl;
if (trailer == NULL)
{
w << "EMPTY LIST";
return w;
}
while (trailer != NULL)
{
w << trailer->data << ' ';
trailer = trailer->rp;
}
return w;
}
Updated with complete program.
Here's an updated reverse:
void reverse(node * & s)
{
node * n1 = s;
if (n1 == NULL) return;
node * n2 = n1->p;
if (n2 == NULL) return;
node *temp;
node *n3;
n3 = n2->p;
temp = n1->rp;
n1->p = n3;
n1->rp = n2;
n2->rp = temp;
n2->p = n1;
if (n3 != NULL)
n3->rp = n1;
s = n2;
}
NOTE: even if temp had to remain as you defined it, there was no need to allocate and delete it. I would have used node temp and replaced temp->blah with temp.blah
I am trying to figure out how to create a tree in C++. I have tried debugging this for hours and I thought it was time I got another set of eyes on it. My question is if my treeNodeClass looks correct. Right now I am getting a stack explosion because I'm double removing items from my node. The tree itself will be parsing a simple xml file. Here is my code.
#include "treeNodeClass.h"
TreeNodeClass::TreeNodeClass()
{
cout << "TREENODECLASS::TREENODECLASS()" << endl;
attributes.clear();
children.clear();
data = "";
height = 0;
parent = NULL;
tag = "";
cout << "EXIT TREENODECLASS::TREENODECLASS()" << endl;
}
TreeNodeClass::TreeNodeClass(const TreeNodeClass& other)
{
cout << "TREENODECLASS::TREENODECLASS(const other)" << endl;
parent = NULL;
CopyIntoMe(other);
cout << "EXIT TREENODECLASS::TREENODECLASS(const other)" << endl;
}
TreeNodeClass::~TreeNodeClass()
{
cout << "TREENODECLASS::~TREENODECLASS()" << endl;
if(parent)
delete parent;
parent = NULL;
children.clear();
attributes.clear();
cout << "EXIT TREENODECLASS::~TREENODECLASS()" << endl;
}
void TreeNodeClass::CreateAttrib(string root, string val)
{
string attrib = root + "=" + val;
attributes.push_back(attrib);
}
void TreeNodeClass::CreateTag(string data, string name)
{
tag = name;
this->data = data;
}
list<string> TreeNodeClass::ReturnAttrib()
{
return this->attributes;
}
string TreeNodeClass::ReturnTag(string tag)
{
string retTag = "";
if(this->tag == tag)
retTag = this->tag;
return retTag;
}
void TreeNodeClass::AddChildren(TreeNodeClass* c)
{
if(c != NULL)
children.push_back(c);
}
TreeNodeClass& TreeNodeClass::operator=(const TreeNodeClass& other)
{
cout << "TREENODECLASS& TREENODECLASS OPERATOR = " << endl;
if(&other != this)
{
if(parent)
delete parent;
parent = NULL;
attributes.clear();
children.clear();
CopyIntoMe(other);
}
return *this;
}
void TreeNodeClass::CopyIntoMe(const TreeNodeClass& other)
{
cout << "Copy into me" << endl;
tag = other.tag;
data = other.data;
attributes = other.attributes;
children = other.children;
parent = new TreeNodeClass;
parent = other.parent;
height = other.height;
}
void TreeNodeClass::AddParent(TreeNodeClass* p)
{
if(p)
{
parent = new TreeNodeClass;
parent = p;
}
}
std::vector< TreeNodeClass* > TreeNodeClass::ReturnChildren()
{
return children;
}
ostream& operator<<(ostream& out, const TreeNodeClass& treeNode)
{
out << "NODE: " << treeNode.tag << " " << treeNode.data << endl;
out << "CHILDREN: " << treeNode.children.size() << endl;
out << "HEIGHT: " << treeNode.height << endl;
out << "Attributes: ";
for(list<string>::const_iterator iter = treeNode.attributes.begin(); iter != treeNode.attributes.end(); iter++)
{
out << *iter << " ";
}
out << endl;
}
void TreeNodeClass::SetHeight(int h)
{
height = h;
}
/*void function(TreeNodeClass* node)
{
cout << node << " " << *node << endl;
}
TreeNodeClass* function2(TreeNodeClass* node)
{
return node;
}
int main()
{
cout << "STARTING PROGRAM" << endl;
cout << "CREATING A TREE NODE CLASS " << endl;
TreeNodeClass* newNode;
TreeNodeClass* tempNode;
list<string> attribs;
newNode = new TreeNodeClass;
tempNode = new TreeNodeClass;
newNode->SetHeight(10);
cout << *tempNode << " " << *newNode << endl;
tempNode->SetHeight(20);
cout << *tempNode << "\n " << *newNode << endl;
cout << "Setting equal " << endl;
*tempNode = *newNode;
cout << *tempNode << " " << *newNode << endl;
tempNode->SetHeight(40);
cout << *tempNode << " " << *newNode << endl;
tempNode->AddChildren(newNode);
newNode->AddParent(tempNode);
cout << *tempNode << "\n " << *newNode << endl;
return 0;
}
*/
And I'm trying to use this code on a simple state machine. I basically set up a vector of lists to return the states. This is what I believe is giving me a majority of my errors. I've been staring at this as well for a while, but I'm kind of lost.The machine will create the tree (supposedly). When the state machine finishes (state 10) it returns and the calling function will just make another call to yylex(). Thanks for the help so far!
TreeNodeClass* ProcessTree(TokenT token, vector <list <stateAssoc> >& vecTree, int depth)
{
int state = 1; //Assume this is a new record.
bool noState = false;
bool update = true;
int dex = 0;
string root, value, data, tag;
TreeNodeClass* treeNode;
treeNode = new TreeNodeClass; //Assume a new node per state machine visit.
while(state != 10)
{
switch(state)
{
case 1: dex = 1;
break;
case 2: state = 3;
noState = true;
root = yylval;
break;
case 3: state = 4;
noState = true;
break;
case 4: dex = 3;
value = yylval;
//cout << value << endl;
treeNode->CreateAttrib(root, value);
break;
case 5: dex = 2;
data = yylval;
//cout << 5 << " " << yylval << " " << token << endl;
//If its data store as data; if tag its a start tag.
break;
case 6: dex = 4;
//cout << token << " " << yylval << endl;
break;
case 7: state = 9;
noState = true;
tag = yylval;
//cout << tag << token << endl;
if(data != "" and data != "authors")
treeNode->CreateTag(data, tag);
break;
case 8: {
TreeNodeClass* childNode = new TreeNodeClass;
childNode = ProcessTree(token, vecTree, depth+1);
cout << "BEFORE PARENT" << endl;
childNode->AddParent(treeNode);
childNode->SetHeight(depth);
treeNode->AddChildren(childNode);
delete childNode;
childNode = NULL;
}
token = TokenT(yylex()); //Get a new token to process.
dex = 5;
break;
case 9: state = 10;
noState = true;
update = false;
break;
case 10: noState = true;
update = false;
break;
default: cout << "Error " << endl;
cout << state << endl;
cin.get();
break;
}
if(!noState)
state = FindMatch(vecTree[dex], token);
else
noState = false;
if(update)
token = TokenT(yylex());
else
update = true;
}
return treeNode;
}
1.A children shouldn`t delete a parent:
TreeNodeClass::~TreeNodeClass()
{
cout << "TREENODECLASS::~TREENODECLASS()" << endl;
/* Delete next 2 lines
if(parent)
delete parent;
*/
parent = NULL;
children.clear();
attributes.clear();
cout << "EXIT TREENODECLASS::~TREENODECLASS()" << endl;
}
2.Containers will not delete a pointer -- you should take it in mind always. Easy way to delete, for example:
for (vector<TreeNodeClass*>::iterator child = children.begin(); child != children.end(); ++child)
delete *child;
But best way -- not use native pointers and use some smart pointers or shared pointers.
3.Main function do not delete pointers tempNode and newNode.
4.If you'll use native pointers, you should recursively create and copy each children. In other way you'll catch memory leak.
5.Example of method CopyIntoMe:
void TreeNodeClass::CopyIntoMe(const TreeNodeClass& other)
{
cout << "Copy into me" << endl;
tag = other.tag;
data = other.data;
attributes = other.attributes;
// delete each pointer to Nodes
foreach (vector<TreeNodeClass*>::iterator child = children.begin(); child != children.end(); ++child)
delete *child;
children.clear();
// Copy recursively each child
foreach (vector<TreeNodeClass*>::iterator child = other.children.begin(); child != other.children.end(); ++child) {
TreeNodeClass* new_child = new TreeNodeClass;
new_child->CopyIntoMe(*child);
children.push_back(new_child);
}
parent = other.parent;
height = other.height;
}
This is bad:
parent = new TreeNodeClass;
parent = p;
This is a memory leak. Since you are allocating memory and pointing parent to it, then immediately pointing parent to something else, you can never delete that allocated memory. The memory will be allocated and lost every time AddParent() is called.
I'm working on a program that works with a binary tree. I'm getting an error with adding new nodes into the tree. I can add one node, but after adding another, I get a STATUS_ACCESS_VIOLATION error. I think the error could be with the function arguments dealing with the search function. Please help me if you can.
Here is he .h file that i've written:
#ifndef P4_H
#define P4_H
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cctype>
#include <string>
using namespace std;
struct TreeNode //ListNode structure with components
{
int acctNum;
TreeNode *left;
TreeNode *right;
};
typedef TreeNode* nodePtr; //defines a pointer to a treenode struct
class Tree
{
private:
nodePtr root;
int numElements;
public:
Tree()
{ root = NULL; numElements = 0; }
bool treeEmpty()
{ return (numElements == 0); }
void addNode()
{
int key;
cout << "Enter account number to add: ";
cin >> key;
cout << endl << endl;
nodePtr location = NULL, parent = NULL, p = NULL;
bool found = searchTree(key, &location, &parent);
cout << found << " " << location << " " << parent << endl << endl;
if (found)
{
cout << "Error! Account number: " << key << " already exists within"
<< " the tree." << endl << endl;
}
else
{
if (parent == NULL)
{
root = new TreeNode;
root->acctNum = key;
}
else
{
if (parent->acctNum > key)
{
parent->left = new TreeNode;
p = parent->left;
p->acctNum = key;
}
else
{
parent->right = new TreeNode;
p = parent->right;
p->acctNum = key;
}
}
}
}
bool searchTree(int key, nodePtr *location, nodePtr *parent)
{
bool found = false;
nodePtr p = root;
*location = root;
parent = NULL;
while (p != NULL && !found)
{
*location = p;
if (key == p->acctNum)
found = true;
else if (key < p->acctNum)
{
*parent = p;
p = p->left;
}
else if (key > p->acctNum)
{
*parent = p;
p = p->right;
}
}
return found;
}
void deleteNode()
{
int key;
nodePtr location = NULL, parent = NULL;
cout << "Enter account number to delete: ";
cin >> key;
cout << endl << endl;
bool found = searchTree(key, &location, &parent);
if (!found)
{
cout << "Error! Account number: " << key << " was not found."
<< endl << endl;
}
else if (location->left != NULL && location->right != NULL)
{ //delete node with left and right subtrees
nodePtr leftmost = location->right, leftmostParent = NULL;
while (leftmost->left != NULL)
{
leftmostParent = leftmost;
leftmost = leftmost->left;
}
leftmost->left = location->left;
leftmost->right = location->right;
leftmostParent->left = NULL;
if (parent->acctNum > location->acctNum)
parent->left = leftmost;
else
parent->right = leftmost;
delete location;
location = NULL;
}
else if (location->left != NULL && location->right == NULL)
{ //delete node with only a left subtree
if (parent->acctNum > location->acctNum)
parent->left = location->left;
else
parent->right = location->left;
delete location;
location = NULL;
}
else if (location->left == NULL && location->right != NULL)
{ //delete node with only a right subtree
nodePtr leftmost = location->right, leftmostParent = NULL;
while (leftmost->left != NULL)
{
leftmostParent = leftmost;
leftmost = leftmost->left;
}
leftmost->right = location->right;
leftmostParent->left = NULL;
if (parent->acctNum > location->acctNum)
parent->left = leftmost;
else
parent->right = leftmost;
delete location;
location = NULL;
}
else
{ //delete a leaf node
if (location->acctNum > parent->acctNum)
parent->right = NULL;
else
parent->left = NULL;
delete location;
location = NULL;
}
}
void displayAscend(nodePtr p, int count)
{
if (p->left != NULL)
displayAscend(p->left, count);
cout << count << ". " << p->acctNum << endl;
count ++;
if (p->right != NULL)
displayAscend(p->right, count);
}
void displayDescend(nodePtr p, int count)
{
if (p->right != NULL)
displayAscend(p->right, count);
cout << count << ". " << p->acctNum << endl;
count ++;
if (p->left != NULL)
displayAscend(p->left, count);
}
void readFile()
{
char filename[50];
cout << "Enter name of file to open: ";
cin.getline(filename,51);
cout << endl << endl;
ifstream inFile;
inFile.open(filename);
while (!inFile)
{
cout << "Error opening file! Please try again." << endl << endl;
cout << "Enter name of file: ";
cin.getline(filename,51);
cout << endl << endl;
}
int num;
while (!inFile.eof())
{
inFile >> num;
nodePtr location = NULL, parent = NULL, p = NULL;
bool found = searchTree(num, &location, &parent);
if (found)
{
cout << "Error! Account number: " << num << " already exists"
<< " within the tree." << endl << endl;
}
else
{
if (parent == NULL)
{
root = new TreeNode;
root->acctNum = num;
}
else
{
if (parent->acctNum > num)
{
parent->left = new TreeNode;
p = parent->left;
p->acctNum = num;
}
else
{
parent->right = new TreeNode;
p = parent->right;
p->acctNum = num;
}
}
}
}
}
};
#endif
In searchTree, you set parent to NULL before the loop, then dereference it in the loop.