Get Height of binary search tree recursively [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I've been trying make a function to get the height of a binary tree in recursive way.
int BSNode::getHeight() const //Returns the height of the tree.
{
if (this->_left == nullptr && this->_right == nullptr)
{
return 0;
}
else
{
return std::max(this->_left->getHeight(), this->_right->getHeight()) + 1;
}
}
I debugged my code and for some reason, I got access violation error on the 'if condition' line. I can't see why I'm still getting this error. I'm suppose that it happening because one of my left or right is null, but I cant see other way to make it.
This is my function for inserting a node to the tree:
void BSNode::insert(string value) //Inserts node to the tree.
{
if (value > this->_data)
{
if (this->_right != NULL)
{
this->_right->insert(value);
}
else
{
this->_right = new BSNode(value);
}
}
else if (value < this->_data)
{
if (this->_left != NULL)
{
this->_left->insert(value);
}
else
{
this->_left = new BSNode(value);
}
}
}
This is the class I built:
class BSNode
{
private:
string _data;
BSNode* _left;
BSNode* _right;
}

The negation of the condition in this if statement
if (this->_left == nullptr && this->_right == nullptr)
is
else if ( not ( this->_left == nullptr && this->_right == nullptr) )
that is in turn equivalent to
else if ( this->_left != nullptr || this->_right != nullptr )
However in the function there is ignored the fact that either this->_left or this->_right can be equal to nullptr.
return std::max(this->_left->getHeight(), this->_right->getHeight()) + 1;
Also it is unclear why the height has the signed type int instead of some unsigned type as for example size_t.
I suppose that the head of the tree is always unequal to nullptr. Otherwise you should rewrite the function as a static member function with one parameter: pointer to the head node.
The function can look the following way
size_t BSNode::getHeight() const //Returns the height of the tree.
{
return 1 + std::max(
this->_left == nullptr ? 0 : this->_left->getHeight(),
this->_right == nullptr ? 0 : this->_right->getHeight());
}

Related

How to print a Binary Tree diagram (vertical) and ensure fairly unbalanced trees are not improperly printed?

I'm trying to write functionality to print a vertical binary tree diagram,
I've got the correct breadth-first search algorithm written, and it outputs the BFS-ordered tree traversal to an integer vector. The code can be seen below:
void bst::printlist(Node* node)
{
std::queue<Node*> travQueue;
std::vector<int> result;
travQueue.push(node);
while (!travQueue.empty())
{
result.push_back(node->val);
if (node->prev != NULL)
{
travQueue.push(node->prev);
}
if (node->next != NULL)
{
travQueue.push(node->next);
}
travQueue.pop();
node = travQueue.front();
}
}
However, I am completely stumped on how to convert the resultant vector to one that accurately represents all missing nodes that exist as gaps in a fairly unbalanced tree,
For this example, the vector would only be filled with the integers in the left-to-right order, when it would need to contain information for every missing node all the way down to the bottom level. When going to write the actual code to print the tree with ASCII characters, I will need this information if I am to be able to determine where to and where not to draw nodes -- so, I planned to include dummy values at these gaps to distinguish.
Does anyone have any recommendations for ways to solve this issue?
Thanks!
Here's a great answer, thanks to #NicoSchertler:
"You can push prev and next to travQueue even if they are nullptr. When you reach a nullptr in your iteration, add the dummy value to the result and two more nullptr to travQueue for the non-existing children."
And here's my code for it:
std::queue<Node*> travQueue;
std::vector<int> result;
int h = treeheight(root) + 1;
travQueue.push(node);
for (int i = 0; i < pow(2, h) - 1; i++)
{
node = travQueue.front();
if (node != nullptr)
{
if (node->prev != nullptr)
{
travQueue.push(node->prev);
} else
{
travQueue.push(nullptr);
}
if (node->next != nullptr)
{
travQueue.push(node->next);
} else
{
travQueue.push(nullptr);
}
} else
{
travQueue.push(nullptr);
travQueue.push(nullptr);
}
if (node != nullptr)
{
result.push_back(node->val);
} else
{
result.push_back(-1);
}
travQueue.pop();
}
return result;

c++ how to get depth of a binary tree recursively

I wrote a code that suposed to return the depth of a binary tree from the root to the node who called the function. using recursive way but I faced a problem about how to count the number of times that the function gets called so I whould know how much convexity I passed. Someone know how can I do that?
int BSNode::getDepth(const BSNode& root) const
{
if (this != nullptr)
{
if (root.getData() > this->_data)
{
this->getDepth(*root.getRight());
}
else if (root.getData() < this->_data)
{
this->getDepth(*root.getLeft());
}
else if (root.getData() == this->_data)
{
// return the number that the function counted
}
}
else
{
return 0;
}
}
You should at least return something in every case. And when you arrive at the intended node (having the data you are looking for), then return 0. In all other cases, return what you get from recursion plus 1. If the value is not found then indeed -1 should be returned. And if this -1 is coming back from recursion, it should be returned like that also to the caller (without adding 1).
Here is the code adapted:
int BSNode::getDepth(const BSNode& root) const
{
int temp;
if (this != nullptr)
{
if (root.getData() > this->_data)
{
temp = this->getDepth(*root.getRight());
return temp == -1 ? -1 : temp + 1;
}
else if (root.getData() < this->_data)
{
temp = this->getDepth(*root.getLeft());
return temp == -1 ? -1 : temp + 1;
}
else if (root.getData() == this->_data)
{
return 0;
}
}
else
{
return -1;
}
}

C++ return a const pointer inside a none const pointer function

I have coded this function to find the shallowest leaf in binary search tree it is not the best but it does the job, the leaf have to be returned after it have been found.
it is a necessary condition not to change the function prototype.
my problem is pointed by a comment below
The problem is i am returning a const Pointer inside a none const pointer function, i look before posting the question, all of the question where functions inside of classes, I have not studied them so I don't know if it is the same for functions outside of classes, is there any workaround for the problem ?
struct Node {
int _data;
struct Node *_left;
struct Node *_right;
};
//-----------------------------------------------------------------------------------
struct Node *min_depth_leaf(const struct Node *root, int &depth) {
int left_depth;
int right_depth;
if (root == NULL) {
depth = INT32_MAX;
return NULL;
} else if (root->_left == NULL && root->_right == NULL) {
depth = 0;
return root;//<-------------- The problem lays here
} else if (root->_left != NULL || root->_right != NULL) {
struct Node *left_node = min_depth_leaf(root->_left, left_depth);
struct Node *right_node = min_depth_leaf(root->_right, right_depth);
if (right_depth < left_depth) {
right_depth += 1;
depth = right_depth;
return right_node;
} else {
left_depth += 1;
depth = left_depth;
return left_node;
}
}
return NULL;
}
Two ways can be used. The first will help maintain a good project and the second will propagate undefined behaviours , giving an unstable software that behaves differently in the same situatuion.
The first way is to return a copy of the const Node, thus allowing the API user of min_depth_leaf to modify the returned copy value, without modifying the original value in the tree, code will be like:
#include<cstdlib>
struct Node {
int _data;
struct Node *_left;
struct Node *_right;
};
//-----------------------------------------------------------------------------------
struct Node *min_depth_leaf(const struct Node *root, int &depth) {
int left_depth;
int right_depth;
if (root == NULL) {
depth = INT32_MAX;
return NULL;
} else if (root->_left == NULL && root->_right == NULL) {
depth = 0;
// return a copy
Node * p = new Node();
p->_data=root->_data;
p->_left = root->_left;
p->_right = root->_right;
return p;
} else if (root->_left != NULL || root->_right != NULL) {
struct Node *left_node = min_depth_leaf(root->_left, left_depth);
struct Node *right_node = min_depth_leaf(root->_right, right_depth);
if (right_depth < left_depth) {
right_depth += 1;
depth = right_depth;
return right_node;
} else {
left_depth += 1;
depth = left_depth;
return left_node;
}
}
return NULL;
}
The other way (to be avoided) is to cast the const value to non const, causing undefined behaviors (UB), for example:
If the API user deletes the returned Node from min_depth_leaf that is returned it will be deleted from the tree.
if the API user creates the tree on stack in a function f1() and then gets the result of the min_depth_leaf in another function f2(), he will be surprised that as soon as f2() ends, the returned node will be deleted from stack, even though f1() is still not ended, so f1() will get garbage when accessing it .
This way is by using const_cast
return const_cast<Node *>(root); //never use this
Without changing the function's signature the only way to solve this problem is with const_cast:
return const_cast<Node*>(root);
Since your code looks like C rather than C++ to me, a C-style cast may be more appropriate:
return (struct Node*)root;
In any case changing the function signature is a way cleaner approach. If you make your function a template, it will work with both const and non-const nodes:
template<typename T> T* min_depth_leaf(T* root, int &depth)

search function causes program to crash

I have been going through the debugger but can't seem to pinpoint exactly what is going wrong. I have come to my own conclusion i must be missing a nullptr check somewhere or something. If anyone can provide some help it would be greatly appreciated.
error message from debugger
error msg
which looks like makes the program crash on this line:
if (node->children_[index] == nullptr) {
search function
Node* search(const string& word, Node* node, int index) const {
Node* temp;
//same as recurssive lookup just difference is returns node weather terminal or not
if (index < word.length()) {
index = node->getIndex(word[index]);
if (node->children_[index] == nullptr) {
return nullptr;
}
else {
temp = search(word, node->children_[index], index++);
}
}
return temp; // this would give you ending node of partialWord
}
Node struct for reference
struct Node {
bool isTerminal_;
char ch_;
Node* children_[26];
Node(char c = '\0') {
isTerminal_ = false;
ch_ = c;
for (int i = 0; i < 26; i++) {
children_[i] = nullptr;
}
}
//given lower case alphabetic charachters ch, returns
//the associated index 'a' --> 0, 'b' --> 1...'z' --> 25
int getIndex(char ch) {
return ch - 'a';
}
};
Node* root_;
int suggest(const string& partialWord, string suggestions[]) const {
Node* temp;
temp = search(partialWord, root_, 0);
int count = 0;
suggest(partialWord, temp, suggestions, count);
return count;
}
Might be a very simple thing. Without digging I am not sure about the rank of the -> operator versus the == operator. I would take a second and try putting parenthesis around the "node->children_[index] == nullptr" part like this:
(node->children_[index]) == nullptr
just to make sure that the logic runs like you seem to intend.
Dr t
I believe the root cause is that you're using index for two distinct purposes: as an index into the word you're looking for, and as an index into the node's children.
When you get to the recursion, index has changed meaning, and it's all downhill from there.
You're also passing index++ to the recursion, but the value of index++ is the value it had before the increment.
You should pass index + 1.
[An issue in a different program would be that the order of evaluation of function parameters is unspecified, and you should never both modify a variable and use it in the same parameter list. (I would go so far as to say that you should never modify anything in a parameter list, but many disagree.)
But you shouldn't use the same variable here at all, so...]
I would personally restructure the code a little, something like this:
Node* search(const string& word, Node* node, int index) const {
// Return immediately on failure.
if (index >= word.length())
{
return nullptr;
}
int child_index = node->getIndex(word[index]);
// The two interesting cases: we either have this child or we don't.
if (node->children_[child_index] == nullptr) {
return nullptr;
}
else {
return search(word, node->children_[child_index], index + 1);
}
}
(Side note: returning a pointer to a non-const internal Node from a const function is questionable.)

Checking for equality in two lists using == operator

I'm fairly new to C++ and I'm working on a method that will check whether two lists are identical using the == operator. Here's my code as it is right now.
bool List::operator==(const List& original) const {
if(this != &original){
if( mySize != original.getSize() ) { return false; }
unsigned counter = 0;
Node * nPtr = original.myFirst;
Node * myPtr = myFirst;
while (counter < mySize ) {
if( this->myFirst == nPtr ) {
if (counter == 0){
counter++;
nPtr = nPtr->myNext;
}
if (myFirst->myNext == nPtr) {
counter ++;
nPtr = nPtr->myNext;
}
} else {
return false;
}
}
}
return true; }
So, from what I understand, here's what my code is doing. It checks whether their addresses are the same and, if it is, it returns true. Otherwise, it checks to see that their sizes are identical. If not, returns false. If true, goes through the list and checks the different values starting at the first address and going through until it reaches the last one.
However, it's failing this test I wrote and I'm not sure why or how:
List list3;
list3.append(33);
List list4;
list4.append(33); // [33]
assert( list4 == list3 );
assert( list3 == list4 );
cout << " 3 " << flush;
My append method adds a certain value to the list and I've tested it. That method works fine.
I realize this question may be similar to this question already asked but that didn't really help me much. Thanks for any help you can provide!