Printing unbalanced binary tree - c++

I'm intentionally creating a wrong and unbalanced binary tree in this code:
void createlist (tree*& node) {
node = new tree;
node->num = 1;
node->left = new tree;
node->left ->num = 2;
node->right = new tree;
node->right->num = 3;
node->left->left = new tree;
node->left->left->num = 4;
node->left->right = new tree;
node->left->right->num = 5;
node->right->left = new tree;
node->right->left->num = 6;
node->left->left->left = new tree;
node->left->left->left->num = 7;
}
Then, when I am trying to print it using an ordinary function for that:
void print (tree* node) {
if (node!= 0) {
print (node->left);
cout << node->num << " ";
print (node->right);
}
}
It throws out an error:
Access violation reading location 0xcdcdcdd5.
at this location:
print (node->left);
I'm just starting with trees and don't quite follow the reason for this error. Could you help with that?

This is an excellent chance for you to learn how to debug your programs. I suggest you run the program in a debugger and see what the values of node and node->left is when the segfault happens.
An access violation is when you are accessing memory that your program is not allowed to access.
Your problem is not trees your problem is using pointers correctly and not initializing your variables properly.
I suspect your problem is that the constructor for tree is not properly doing:
left = NULL;
right = NULL;
Remember in C/C++ that the compiler does not set any specific values into variables when they are created, it is up to you to initialize variables.
It is custom to use NULL (or nullptr in C++11) to rather than 0 to test/set pointers.
Link to C++ pointers tutorial

Hard to tell without the source of your tree class, but perhaps making a new tree doesn't initialize the left and right members to null pointers? In that case, some of your trees will contain uninitialized pointer data.

Related

Linked list issue with overwriting variables

I am trying to code a linked list in C++, but I am running into a problem. When I insert only one item, it works, but when I insert more than one, it goes into an infinite loop. Here is the code:
#include "linkedList.hpp"
#include <iostream>
linkedList::node::node(int value)
{
internalValue = value;
next = nullptr;
previous = nullptr;
};
linkedList::linkedList()
: header{node(-2)}, trailer{node(-2)}
{
trailer.previous = &header;
header.next = &trailer;
size = 0;
}
int linkedList::getLength()
{
return size;
}
void linkedList::appendElement(int value)
{
node newNode = node(value);
newNode.next = &trailer;
newNode.previous = trailer.previous;
(trailer.previous)->next = &newNode;
trailer.previous = &newNode;
size = size + 1;
}
void linkedList::print()
{
node * current = header.next;
while (current -> next != nullptr)
{
std::cout << current -> internalValue << "->" << "\n";
current = current->next;
}
std::cout << "v";
}
After trying to debug it, I found that the issue is with the construction of a node. So the first time I try to insert 5, the program creates a node called new node, which is then appended perfectly fine.
What happens next is when a second number is to be appended, lets say 6, the program doesn't really create a new node object. Rather the variable name "newNode" still refers to the node with the value 5 stored in it and it replaces it with a node with the value of 6.
This understandably then creates an infinite loop since it essentially makes the array circular. I don't know how to fix this. Can someone point me in the right direction?
PS: sorry if this is extremely simple, I am very new to C++ (this is only my second day of coding)
In linkedList::appendElement(int value) you create a new node on the stack ( or 'automatic storage' ), which means the node will be destroyed when the function returns.
Instead, create the node on the heap ( or 'dynamic storage' ) using the new operator so it is not destroyed when the function returns.
node* newNode = new node(value);
You will also have to remember to destroy nodes yourself when the list is destroyed or truncated, and most C++ developers soon find it better to use smart pointers for that.

Pointers to structures in C++

