Binary Tree "behavior" - c++

I have the following binary search tree (in C++) and i have a question to a specific line of code :
delete k;
My code is working if i remove that line , and I don't understand why.
By my understanding : the data from k is being inserted into the tree and THEN then the variable k is deleted.
Why is the data deleting from the Tree too?
here is my code:
#include <iostream>
using namespace std;
struct nod
{
nod *st=NULL;
int info;
nod *dr=NULL;
int h;
nod *par=NULL; // par = "father"
};
struct avl
{
nod *rad=NULL; //rad = root;
void insert(nod *z) //INSERT
{
nod *y = NULL;
nod *x = rad;
while (x != NULL)
{
y = x;
if (z->info < x->info)
{
x = x->st; // st = left
}
else
{
x = x->dr; //dr = right
}
}
if (y == NULL)
{
rad = z;
}
else
{
if (z->info < y->info)
{
y->st = z;
}
else
{
y->dr = z;
}
}
z->par = y;
}
void inordine(nod *k)
{
if (k)
{
inordine(k->st);
cout << k->info<<"\t";
inordine(k->dr);
}
}
};
int main(void)
{
avl *arbore = new avl;
int el = 5;
arbore->rad=NULL;
while (el >= 0)
{
cout << "element\n";
cin >> el;
nod *k = new nod;
k->dr = NULL;
k->st = NULL;
k->par = NULL;
k->info = el;
arbore->insert(k);
delete k;
}
cout << "print inordine\n";
arbore->inordine(arbore->rad);
}

the data from k is being inserted into the tree and THEN then the variable k is deleted
No, k is just a pointer. It points to a nod(e). You are inserting this node into your tree (by passing it as a pointer). It is not a copy, it is that same node. delete does not delete a variable, it deletes the node, so you are also removing it from your tree.
A big argument against raw pointers like you are using, is that it is difficult to express who is the owner of the object. This is evidence supporting that argument. You were expecting that the tree owned its nodes, your program shows the opposite behavior.
To properly dispose of the nodes you would need a destructor that traverses the tree and deletes each node upon the destruction of the tree. You would also need to hide the actual nodes from your trees users by using inserts like avl::insert(int info, int h);

Related

Breakpoint on Delete class pointer

