findNode in binary search tree - c++

Does this look right? I mean I am trying to implement the delete function.
Node* BST::findNode(int tofind) {
Node* node = new Node;
node = root;
while (node != NULL) {
if (node->val == tofind) {
return node;
} else if (tofind < node->val) {
node = node->left;
} else {
node = node->right;
}
}
}
Here is the delete, it's not even close to done but,
void BST::Delete(int todelete) {
// bool found = false;
Node* toDelete = new Node();
toDelete=findNode(todelete);
if(toDelete->val!=NULL) {
cout << toDelete->val << endl;
}
}
This causes a segmentation fault just running that, any ideas?

The main problem with findNode() is that you never return the node that you've found. That's why you're getting the segfault.
Also, in deleteNode() you should check whether findNode() has returned NULL. And of course you also need to code up the rest of the deletion logic.
Finally, the two new Node allocations are unnecessary and are leaking memory.

oh wait it's because in delete I should have done:
if(toDelete!=NULL) {
cout << toDelete->val << endl;
}
before it was
if(toDelete->val!=NULL)

Related

Delete Even Numbers From A Linked List C++

I can't seem to understand what am I missing, I've spent hours and hours looking at this and everything I tried doesn't work.
My thought process to check if the second node of the list is even, if it is then to link the first and third node and delete the second but it doesn't work... I've been stuck at this for a week.
void delete_even()
{
nod *aux;
if (head == NULL)
{
cout << "List doesn't exist!";
}
else
{
nod *curent;
current = head;
while (curent)
{
if (curent->next->info % 2 == 0)
{
curent = curent->next->next;
curent->next = aux;
delete aux;
break;
}
else
{
curent = curent->next;
}
}
}
}
I don't know what else to do.
There are several things wrong with this code.
Your use of curent->next invokes undefined behavior when curent is pointing at the last node in the list, since next will be NULL in that case. It is are causing you to skip the 1st node in the list.
You never assign aux to point at anything, so calling delete on aux is also undefined behavior.
Even if aux were pointing at a valid node, you are assigning aux to curent->next right before deleting the node that aux is pointing at, thus leaving curent->next pointing at invalid memory, which is also undefined behavior.
If you did manage to remove a node from the list, you are breaking the loop immediately afterwards, so you would be removing only one even number from the list, not removing all even numbers, as your title suggests you want to do.
Try something more like this instead:
void delete_even()
{
if (!head)
cout << "List is empty!";
else
{
nod *curent = head, *prev = NULL;
while (curent)
{
nod *next = curent->next;
if (curent->info % 2 == 0)
{
if (prev)
prev->next = next;
else
head = next;
delete curent;
}
else
{
prev = curent;
}
curent = next;
}
}
}
Alternatively:
void delete_even()
{
if (!head)
cout << "List is empty!";
else
{
nod *curent = head;
nod **prev = &head;
while (curent)
{
if (curent->info % 2 == 0)
{
*prev = curent->next;
delete curent;
}
else
{
prev = &(curent->next);
}
curent = *prev;
}
}
}

Different output depending on whether or not I print the return value

So I have a simple snippet of C++ code which is SUPPOSED to insert a node into a binary search tree. It returns true if the value is successfully inserted and false if the value is already in the tree.
struct Node {
int data;
Node* parent = nullptr;
Node* left = nullptr;
Node* right = nullptr;
};
bool insert(Node& root, int data) {
if (data > (root.data)) {
if ((root.right) == nullptr) {
Node newNode = {data, &root};
root.right = &newNode;
return true;
} else {
return insert(*root.right, data);
}
}
else if (data < (root.data)) {
if ((root.left) == nullptr) {
Node newNode = {data, &root};
root.left = &newNode;
return true;
} else {
return insert(*root.left, data);
}
}
else {
return false; // if both values are equal
}
}
When testing my function I noticed something peculiar. When I don't print the function's return value, it gives the right answer (20):
Node root = {50};
insert(root, 20);
cout << (root.left->data) << endl;
However, when I do print the return value, it gives the incorrect result (0):
Node root = {50};
cout << insert(root, 20) << endl;
cout << (root.left->data) << endl;
I cannot possibly fathom why this happens, but my best bet is because of some weird memory hijinks, perhaps not allocating new memory for the struct? I come from Python where memory management is handled automatically so I'm still getting used to situations like this.
You invoke undefined behaviour right there:
Node newNode = {data, &root};
root.right = &newNode;
This stores, in your tree, the address of a stack variable. As soon as the function returns, it's not legal anymore to dereference this Node's children. From there, anything could happen.
You probably want something like:
Node* newNode = new Node;
newNode.data = data;
newNode.root = root;
...
root.right = newNode;
Edit: Remember that whenever you put a new in code, you need a matching delete. To avoid this hassle, the modern approach is to use unique_ptr. You should look into that. In your case, since you keep back pointers to the root, you'll need either shared_ptr and/or weak_ptr.