In order to complete my homework I had to implement a list in C++, thus I defined a structure:
struct Node {
int value;
Node * next;
Node * operator [] (int index)//to get the indexed node like in an array
{
Node *current = this;
for (int i = 0; i<index; i++)
{
if (current==NULL) return NULL;
current = current->next;
}
return current;
}
};
When I used it with actual structures, it worked fine:
Node v1, v2, v3;
v1.next = &v2;
v2.next = &v3;
v3.value = 4;
v3.next = NULL;
cout<<v1[2]->value<<endl;//4
cout<<v2[1]->value<<endl;//4
cout<<v3[0]->value<<endl;//4; works just as planned
cout<<v3[1]->value<<endl;//Segmentation fault
But when i tried to use it with pointers, the things got messed up:
Node *v4, *v5, *v6;
v4 = new Node;
v5 = new Node;
v6 = new Node;
v4->next = v5;
v4->value = 44;
v5->next = v6;
v5->value = 45;
v6->next = NULL;
v6->value = 4646;
//cout cout<<v4[0]->value<<endl; compiler says it's not a pointer
cout<<v4[0].value<<endl;//44
cout<<v4[1].value<<endl;//1851014134
cout<<v4[2].value<<endl;//45
cout<<v4[3].value<<endl;//1851014134
cout<<v4[4].value<<endl;//4646
cout<<v4[5].value<<endl;//1985297391;no segmentation fault
cout<<v6[1].value<<endl;//1985297391;no segmentation fault even though the next was NULL
delete v4;
delete v5;
delete v6;
Though it is possible to work with function, I've got some questions:
Why the returned value in pointers example was a structure but not a pointer?
Why elements now have doubled index and what are the elements between them?
Why there was no segmentation fault?
I'd be very thankful if someone explained me these moments or gave me the sources I could learn from
That's because v4[0] (and the rest) aren't actually calling your Node::operator[]. That's because v4 isn't a Node, it's a Node*, and pointers have a builtin meaning behind operator[]: v4[i] == *(v4 + i) (that is, we're just indexing into that "array"). So when you write something like v4[3], that isn't calling operator[](3)... it's instead giving you back a Node three Nodes after v4 in memory somewhere, which is basically just garbage.
To get what you want to happen, you'd have to dereference the pointers first:
(*v4)[0]
(*v6)[1]
// etc
By doing this
v4 = new Node;
cout<<v4[0].value<<endl;//44
cout<<v4[1].value<<endl;//1851014134
cout<<v4[2].value<<endl;//45
cout<<v4[3].value<<endl;//1851014134
cout<<v4[4].value<<endl;//4646
cout<<v4[5].value<<endl;//1985297391;no segmentation fault
You are not calling operator[] of struct Node, you are making pointer dereferencing, v4[1] is equal to ++v4; *v4; So this code is causing unpredicted behavior, because you are dereferencing some garbage.
To make it work as you want, you need to change it to:
cout<<v4->operator[](0).value<<endl;
cout<<v4->operator[](1).value<<endl;
cout<<v4->operator[](2).value<<endl;
...

Deleting elements from doubly bounded pointer list

I am working on a project where I create a double bounded pointer list, delete several elements, and still be able to read off the list. I have a double bounded pointer list, but am having trouble deleting elements and keeping the list double bounded. This then causes issues when trying to print the list.
Below is the IF statement I've placed in a while loop to help delete unwanted elements. I keep getting a segmentation fault (core dumped).
if ((black2 != black)||(white2 != white)) {
dump = help;
help = help ->next;
dump -> before = temp;
temp -> next = help;
help ->before = temp;
delete dump;
}//if
else { temp = help;
help = help->next;
help ->before = temp; }//else
To maintain properly the doubly linked list you should do something like :
void remove(X *elt) {
X* before = elt->before;
X* after = elt->next;
if (before != NULL) { // assuming first element points to NULL
before->next = after;
}
else {
first = after; // assuming first is a pointer to first element of list
}
if (after != NULL) { // assuming last element points to NULL
after->before = before;
}
else {
last = before; // assuming last is a pointer to last element
}
delete elt;
}
That way, you ensure that elements around current correctly point to each other dealing with special cases of removing first or last element.
But you already have a std::list template in Standard Template Library
One logical issue in your code is the line dump->before = temp.
What this does is that it sets the previous node pointer of dump to temp, as opposed to defining temp as the previous node.
The correct line should read temp = dump->before
PS: Your code is correct assuming that the node you are deleting isn't the first or last node (and you haven't padded with dummy nodes). You should introduce checks for these cases if required.