I'm working on a class project and this piece of code won't let me delete an instance of a class without throwing a breakpoint error.
The class is Node, I'm trying to build a singly linked list for data structures and algorithms. I'll include the whole program, it isn't long, but the code in question that's causing the problem is in deleteMin(), the delete u.
#include <iostream>
using namespace std;
// we create a Node class.
class Node { // inside this class we hold two pieces of information.
int x; // the integer x, which is our data.
Node* next; // and the address of the next node.
public:
Node(int x0) : x(x0), next(NULL) { } // Here I've set up a constructor that sets x equal to the argument
// and defaults the next address to NULL.
bool add(int newValue); // Here follows our three required functions.
int deleteMin();
int size();
void printSSL(); // I also added a printSSL() function so that we can test and see what's going on.
};
//Originally I wanted to put these inside of the Node class, but then you'd end up with a unique head and tail for every Node.
//So instead I've left them outside. If you wanted to create multiple SSList's then you'd want to create an object out of these as well.
Node* head; // The first value in the our SLList.
Node* tail; // The last value in our SLList.
int n; // The number of elements in the list.
// I should mention here that head and tail are set equal to the first value in the SLList in the Main() function below.
// Here follows the actual implementation.
// I chose to try and simplify things by focusing on the add() function.
// If the add function organizes the information, and puts it into the SLList in order,
//then deleteMin() only has to pull the first value.
bool Node::add(int newValue) { // add() is a member function of Node and it takes in the newValue were adding to the list.
Node* u = new Node(newValue); // First thing we do is create a new Node using the argument value x. We pass this into a pointer, u.
if (newValue <= head->x) { // Next, we check to see if the new value is less than the head.
u->next = head; // if it is, then our job is done and we just make this new, smaller value, the new head.
head = u; // we do this by making the initial head equal to the next address in the new Node u.
n++; // Once we have the address saved, we make u into the new head and increment n.
return true; // There's no iteration in this case, so this if statement would be O(1).
}//O(1)
else { // If the new value is greater than the head, then we have to store it further back in the SLList.
Node* y = head; // This was the hardest part of the whole thing... I solved it by creating two Node pointers,
Node* z = head; // Both Node pointers are set equal to head, but this is mostly just to ensure that they aren't empty.
while ((newValue > y->x) && (y != tail)) { // Then I set a while loop that looks at whether the new value is less than the value in the head.
z = y; // The while loop continues, moving through the list of values, setting y equal to the next value,
y = y->next; // and using z to keep track of the former value.
} // The loop exits when we either a) hit the end of the SLList, y == tail, or when the new value is
if (y == tail) { // smaller than the next value, newValue < y->x. When the loop exits we have to deal with these two
y->next = u; // scenarios separately. If we reached the end of our list, then adding the new value is as simple as
tail = u; // setting y->next equal to u, then we make u into the new tail.
} // if we didn't reach the end of the list, then we have to set u inbetween z and y. This was really
else { // the only reason I needed z. I needed to be able to update the address of the previous Node, and
z->next = u; // I also needed to have the address of the next Node, this way I could slip u inbetween the two.
u->next = y; // Worst case scenario, this function runs through the entire SLList and then adds the value at the end.
} // I could have shaved off some time by asking if(newValue > tail->x) then run the z->next=u; and u->next=y; after
n++; // after that, but that throws an error becauset ail is a NULL pointer, which is bull#*#!
return true; // because I'm not dealing the tail->next, all I care about is tail->x which isn't NULL.
}//O(n) // But because this is an SSList and not a DLList I have no way of going to the n-2 element.
}//O(max(1, n)) // When that's done, we just increment n and leave the function.
// Considering that the worst case scenario, when x > tail->x, takes us through the whole SLList.
// I'm going to say that this add function is O(n).
int Node::deleteMin() { // The deleteMin() function starts by checking whether or not the
int x = head->x;
Node* u = head;
head = head->next;
delete u; // I have to figure out what the hells going on right here, why can't I delete this?
return x;
}
int Node::size() {
cout << n + 1 << endl;
return n + 1;
}
void Node::printSSL() {
Node* u = head;
cout << "Head:";
for (int i = 0; i <= n; i++) {
cout << i << ":(" << u->x << ", " << u->next << ") ";
u = u->next;
}
cout << " Tail" << endl;
}
int main()
{
Node one(1);
head = &one;
tail = &one;
one.printSSL();
one.deleteMin();
}
You declared an object of the type Node
Node one(1);
You may not apply the operator delete to a pointer to the object because the object was not allocated dynamically. It has automatic storage duration.
Pay attention to that it is a bad idea when functions depend on global variables. For example you will be unable to define two lists in your program.
What you need is to define a class named something like List the following way
class List
{
private:
Node *head = nullptr, *tail = nullptr;
public:
// special member functions and some other member functions;
void clear();
~List() { clear(); }
};
and to allocate nodes dynamically that will be inserted in the list.
The destructor and the function clear will delete all the allocated nodes in the list.
class Node also should be defined as a nested class of the class List.
For example the function clear can be defined the following way
#include <functional>
//...
void List::clear()
{
while ( head )
{
delete std::exchange( head, head->next );
}
tail = nullptr;
}
#include <iostream>
using namespace std;
class SLList { // SLList is the object that holds the entire list.
public: // The Node class lives inside the SLList class.
struct Node {
int data;
Node* next;
Node(int x0) : data(x0), next(NULL) {}
Node() : data(NULL), next(NULL) {}
};
Node* head;
Node* tail;
int n;
SLList() : n(0) {
Node* initial = new Node();
head = initial;
tail = initial;
cout << "You've created a new SSList" << endl;
}
bool add(int newValue);
int deleteMin();
int size();
void printSSL();
};
bool SLList::add(int newValue) { //
if (n == 0) {
head->data = newValue;
n++;
return true;
}
else {
Node* u = new Node(newValue);
if (newValue <= head->data) { //
u->next = head; //
head = u; //
n++; //
return true; //
}//O(1)
else { //
Node* y = head; //
Node* z = head; //
while ((newValue > y->data) && (y != tail)) { //
z = y; //
y = y->next; //
} //
if (y == tail && newValue > y->data) {
y->next = u; //
tail = u; //
} //
else { //
z->next = u; //
u->next = y; //
} //
n++; //
return true;
}
}//O(n) //
}//O(max(1, n)) //
int SLList::deleteMin() {
int x = head->data;
Node* u = head;
head = head->next;
delete u;
n--;
return x;
}//O(1)
int SLList::size() {
cout << n + 1 << endl;
return n + 1;
}//O(1)
void SLList::printSSL() {
Node* u = head;
cout << n << " Nodes|" << "Head:";
for (int i = 0; i < n; i++) {
cout << i << ":(" << u->data << ", " << u->next << ") ";
u = u->next;
}
cout << " Tail" << endl;
}//O(n)
int main() {
SLList* one = new SLList;
one->printSSL();
one->add(30);
one->printSSL();
one->add(20);
one->printSSL();
for (int i = 0; i < 7; i++) {
int x = rand() % 50;
one->add(x);
one->printSSL();
}
for (int i = 0; i < 9; i++) {
one->deleteMin();
one->printSSL();
}
}

