How to find an element in a binary search tree? - c++

I've been trying to build a 2-3 node. The adding function is working properly and has been confirmed by me so far. The only problem is the find function, which is called to find an element inside the 2-3 node. It does not seem to be working at all. The match pointer inside the it does not take the returned valued from the find_rec method at all, even though I already assigned it. It's just getting a new given address whenever the function is called and I have no idea why it does that. Can anyone help me out ? and tell me what I did wrong ? Thank you
**LValue and RValue**
E LValue() {return _first._value;}
E RValue() {return _second._value;}
**find function**
// Assuming this set contains an element y such that (x == y),
// return a reference to y. Such a y must exist; if it does not an
// assertion will fail.
E& find(E& x)
{
// the match pointer is supposed to take
// returned pointer from the find_rec function
// Yet, it is not doing that at all.
E* match = find_rec(x, _root);
assert(match != nullptr);
return *match;
}
**find_rec function**
// Helper function: find recursion
// function returns a pointer
E* find_rec(E& x, BNode<E>* root)
{
if(root == nullptr)
return nullptr;
else
{
// 2-node
if(!root->IsThree())
{
if(x == root->LValue())
return &root->LValue();
else if (x < root->LValue())
return find_rec(x, root->GetLeft());
else
return find_rec(x, root->GetRight());
}
// 3-node
else
{
if(x == root->LValue())
return &root->LValue();
else if(x == root->RValue())
return &root->RValue();
else if(x < root->LValue())
return find_rec(x, root->GetLeft());
else if(x < root->RValue())
return find_rec(x, root->GetMiddle());
else
return find_rec(x, root->GetRight());
}
}
}

The code is clearly able to return a nullptr when the desired value is not present in the tree.
The moment it gets into that situation, the assert will trigger and the *match return would fail. I expect you need to change the function signature to provide a return type that allows for this case.

From the code seems you're returning the address of a local temporary.
I cannot be sure because the LValue() method declaration is not visible, but if it's returning the node content by value and not by reference then the find_rec function will just return garbage (the address of a temporary allocated on the stack).
A decent compiler should issue a warning for this, by the way.

Related

C++ Statement can be simplified

