C++ Structure returning true, but why? - c++

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.

Related

Recursive function removing all instances of a character in a linked list

I wrote a recursive to remove nodes with a specific data value, however it is not working correctly.
Node * removeAll(Node *top, char c){
if(top == NULL)
return NULL;
Node *newTop;
if(top->data == c){
newTop = top->next;
delete top;
}else{
newTop = top;
}
newTop->next = removeAll(newTop->next,c);
return newTop;
}
The linked list provided to the function contains the values h e l l o
I expected the outputted list to contain the values h e o, but instead it has the values h e l o
I'll answer this as a tutorial because nearly everyone struggles a bit when learning how to think recursively.
Note that because it uses a while loop, #Edward's answer isn't a fully recursive form.
When you're learning, it invariably helps to write out a recursive description of the answer in human language first. Starting with code draws focus away from thinking about the algorithm and toward unimportant details like syntax and pointer semantics. In English,
A list of the form [HEAD, rest_of_list] with character C removed is equal to rest_of_list with character C removed and HEAD optionally pre-pended to it. Whether to prepend HEAD or not depends on whether it's equal to C.
Here HEAD is a single character, and rest_of_list is itself a list.
The recursive part is removing C from rest_of_list. Note that the recursion is occurring on a string one character shorter than the input. That's good! It means that the algorithm is making progress from one recursive call to the next.
We'll also need to describe a "base case" where the recursion stops. Here since the list is getting shorter from one call to the next, it's logical to try the empty list. In English,
When the input list is empty, it can't contain C, so return the empty list.
So we're ready to write code. First the base case. Your implementation is fine. A NULL pointer is the empty list in the usual C list implementation.
Node *removeAll(Node *list, char c) {
// Base case.
if (list == NULL) return NULL;
// Recursive case.
// TODO: Complete me.
}
For the recursive case, HEAD as we wrote in English is list->data in C. And rest_of_list is list->next. So go ahead and write that:
// Recursive case.
char head = list->data;
Node *rest = list->next;
The recursive case itself has 2 cases. If head is c, then we just return rest with c removed.
if (c == head) return removeAll(rest, c);
The remaining case is where head is not equal to c. Here there's a choice. You need a node to hold c. You can either re-use the one that currently holds it, which means you're changing the original list. Or you can allocate a new node, which means the original list remains intact. In real applications, this decision can be extremely important. Let's say you want to keep the original list intact. Prepending is accomplished with
return allocateNewNode(head, removeAll(rest, c));
Here allocateNewNode gets fresh memory for the node that's not being used for some other list. For example, it could call malloc.
On the other hand, if you want to change the input list (the term mutate is pretty common), then modify the first node in list.
list->next = removeAll(rest, c);
return list;
All together, the mutating case is:
Node *removeAll(Node *list, char c) {
// Base case: on empty list, return empty list.
if (list == NULL) return NULL;
// Recursive cases. Extract head value and rest of list.
char head = list->data;
Node *rest = list->next;
// If head is C, return rest with C removed.
if (c == head) return removeAll(rest, c);
// Otherwise prepend C to rest with C removed by mutating the first list node,
// which already contains head.
list->next = removeAll(rest, c);
return list;
}
I hope this is helpful to you and others trying to get the hang of recursive thinking.
Change this:
if(top->data == c){
newTop = top->next;
delete top;
}else{
newTop = top;
}
to this:
while(top && top->data == c){
newTop = top->next;
delete top;
top = newTop;
}
newTop = top;
That way successive elements which contain the target value will all be deleted before moving to the next element.
As an aside, this function might use less memory and be faster if it were written iteratively rather than recursively.

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.

How to replace data in a certain node in a linked list?

I have an exercise using linked lists for my class. I am fairly new to the language, but I've given it an attempt. The instructions tell us to "iterate through until NodeData is found, then replace the data using the sets."
What are "the sets" in C++? I've looked online and I couldn't find anything. The only thing I can think of is setting the nodes to point somewhere else. For example head->NULL. But is this really necessary if I am simply replacing the data? To replace the data I've tried temp->order = NEWDATA. Is that the correct implementation? It did not seem to work. Maybe it was an error in a different part of the code.
bool OrderLL::Modify(Order * NodeData) {
OrderNode *temp = head;
if (temp == NULL) {
cout << "Empty List";
}
else {
while (temp != NULL) {
if (temp->order == NodeData) {
//not sure if this is the proper way of deleting data inside a node
delete anOrder;
//HOW DO I REPLACE THE DATA IN THIS PART?
}
temp = temp->next;
}
}
return false;
}
On a side note, I really do not understand why I continue to recieve downvotes on all my questions. Is it because they're basic C++ questions? They're not so basic to me. I know this website looks down upon "offtopic/chat discussions" but I just don't understand what is wrong with my questions.
You mentioned "replace" in your question, so just taking a guess but might be you are expected to replace the node itself and not just the data. In which case, it will be something like this
if(curr_node->data == to_replace_data){
curr_node->next = new_node;
new_node->next = curr_node->next->next;
free( curr_node->next); //or return curr_node->next depending on what
// you are trying to do.
}