Runtime error when using struct as value in std::map?

I am using a map with int value -> trie, trie is the struct. So why am I getting runtime error when I print all keys value in my map? But if I don't print anything then there is no error(the insert() part don't cause any error).
struct trie{
node *root;
trie(){
root = new node();
}
void insert(int x){
node *cur = root;
for(int i = 31; i >= 0; i--){
int b = (x >> i) & 1;
if (cur->child[b] == NULL) cur->child[b] = new node();
cur = cur->child[b];
}
cur->isleaf = true;
}
int maxxor(int x){
node *cur = root;
int res = 0;
for(int i = 31; i >= 0; i--){
int b = (x >> i) & 1;
if (cur->child[b ^ 1] != NULL){
res |= (1ll << i);
cur = cur->child[b ^ 1];
}
else cur = cur->child[b];
}
return res;
}
int minxor(int x){
node *cur = root;
int res = 0;
for(int i = 31; i >= 0; i--){
int b = (x >> i) & 1;
if (cur->child[b] != NULL) cur = cur->child[b];
else{
res |= (1ll << i);
cur = cur->child[b ^ 1];
}
}
return res;
}
~trie(){
delete root;
}
};
map<int, trie> tr;
int32_t main(){
ios::sync_with_stdio(false);
tr[3].insert(1);// no error
for(auto x: tr) cout << x.first << ' '; //RUNTIME ERROR?
}
I have tried to debug and read various questions/answers but I still not be able to debug this code. Any help are appreciated.
You have implemented a "complex" tree if i may say, using linked list. And in order to avoid trouble, you need to make sure that your destructors do their work propoerly and are coherent i.e destroy all allocated memory and don't "try" to "destroy" unallocated space or already destroyed space.
That said, your trie destructor destroys root data member, which calls node destructor. And node destructor destroys both two child which were not necessarily allocated. This is the origin of your Segmentation Error.
To correct this you should only destroy allocated child.
Here is a simplified version of your code
#include <bits/stdc++.h>
#define int int64_t
using namespace std;
struct node{
node* child[2];
bool isleaf;
node(){
child[0] = child[1] = NULL;
isleaf = false;
}
~node(){
}
};
struct trie{
node *root;
trie(){
cout << " in trie ctor" << endl;
root = new node();
}
void insert(int x){
cout << "in insert trie methode " << endl;
node *cur = root;
cur->child[0] = new node();
cur->child[1] = new node();
}
~trie(){
delete root->child[0]; // i'm sure it has been allocated
delete root->child[1]; // i'm sure it has been allocated
// delete root, would be like doing int *p; delete p;
}
};
map<int, trie> tr;
int32_t main(){
ios::sync_with_stdio(false);
tr[3].insert(1);
for(auto x: tr)
cout << x.first << endl << endl;
}

Strange bug in my splay tree implementation