Implementing a hasNext function in a C++ linked list

I'm attempting to write a function to see whether or not there are more nodes to search through in the linked list, and what I have so far gives me a seg fault. Any ideas on what I need to change?
Iterator class:
bool Iterator::hasNext(){
Node* temp = current->getNext();
if(temp == NULL){
return(false);
}
else{
return(true);
}
List Class:
void List::addFirst(void* obj)
{
Node* newNode = new Node(obj);
newNode->setNext(head);
head = newNode;
}
Node Class:
Node* Node::getNext()
{
return(next);
}
Main class:
List list1;
for(int i = 0; i < 4; i++) {
list1.addFirst(stars[i]);
}
Iterator itr(&list1);
while(itr.hasNext()) {
std::cout << ((char*)itr.get()->getItem())
<< std::endl;
itr.advance();
}
I am not sure about it but you can
Try
//directly accessing the next and comparing
return if(current->getNext() == NULL)
directly without storing it in a separate temp node .

Segmentation fault in queue program when using push

Im getting a segmentation fault when i try to push elements into the queue, im not an expert working with queues so i dont recognize where the problem is.
I have been searching for the solution to this problem and even though people get similar problems i didnt help me fix my problem.
Here is the code:
(I used the debug option in Dev-c ++ 5.9.2 and it told me the line "temp->link = NULL;" is causing the problem but i have no idea how to fix it)
#include <iostream>
using namespace std;
struct Node {
int data;
Node* link;
};
class Queue {
public:
Queue();
~Queue();
void pushBack(int d);
bool popFront();
bool isEmpty();
void displayQueue();
private:
Node* back;
Node* front;
};
Queue::Queue() {
back = NULL;
front = NULL;
}
Queue::~Queue() {
while (!isEmpty()) {
popFront();
}
}
void Queue::pushBack(int d) {
Node* temp;
if (temp == NULL) {
return;
} else {
temp->link = NULL; <========== This is where is get the error
if (back == NULL) {
back = temp;
front = temp;
} else {
front->link = temp; <===== here too
front = temp;
}
}
}
bool Queue::popFront() {
if (front == NULL) {
return false;
} else {
Node* removeNode;
removeNode = front;
if (back == front) {
back = NULL;
front = NULL;
} else {
Node* previousFront = back;
while (previousFront->link != front) {
previousFront = previousFront->link;
}
front = previousFront;
front->link = NULL;
}
delete removeNode;
return true;
}
}
bool Queue::isEmpty() {
return (back == NULL);
}
void Queue::displayQueue() {
if (isEmpty()) {
cout << "Queue is empty!" << endl;
} else {
Node *current;
current = back;
cout << endl << "-- BACK -- ";
while (current != NULL) {
cout << current->data << " ";
current = current->link;
}
cout << "-- FRONT --" << endl << endl;
}
}
int main(){
Queue q;
q.displayQueue();
q.pushBack(20);
q.pushBack(30);
q.displayQueue();
q.pushBack(40);
q.pushBack(12);
q.displayQueue();
q.popFront();
q.displayQueue();
return 0;
}
You have to know that when you add a new
node to the list you constructed, you need to allocate a dynamic
location for the new node and then add it to the list -queue-;
second thing : when the back is pointing already at some node in the link
you need to make the new node points at the node the back was pointing at,
then make the back pointer points at the new node .
the new function (pushBack) bacomes :
void Queue::pushBack ( int d ) {
Node* temp = new Node;
temp->data = d;
temp->link = NULL;
if (back == NULL) {
back = temp;
front = temp;
}
else {
temp->link = back;
back = temp;
}
}
You are creating a pointer to a node, but you have not created the node yet. (what everyone else has said)
change
Node* temp; - stack memory
To
Node *temp = new Node() - heap memory
im not an expert working with queues so i dont recognize where the problem is
Note that the problem has nothing to do with queues: The problem is understanding how the language works.
As Thornkey pointed out, you have a temp var in your pushBack function. It's a pointer, but it points to random data until you tell what to point at. When you follow the pointer, it could go anywhere and get a segfault or break some other part of your program.

Deleting from Binary Tree error

I wrote a small code to detect the largest number in the binary tree, it is working just fine, its simple, it goes far down to the last right node(leaf in case) and then i just cout<< it, now i would like to delete it, i looked trough some similar question, but i only need to delete the number i got back from the search, but my prog just crashes after i run it list the tree get the number, delete and try to list it again.
Here is my search:
T Remove( Node* theRoot)
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
return Largest(theRoot->rChildptr);
else
delete theRoot;
return theRoot->data;
}
Here is the full code:
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
template<class T>
class BinaryTree
{
struct Node
{
T data;
Node* lChildptr;
Node* rChildptr;
Node(T dataNew)
{
data = dataNew;
lChildptr = NULL;
rChildptr = NULL;
}
};
private:
Node* root;
void Insert(T newData, Node* &theRoot)
{
if(theRoot == NULL)
{
theRoot = new Node(newData);
return;
}
if(newData < theRoot->data)
Insert(newData, theRoot->lChildptr);
else
Insert(newData, theRoot->rChildptr);
}
void PrintTree(Node* theRoot)
{
if(theRoot != NULL)
{
PrintTree(theRoot->lChildptr);
cout<< theRoot->data<<" \n";
PrintTree(theRoot->rChildptr);
}
}
T Largest( Node* theRoot)
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
return Largest(theRoot->rChildptr);
else
delete theRoot;
return theRoot->data;
}
T Remove(Node* theRoot)
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
return Largest(theRoot->rChildptr);
else
delete theRoot;
return ;
};
public:
BinaryTree()
{
root = NULL;
}
void AddItem(T newData)
{
Insert(newData, root);
}
void PrintTree()
{
PrintTree(root);
}
T Largest()
{
return Largest(root);
}
//void Remove()
//{
// Remove(root);
//}
};
int main()
{
BinaryTree<int> *myBT = new BinaryTree<int>();
myBT->AddItem(2);
myBT->AddItem(20);
myBT->AddItem(5);
myBT->AddItem(1);
myBT->AddItem(10);
myBT->AddItem(15);
//for(int i = 0; i < 10; i++) //randommal tolti fel
//myBT->AddItem(rand() % 100);
cout << "BinaryTree:" << endl; //kilistazaa a fat
myBT->PrintTree();
cout << "Largest element: " << myBT->Largest() << endl; //visszaadja a legnagyobb elemet
//myBT->Remove();
myBT->PrintTree();
}
the actual delete function is in // comments so i can run the prog.
You are deleting theRoot and then trying to dereference it. If you want to return the value stored in the node you need to make a local copy first like this:
T value = theRoot->data;
delete theRoot;
return value;
Is the return thetRoot->data; line intended to be part of the else statement? If so you need to add brackets around it like this:
if (theRoot->rChildptr != NULL)
{
return Largest(theRoot->rChildptr);
}
else
{
T value = theRoot->data;
delete theRoot;
return value;
}
Or simply remove the else case altogether (since you always return if the child pointer is null):
if (theRoot->rChildptr != NULL)
{
return Largest(theRoot->rChildptr);
}
T value = theRoot->data;
delete theRoot;
return value;
You will also need to make sure that the parent node does not still point to a deleted child (hard to see exactly what is going on because you haven't posted much code).
You cannot simply delete the object you don't want -- you must also remove the reference you used to find the node that you are deleting. And, if the node has any children, you must reattach the child nodes elsewhere to the tree so that they remain reachable.
The thing that makes it so tricky is that you have to properly update: the parent's reference to the node being deleted; one of the 'child' pointers for one of the children of the deleted node; and the parent links from both children of the deleted node. If you perform the updates out-of-order, you'll read a stale pointer and perhaps corrupt memory, so you must wait to remove nodes until you do not need any more references from within the node and you've removed references to the node from elsewhere.
Update
Don't forget that "the last right node" can in fact be the root of your tree:
5
4
3
2
1
5 is the largest, right-most, node of your tree, and if you delete it, you've lost your entire tree.
Unless you're doing some re-balancing that we're not seeing here; if you are, be sure you also handle this case:
2
1
Our friends at Wikipedia have been very kind to analyze how to delete a node from a binary search tree:
Deleting a leaf (node with no children): Deleting a leaf is easy, as we can simply remove it from the tree.
Deleting a node with one child: Remove the node and replace it with its child.
Deleting a node with two children: Call the node to be deleted N. Do not delete N. Instead, choose either its in-order successor node
or its in-order predecessor node, R. Replace the value of N with the
value of R, then delete R.
Your delete code must handle all three of these cases. Don't forget that the node you're deleting might be the root of the tree and not have a parent node.
Can you post the entire program so that it can be compiled. But basically the problem is that when theRoot->rChildptr is NULL you are deleting theRoot and then your return statement tries to return theRoot->data which is pointing to nowhere.