Printing unbalanced binary tree

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.

Visual Studio 2010 Debugging "if (var == NULL)" not triggering

Solved - Problem with constructor
Matthew Flaschen and Michael Burr pointed out the problem of the overloaded constructor of Node(int) calling Node() which doesn't work because...
Thanks guys!
I have built a program (I am debugging it) and have run into a weird problem... A `if` statement is not getting triggered when it should be... This is a school project where we must build an AVL Tree with at least one 'optimizing' feature.
I am sure and have tested that the `rdown` and `ldown` work (as the balancing factors) - the tree is not perfectly balanced. Rather it is based on the hight of the branches (i.e. - `balance()` should only return (1,0,-1) otherwise it is unbalanced.
I hope this is enough information to solve this weird problem... I have never ran into anything like this before with Microsoft Visual Studio 2010.
Node struct:
struct Node {
int data; // the data in the Node
int rdown; // the number of ellements below the node on the right side
int ldown; // the number of ellements below the node on the left side
Node * parrent; // the node's parrent
Node * lchild; // the nodes left child
Node * rchild; // the nodes right child
Node () { rdown = 0, ldown = 0; data = 0; parrent = NULL; lchild = NULL; rchild = NULL; }
Node (int dat) {rdown = 0, ldown = 0; parrent = NULL; lchild = NULL; rchild = NULL; data = dat; }
bool end() { if (lchild == NULL && rchild == NULL) return true; // check if this node is the 'end of the line' - where it doesn't
return false; } // have any children
bool goodToAdd() { if (lchild == NULL || rchild == NULL) return true; // make sture the current node has at least one spot to add
return false; } // a new node to - either lchild or rchild must be NULL
int balance() { return (ldown - rdown); } // get a balance number for the node
};
Search function that is causing the problems
Node * AVL_Tree::search(const Node * num) {
Node * tmpNode = AVL_Tree::root; // tmpNode is a place holder for the search
for (int i = 1; true; i++) { // increment int i to check for excess searching -> pervents endless loop
if (tmpNode == NULL) //****** causing problems******** // the search has reached a dead end (the data is not contained) ==> NULL
return NULL;
if (tmpNode->data == num->data) // if the data of num is the same as tmpNode the data is contained ==> Node *
return tmpNode;
// since the node has not been found yet move down the tree...
if (tmpNode->data > num->data && tmpNode->lchild != NULL) // if the data is smaller than the tmpNode move to the lchild
tmpNode = tmpNode->lchild;
else if (tmpNode->rchild != NULL) // since the node has been proven to not be = to the data to be searched for
tmpNode = tmpNode->rchild; // and it is not smaller... move to the right
if (i > (root->ldown + 1) && i > (root->rdown + 1) ) { // the while loop has searched suffecent time and has not ended
string tmp = "the search incountered a critical error... aborting..."; // to prevent an endless loop the string error
throw tmp; // is thrown (should not happen) - indicates a broken tree
}
}
}
A screen shot of the first encounter with the for loop
A screen shot of the second encounter with the for loop
If you would note in the 'Autos' tab at the bottom that all the data and the node itself's address is NULL - yet in the next screen shot it continues
The program continues!!! what?>!
I pushed F-10 (the 'go to next command' button) ... and it jumps right over the statement? why?
0xcdcdcdcd is not a NULL pointer - that value is used in the debug builds of MSVC for memory that has been allocated but not initialized.
See When and why will an OS initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete? for more details.
The root of your problem might be in the constructor that takes an int parameter:
Node (int dat) { Node(); data = dat; }
The Node(); statement ends up doing nothing. This constructor leaves most of the members of the structure uninitialized.
tmpNode is not null in any screenshot.
It's first 0x00294820, then 0xcdcdcdcd. The second is the magic debug value for uninitialized malloced memory.
NULL, in C++, tends to be (but is not guaranteed to be) 0.
In your second/third screenshots, tmpNode = 0xcdcdcdcd, which is not NULL. 0xcdcdcdcd is the value Visual Studio gives to uninitialized variables (when running a debug release).
Make sure to initialize all all your nodes' fields:
Node* root = NULL;
or
Node* root = new Node(); //Don't forget to delete!
Setting fields to NULL is not done automatically in C++ as it is in other languages like Java and C#.
tmpNode is referencing uninitialized memory, which is generally not guaranteed to be null. For instance, the following statement does not guarantee that tmpNode is null.
Node* tmpNode; // or assignment to another uninitialized variable.
You are assigning tmpNode to root and I suspect that root is uninitialized, hence the non-null value of tmpNode. Please check your initialization of root -- I cannot comment on it as you haven't posted this specific code.