I am attempting to write a C++ template struct for a splay tree, but when I try to test the code, I am getting very strange results.
This is my code for the template:
template <class T>
struct splaytree {
struct node {
splaytree<T> *tree;
node *p, *c[2];
T v;
int w;
node(T t, splaytree<T> *st) {
v = t;
p = 0;
c[0] = 0;
c[1] = 0;
w = 1;
tree = st;
}
int side() {
return (p->c[1] == this) ? 1:0;
}
void r() {
node *x = this;
int b = x->side();
node *p = x->p;
x->w = p->w;
p->w = x->c[1^b]->w + 1 + p->c[1^b]->w;
x->p = p->p;
p->p = x;
p->c[0^b] = x->c[1^b];
x->c[1^b] = p;
}
void splay() {
node *x = this;
while (x->p) {
node *p = x->p;
if (p == tree->root) x->r();
else if (((x->side())^(p->side()))) {
x->r();
x->r();
}
else {
p->r();
x->r();
}
}
tree->root = this;
}
int index() {
this->splay();
return this->c[0]->w;
}
};
node *root;
splaytree() {
root = 0;
}
void add(T k) {
node x0(k,this);
node *x = &x0;
if (root == 0) {
root = x;
return;
}
node *i = root;
while (i != x) {
int b = (k < i->v) ? 0:1;
if (i->c[b] == 0) {
i->c[b] = x;
i->w++;
x->p = i;
}
i = i->c[b];
}
x->splay();
}
};
I am using this to test it:
int main() {
splaytree<int> st;
st.add(2);
cout << st.root->v << endl;
cout << st.root->v << endl;
st.add(3);
cout << st.root->c[0] << endl;
}
I inserted the element 2 and then printed the value of the root node twice. Somehow the two prints gave me two different values (2 and 10 in Ideone at http://ideone.com/RxZMyA). When I ran the program on my computer, it gave me 2 and 1875691072 instead. In both cases, when inserting a 3 after the 2, the root node's left child was a null pointer when it should be a node object containing 2.
Can someone please tell me why I am getting two different values when printing the same thing twice, and what I can do to make my splaytree.add() function work as intended? Thanks!
After
node x0(k,this);
node *x = &x0;
if (root == 0) {
root = x;
return;
}
root is an address of a local variable. By the time you print root->v, x0 is gone out of scope. All bets as to what the root really points to are off.

I Am Having Issues with Passing Struct Pointers

I am issues with a homework assignment. We are working on binary trees and whenever I try to pass my head node to my insert() function the node is not being changed. This has lead me to believe that I am somehow not passing by reference, I just can't figure out where the mistake is, however. Thank you for any help in advance.
/*Linked List
**Code inspired by Linked List by Daniel Ross
**Code written by Collin Bardini
**Assignment 6
*/
#include <iostream>
using namespace std;
//Our node
struct node {
int data;
node* left; //lower
node* right; //greater
};
//function declarations
void insert(node * head, int);
void print_preorder(node * root);
void print_postorder(node * root);
void print_inorder(node * root);
int search(int data, node * root);
//main for testing the access functions
void main(void)
{
node* headA = 0;
node* headB = 0;
const size_t as = 7;
const size_t bs = 100;
int a[as] = {1,5,4,6,7,2,3};
int b[bs] = {118,119,158,166,163,123,108,116,117,184,165,137,141,111,138,122,109,194,143,183,178,173,139,
126,170,190,140,188,120,195,113,104,193,181,185,198,103,182,136,115,191,144,145,155,153,151,
112,129,199,135,146,157,176,159,196,121,105,131,154,107,110,175,187,134,132,179,133,102,172,
106,177,171,156,168,161,149,124,189,167,174,147,148,197,160,130,164,152,142,162,150,186,169,
127,114,192,180,101,125,128,100 };
for (int i = 0; i < as; i++)
insert(headA, a[i]);
for (int i = 0; i < bs; i++)
insert(headB, b[i]);
print_preorder(headA);
cout << "search 196: " << search(196, headB) << endl <<
"search 137: " << search(137, headB) << endl <<
"search 102: " << search(102, headB) << endl <<
"search 190: " << search(190, headB) << endl;
}
// creates a new node and inserts it in the correct location in the tree
void insert(node * head, int d)
{
//make a new node
node *p = new node;
p->right = 0;
p->left = 0;
p->data = d;
if (head == 0) //list is empty
head = p;
else //append to tail end
{
node* c1 = head;
node* c2 = head;
while (c1)
{
if (d > c1->data)
{
c2 = c1;
c1 = c1->right;
}
else
{
c2 = c1;
c1 = c1->left;
}
}
if (d > c2->data)
c2->right = p;
else
c2->left = p;
}
}
Short answer: see my answer to this identical question and use double pointers in the insert() function.
Regarding the "pass-by-reference" part of the question, well it depends on what exactly you mean by these words. You are passing the node by reference, true, but you're passing the pointer to the node by value. Remember that pointer is just another variable holding a non-negative integer value (overly simplified, but still true).
Long answer: the modifying functions should use either double pointers or references to pointers. The reason is that, in a function definition like void insert(node * head, int d) { /*...*/ }, the pointer itself is passed by value. That is, a temporary copy of the original pointer is created, and modified inside the function. The actual pointer remains unchanged. I.e., in these lines:
// definition
if (head == 0) //list is empty
head = p;
// client code
for (int i = 0; i < as; i++)
insert(headA, a[i]);
The temporary local variable head is modified, not the headA variable that you pass to the function. See the linked question where I posted a schematics of what happens with the pointer values in this situation.
You can change to e.g. double pointers like so:
void insert(node ** head, int d) {
// snip...
if (*head == 0) //list is empty
*head = p;
Or pass the pointer by reference.
Note: for read-only functions, such as print...(), you don't need to use a double pointer or any other pass-by-reference mechanism.

Recursively Populate N-ary Tree in c++

I'm attempting to create the game tree of the tic-tac-toe board game. I've written some basic methods, but I'm having trouble recursively populating the elements of the tree.
I'm using a Node struct to define the Nodes of the tree. Each node has an array of children.
struct node {
string data;
int height;
node * child[9];
};
Each Node stores the content of a game board as a string. * is used to display blanks.
So, * * * * * * * * * would be a blank board.
I have a Tree class that implements the tree.
class Tree {
public:
Tree();
Tree(string data);
~Tree();
void insert(string data, node * leaf);
node * get_root();
void populate(node * n);
void generate_tree(node * n);
int number_of_blanks(string);
private:
void destroy_tree(node * leaf);
node * root;
node * temp;
int count;
};
Tree::Tree(string data) {
root = new node;
root->data = data;
root->height = 0;
temp = root;
count = 0;
}
Here is my method for inserting nodes. It inserts a new node to the first NULL child.
void Tree::insert(string data, node * leaf) {
int i;
//checks for first NULL child
for(i = 0; i < 9; i++) {
if(leaf->child[i] == NULL) {
//first NULL child is inserted and all its children set to NULL
leaf->child[i] = new node;
leaf->child[i]->data = data;
leaf->child[i]->height = leaf->height + 1;
break;
}
}
}
This code works how I've intended it to, however I'm sure it's not the best method.
Where I'm having the most trouble is recursively populating the tree. My recursion either ends early, or is an endless loop. I'm not sure how to approach this problem, as I've never used recursion with a void method.
void Tree::generate_tree(node * leaf) {
int i;
string data;
string player;
int length = number_of_blanks(leaf->data);
if(leaf->height % 2 == 0)
player = "X";
else
player = "O";
if(leaf->data.find_last_of('*',8) == string::npos) {
cout << "This is a leaf!!!!!!!!! " << leaf->data << endl;
return;
}
for(i = 0; i < length; i++) {
if(leaf->height >=9 )
return;
data = leaf->data.replace(count,1,player);
insert(data,leaf);
cout << "New Node: " << data << " Height: " << leaf->child[i]->height << endl;
count++;
generate_tree(leaf->child[i]);
count = 0;
}
}
Any tips, or specific suggestions would be greatly appreciated. Thank you.
I'd recommend giving node a constructor and to initialize members before the code block that makes up the constructor. For example:
node(string s, int h) : data(s), height(h) {
for (int i=0;i < 9; ++i)
child[i] = NULL;
}
Similarly for the constructor for Tree:
Tree::Tree(std::string data) : root(new node(data,0)), count(0) {}
This makes other parts of the code much simpler. For example, your insert code would now look like this:
void Tree::insert(std::string data, node * leaf) {
//checks for first NULL child
for(int i = 0; i < 9; i++) {
if(leaf->child[i] == NULL) {
//first NULL child is inserted and all its children set to NULL
leaf->child[i] = new node(data, leaf->height+1);
break;
}
}
}
I haven't had the time to analyze the rest, but this may make it easier for you to solve.