C++ Structure returning true, but why?

Doing some coursework and I need to make a binary search tree. Piece of cake, should be fun.
Since C++ doesn't feature a dictionary I've decided to make one using a BST.
I found some sample code online to give me a brief idea as to how they're put together and it's all relatively simple but being new to C++ and having come from a C# environment, one thing has thrown me into confusion and that is 'c'. I don't understand why 'c' is returning true in the while loop or why changing the data in left or right would affect this outcome.
node* t = new node;
node* parent;
t->data;
t->left = NULL;
t->right = NULL;
parent = NULL;
...
node* c;
c = root;
while (c)
{
parent = c;
if(t->data > c->data)
{
c = c->right;
}
else //else it's assigned left
{
c = c->left;
}
}
In C and C++, a pointer is considered false if it's null, and true otherwise. This while loop keeps walking down the tree until c becomes a null pointer.
Also, C++ does have dictionaries. Check out std::map and std::unordered_map.

Pointers and Objects in C++, x86 Compilation Error

I'm creating a binary tree by linking individual nodes all the way up to the root node, which I return from the method.
MaxWinnerTree::MaxWinnerTree(int elements)
{
WinnerTree(elements);
}
`Node MaxWinnerTree::WinnerTree(int elements)
{
int size = 1;
while (size<elements)
size = size * 2; //gets closest power of 2 to create full bottom row
Node* a[size]; //array of pointers to nodes
for (int i = (2*elements-1); i>0; i--)
{
//Create nodes and link them to parent, right, and left values
if (i > elements-1) //leaf
{
//Create new nodes with data -1, store pointer to it in array
*a[i] = newNode(i,-1,NULL,NULL,NULL);
}
else // not leaf
{
//Create node with data = max of children, store pointer
*a[i] = newNode(i,-1,a[i*2],a[i*2 +1], NULL); //create
a[i]->data = max(a[i*2]->data, a[i*2+1]->data); //gets max
a[i]->right->parent = a[i];
a[i]->left->parent = a[i];
if(i=1)
root = a[i];
}
}
return *root; }
However, trying to create an object in my main method isn't working like it should.
MaxWinnerTree* tree = new MaxWinnerTree(elements);
Gives a standard x86 architecture error, where as
MaxWinnerTree tree = new MaxWinnerTree(elements);
Gives
main.cpp:22: error: invalid conversion from ‘MaxWinnerTree*’ to ‘int’
main.cpp:22: error: initializing argument 1 of ‘MaxWinnerTree::MaxWinnerTree(int)’
Why does the compiler think that my method is returning an int? What is to correct way to create an object in this fashion? In reality, I just need a pointer to the root node, where all my other methods will begin.
Thanks for any help in advance.
Changes I would make:
Change newNode (which you haven't shown us) to return a Node *. If newNode isn't actually allocating a new Node, then you need to rethink its design. Or, move the arguments to newNode into a constructor for Node, and change your code to read new Node( ... args ... ).
Instead of saying *a[i] = newNode( ... ) say a[i] = newNode( ... ) (or whatever you replace newNode with as per my first bullet). What you have written asks the C++ compiler to invoke a copy constructor to copy whatever newNode returned into the object pointed to by *a[i], but from the snippet you shared with us, *a[i] doesn't point to anything yet.
You've built a heap, but with explicit pointers. If you really wanted a heap, you don't need the explicit pointers...
This next line can just ruin your whole day. i=1 assigns 1 to i and then returns 1 as its value, which doesn't really do the right thing. In your case, it'll make your loop stop iterating as soon as it gets to the part of the heap-building where the elements have children.
if(i=1)
root = a[i];