Apologies for the lame question. I am using Intellij Clion Student licensed version for my C++ curriculum. As a part of implementing an UnsortedList class, we had to write a method isInTheList to see if an element is present in the array. The class implementation goes as
bool UnsortedList::isInTheList(float item) {
for (int i = 0; i < length; i++) {
if (data[i] == item) {
return true;
}
return false;
}
}
However, the ide shows a coloured mark at data[i] == item with a popup saying
Statement can be simplified less... (Ctrl+F1)
This inspection finds the part of the code that can be simplified, e.g. constant conditions, identical if branches, pointless boolean expressions, etc.
For a previous method to check if the list if empty, I used the following simplified form instead of if-else statement.
bool UnsortedList::isEmpty() {
return (length == 0);
}
However, with iteration involved now, I cannot come up with a simplified statement in the former. Any help is much appreciated. Thank you.
Fix
Your return false should be moved outside off the for loop.
Because you accidentally put it inside the for loop, this iteration never execute for the second time.
So your IDE thinks the for loop is pointless, and suggests you to simplify it to:
return data[0] == item;
This obviously isn't what you want. So really this is just a one-line shift to make it right.
Why not use STL?
inline bool UnsortedList::isInTheList(float item) {
return std::find(data, data+length, item) != data+length;
}
std::find returns an iterator pointing to the element if it's found, or an iterator equal to one-past-last item (i.e. exactly the second argument passed) if nothing is found. You can use a simple equality check to decide if one is found.
You are actually returning after one iteration in your loop. That's the remark of your compiler.
Your code could be simplified by easy write this:
bool UnsortedList::isInTheList(float item) {
if (length != 0) {
return data[0] == item;
}
}
Note, that this is still undefined behavior (UB). You do not have a return in all of your execution paths.
If your list is empty, you never enter the loop, which results in an UB, because there is no return statement, but the function has to return a bool.
I think, your intention was, to write something like this.
bool UnsortedList::isInTheList(float item) {
for (int i = 0; i < length; i++) {
if (data[i] == item) {
return true;
}
}
return false;
}
Move the return false; out of your for loop and you will be fine (still there are better ways to implement this, but that's another topic).

Recursive function throwing end of non-void function warning

Node * replaceValue(Node * x) const
{
if (x == nullptr)
return nullptr;
if (x->left != nullptr)
replaceValue(x->left);
else
return x;
}
Warning: control reaches end of nonvoid function
Should i just ignore this? I made sure that this function always returns something (all pointers initialized with nullptr), but I don't want this warning to keep popping up. If I add a return nullptr at the end of the function, then it just crashes. Is there any way around this?
Never ignore a warning. It's telling you something important.
In this case when you call replaceValue recursively, you're throwing away the return value from that call then falling out the bottom of the function without returning anything.
You probably want to use return replaceValue instead.
Although it's a very old question still I will answer it.
It is like not providing a default case to a switch statement. When the control reaches the end of your non-void function it doesn't have anything to return, in case all of your conditions fail. I believe the compiler does this so that you take care of all the corner cases and possibilities for the function. For example, if the user enters a value of a datatype which you haven't used in your function then without throwing an exception a default value can be returned instead.
If you don't want to do this you can always use a void function that doesn't return anything.
You should consider adding a return statement like this so that after the recursive call a value is returned.
if (x->left != nullptr)
return replaceValue(x->left);
But if you are sure that your function takes care of all the corner cases and the control will never reach the default value then you can add return x at the end just like this. The return x here is just to suppress the error message and nothing else in your case.:
Node * replaceValue(Node * x) const
{
if (x == nullptr)
return nullptr;
if (x->left != nullptr)
replaceValue(x->left);
else
return x;
return x; // Default value
}

My C++ program crashes on this function?

I'm a beginner programmer(Just started) and I'm writing some code for a binary search tree for fun.
For some reason, whenever I call this append function my program crashes. It has to do with one of the two functions itself, not anything else in the header file or my source file which includes main(). By the way Leaf is just a struct with an int value, and two Leaf pointers named left and right.
This crashes with no output error.
Leaf* BinarySearchTree::GetLeaf(int x,Leaf*a)
{
int key = a->value;
cout <<key<<"\n";
if(x > key)
{
if(a->right == NULL)
{
Leaf* newleaf = new Leaf();
newleaf->value = x;
a->right = newleaf;
return newleaf;
}
else if (a->right != NULL)
{
return a->right;
}
}
else if(x< key)
{
if(a->left == NULL)
{
Leaf* newleaf = new Leaf();
newleaf->value = x;
a->left = newleaf;
return newleaf;
}
else if (a->left != NULL)
{
return a->left;
}
}
else if(x == key)
{
//tbc
}
}
void BinarySearchTree::Append(int x)
{
if(root != NULL)
{
Leaf* current = root;
while(current->value != x)
{
current = BinarySearchTree::GetLeaf(x,current);
cout<<"value: "<<
current->value;
}
}
else
{
cout <<" No ROOT!";return;
}
}
If you want to see my main (source) file, go here(Since I don't want to flood this post)
http://pastebin.com/vrh7KkMm
If you want to see the rest of the header file, where these two functions are located,
http://pastebin.com/ZGWewPdV
In your BinarySearchTree constuctor, you start accessing root without having allocated memory for it first. This may be your crash. Try adding
root = new Leaf()
at the start of the constructor.
Edit - More information:
C++ does not automatically set values for your member variables, you normally need to initialize them by hand. (c++11 does allow you to do it in the declaration). This means that any variable that you don't set to a value will have a garbage value in it. If you use this garbage value as a pointer, you will most likely get a crash.
In your case, one of the initial problems is that the LinkedList class did not initialize its root member variable in the constructor before starting to reference it.
BinarySearchTree has the same problem.
Learning to use the debugger is one of the best things you can do when learning to program. It lets you step through your code one line at a time and look at the value of each variable. This makes i easy to see where things aren't going as you planned. Which debugger you use depends on your platform.
If GetLeaf() is called with x == key the function returns neither nullptr nor a valid pointer. This is a potential crash source. You need to return something sensible in any case.
UPDATE: Don't forget to initialize the Leaf structure properly in its constructor (all three members).
UPDATE2: Also initialize your root properly. I would initialize it with nullptr and change the append function in a way that it creates the very first leave if root==nullptr.

error: lvalue required as left operand of assignment c++

template <typename Type>
bool Lazy_deletion_node<Type>::insert( Type const &obj ) {
if(this == nullptr){
Lazy_deletion_node<Type> *tmp = new Lazy_deletion_node( obj );
this = tmp;
return true;
}
else if(obj == this->retrieve()){
if(erased){
erased = false;
return true;
}
else{
return false;
}
}
else if(obj < this->retrieve()){
left()->insert( obj );
}
else if(obj > this->retrieve()){
right()->insert( obj );
}
}
Hey guys, I'm trying to to do an insert for a Lazy deletion tree, which is basically a binary search tree except that I mark the nodes as "erased" instead of actually removing them from the tree. This is a method to insert a new node into the tree containing the object obj. nullptr is defined to be 0.
I first test to see if the pointer is pointing to 0. If it is, I create a node that stores obj inside and then I try to make the pointer point to this newly created node.
However, when I try to compile, it gives me the error that lvalue is required as left operand of assignment on the line that reads this = tmp;. Can anybody tell me why this is happening?
Thanks in advance.
You can't reassign this. Like the error says, it's not a modifiable l-value.
However, if this was a pointing at an object that had a mutable field of the same type you're trying to assign, you could access it through this->myField or this.myField, depending on whether it's a pointer or a reference.
"this" is a reserved keyword that is a pointer to the object currently in scope (loosely similar to "self" if you're familiar with Python). It is designed to ALWAYS point to the object currently in scope, which means you cannot change its value.
What you're trying to do when you use "this = tmp;" is a little bit like trying to use "false = 10;"

What can I use as a NULL struct?

I'd like to code a loop going through several instances of the same struct (named edg in my case) iterated by a certain function going from neighbor to neighbor until it returns an element that says STOP. I tried coding it using a NULL return but it doesn't work. What could I use?
Here is some code explaining it probably more accurately than my previous words:
My structure:
struct edg{
int i,j,k;
edg(int a, int b, int c){
i = a; j = b; k = c; //I'm adding a constructor to it
}
}
My iterating function:
edg neighbour(edg temp){
if(temp satisfies certain criterias){ return edg(new coordinates);}
else{ return NULL;}
}
My loop:
while(my_edg!=NULL){
my_edg = neighbour(my_edg);
}
I guess I could just pick a certain value of an edg define it as a rejection, and replace in my loop by:
while(my_edg!=edg_marked_as_rejection)
But is there another way to do so?
Note that your function:
edg neighbour(edg temp){
if(temp satisfies certain criterias){ return edg(new coordinates); }
else{ return NULL; }
}
returns an instance of edg by value thus trying to return NULL; is invalid (unless you've defined some custom conversion). NULL is a possible value when passing / returning by pointer, which in this case could mean changing the prototype of this function to:
edg* neighbour(edg temp) { ... }
however based on the semantics it would be more reasonable to either pass by reference and return a flag indicating success:
bool neighbour(const edg& temp, edg& result) {
if (...) {
result = ...;
return true;
}
return false;
}
or in case your condition "if(temp satisfies certain criterias)" should be met in most of cases and these criteria not being met is rather an exceptional state, you might also consider throwing an exception (instead of returning NULL).
A third option might be implementing a NULL object design pattern, meaning that instance of edg marked as "invalid" would be constructed and returned and caller would do something like:
edg n = neighbour(tmp);
if (!n.isValid()) {
...
}