For binary search tree to see if the tree has duplicated value or not. I took this post order approach.
My goal was to keep the value of the current node and then use other function traverse the tree to see if there is any matching value to that current value, and if it finds any duplicate value it brings "true value". I choose to use recursion as it seems easier to track. but when I ran the program there was no output coming out.
#include "pch.h"
#include <iostream>
using namespace std;
class BSTNode {
public:
int data;
BSTNode* left;
BSTNode* right;
BSTNode() {};
};
BSTNode* newnode(int newdata) { BSTNode *curr = new BSTNode; curr->data = newdata; curr->left = curr->right = nullptr; return curr; }
void print(BSTNode* root) {
if (root != nullptr) {
print(root->left);
cout << root->data << endl;
print(root->right);
}
}
bool checking(BSTNode* parent, int val) {
if (val == parent->data){
bool left = checking(parent->left, val);
bool right = checking(parent->right, val);
return left||right;
}
else
return false;
}
bool assist(BSTNode* parent) {
if (parent != nullptr) {
assist(parent->left);
assist(parent->right);
return checking(parent, parent->data);
}
else return false;
}
int main() {
BSTNode *test = newnode(1);
test->left=newnode(2);
test->right=newnode(3);
test->left->left=newnode(2);
test->right->right=newnode(5);
print(test);
if (assist(test))
cout << "There is duplicated" << endl;
else
cout << "There is no duplicated" << endl;
return 0;
}
Your checking function should look like this:
bool checking(BSTNode* parent, int val) {
if(parent == nullptr) // point 1
return false;
if (val == parent->data){ // point 2
return true;
}
else{
bool left = checking(parent->left, val);
bool right = checking(parent->right, val);
return left||right;
}
}
Your assist function should look something like this:
bool assist(BSTNode* parent) {
if (parent != nullptr) {
if(checking(parent->left, parent->data)) return true; // point 3
if(checking(parent->right, parent->data)) return true;
return assist(parent->left)||assist(parent->right); // point 4
}
else return false;
}
You need to check for null values.
If val is same, why are you still checking? Just stop
You need to check node's value in the left and right subtree.
Recurse it for the child nodes
If you want to check that parent value is different than child values, you might do:
bool checking(const BSTNode* node, int parent_value) {
if (node == nullptr) { return false; }
if (node->data == parent_value) { return true; }
return checking(node->left, node->data)
|| checking(node->right, node->data);
}
bool assist(const BSTNode* parent) {
if (parent == nullptr) {
return false;
}
return checking(parent->left, parent->data)
|| checking(parent->right, parent->data);
}
You could just go through the BST breadth wise with a Deque. Store the values in a set and check if the value is already in the set, if it is return true otherwise wait for the loop to finish and return true. This had the benefit of hash table lookup for values at thr cost of extra storage in O(n) time. Its also easier to follow in my opinion as it's not recursion.
bool hasDuplicate(BSTNode *parent)
{
if (!parent) return false;
std::dueue<BSTNode*> nodes;
std::unordered_set<int> vals;
nodes.push_back(parent);
while(!nodes.empty()) {
BSTNode *node = nodes.pop_front();
int v = nodes->val;
// Check if value exists and return true
if(vals.find(v) != vals.end()) return true;
// Otherwise insert it
vals.insert(v);
// insert left node if exists
if (node->left) nodes.push_back(node->left);
// insert right node if exists
if (node->right) nodes.push_back(node->right);
}
// no dups found
return false;
}
Sorry for bad indents. Did this on phone lol.
Related
I have been scratching my head for a while on this C++ program debug. I'm trying to write a program to help validate if the binary search tree syntax is correct by construction. I'm not a lost for why my program seems to be crashing at the recursive part of the program.
I have a simple Node class:
#include <iostream>
class Node
{
public:
Node(int value, Node* left, Node* right)
{
this->value = value;
this->left = left;
this->right = right;
}
int getValue() const
{
return value;
}
Node* getLeft() const
{
return left;
}
Node* getRight() const
{
return right;
}
private:
int value;
Node* left;
Node* right;
};
Here is the problematic function:
class BinarySearchTree
{
public:
static bool isValidBST(const Node* node) {
std::cout << "DEBUG 1\n";
/* false if left is > than node */
if (node->getLeft() != NULL && node->getLeft()->getValue() > node->getValue())
return false;
std::cout << "DEBUG 2\n";
/* false if right is < than node */
if (node->getRight() != NULL && node->getRight()->getValue() < node->getValue())
return false;
std::cout << "DEBUG 3\n";
/* false if, recursively, the left or right is not a BST */
//std::cout << isValidBST(node->getLeft()) << std::endl;
if (!isValidBST(node->getLeft()) || !isValidBST(node->getRight()))
return false;
/* passing all that, it's a BST */
return true;
}
};
It's called like this:
int main()
{
Node n1(1, NULL, NULL);
Node n3(3, NULL, NULL);
Node n2(2, &n1, &n3);
std::cout << " TEST ";
std::cout << BinarySearchTree::isValidBST(&n2);
std::cout << " DONE " ;
return 0;
}
Your program suffers from too much repetition, and some assumptions about pointers. To begin with, if you call isValidBST(NULL) your program exhibits undefined behavior even though one expects that an empty tree is a valid BST.
Beyond this, your compound conditional statements are duplicating not only pointer test logic, but also the comparisons which it turns out you also did not get correct. You have not considered that duplicate values in a BST are also invalid, and so fixing this logic requires multiple edits.
In general, maintaining identical logic in multiple parts of a program (or a function) adds the potential for future bugs, and it's good to avoid when possible. This is especially true when the duplicated logic is inverted.
Consider the following rearrangement of your function, with the logic in one place:
class BinarySearchTree
{
public:
static bool isValidBST(const Node* node)
{
const Node* prev = NULL;
return isValidBST(node, prev);
}
private:
static bool isValidBST(const Node* node, const Node* &prev)
{
if (!node)
return true;
// Validate left
if (!isValidBST(node->getLeft(), prev))
return false;
// Validate current
if (prev && prev->getValue() >= node->getValue())
return false;
prev = node;
// Validate right
return isValidBST(node->getRight(), prev);
}
};
The function bootstraps a private overload that maintains a pointer of the last value node tested. In this way, you can see the code is vastly simplified and more obvious to the reader.
You need to check that in isValidBST method your node variable is null or not. if node is null and you call
node->getLeft(), node->getRight() or node->getValue()
you will get an error. You need to add null check conditon in isValidBST method
if(node == NULL) return true;
Your can resolve this like
#include <stdexcept>
#include <string>
#include <iostream>
#include <algorithm>
class Node
{
public:
Node(int value, Node* left, Node* right)
{
this->value = value;
this->left = left;
this->right = right;
}
int getValue() const
{
return value;
}
Node* getLeft() const
{
return left;
}
Node* getRight() const
{
return right;
}
private:
int value;
Node* left;
Node* right;
};
class BinarySearchTree
{
public:
static bool isValidBST(const Node* node) {
if(node == NULL) return true;
std::cout << "DEBUG 1\n";
/* false if left is > than node */
if (node->getLeft() != NULL && node->getLeft()->getValue() > node->getValue())
return false;
std::cout << "DEBUG 2\n";
/* false if right is < than node */
if (node->getRight() != NULL && node->getRight()->getValue() < node->getValue())
return false;
std::cout << "DEBUG 3\n";
/* false if, recursively, the left or right is not a BST */
//std::cout << isValidBST(node->getLeft()) << std::endl;
if (!isValidBST(node->getLeft()) || !isValidBST(node->getRight()))
return false;
/* passing all that, it's a BST */
return true;
}
};
#ifndef RunTests
int main()
{
Node n1(1, NULL, NULL);
Node n3(3, NULL, NULL);
Node n2(2, &n1, &n3);
std::cout << " TEST ";
std::cout << BinarySearchTree::isValidBST(&n2);
std::cout << " DONE " ;
return 0;
}
#endif```
I found a logic bug with my recursive program:
needed this extra case with the NULL left and NULL right node.
class BinarySearchTree
{
public:
static bool isValidBST(const Node* node) {
std::cout << "DEBUG 1\n";
/* false if left is > than node */
if (node->getLeft() != NULL && node->getLeft()->getValue() > node->getValue())
return false;
std::cout << "DEBUG 2\n";
/* false if right is < than node */
**if (node->getRight() != NULL && node->getRight()->getValue() < node->getValue())
return false;**
std::cout << "DEBUG 3\n";
if (node->getLeft() == NULL && node->getRight() == NULL) {
return true;
}
/* false if, recursively, the left or right is not a BST */
//std::cout << isValidBST(node->getLeft()) << std::endl;
if (!isValidBST(node->getLeft()) || !isValidBST(node->getRight()))
return false;
/* passing all that, it's a BST */
return true;
}
};```
Hello i am new to c++ and learning about binary search trees.
I am trying to implement a simple binary search tree where i can store "KeyCodePair" object(which has string and integer) and doing some operations on tree like search and insert. Seems like there are some problems with my logic thats why first Insert function is working but second is not working(calling them from Main) I guess there is problem with the way i implemented "root" where should i write it
This is Tree.cpp:
#include "Tree.h";
#include "KeyCodePair.h";
Tree::Tree() {
treeNode* root = NULL;
}
Tree::treeNode* Tree::getNewNode(KeyCodePair data) {
treeNode* newNode = new treeNode();
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}
Tree::treeNode* Tree::Insert(KeyCodePair data) {
if (root == NULL) {
root = getNewNode(data);
}
else if (data.getCode() <= root->data.getCode()) {
root->left = Insert(data);
}
else {
root->right = Insert(data);
}
return root;
}
bool Tree::Search(KeyCodePair data) {
if (root == NULL) {
return false;
}
else if (root->data.getCode() == data.getCode()) {
return true;
}
else if (data.getCode() <= root->data.getCode()) {
return Search(data);
}
else {
return Search(data);
}
}
Tree.h:
#ifndef TREE_H
#define TREE_H
#include "KeyCodePair.h"
class Tree {
private:
struct treeNode {
KeyCodePair data;
treeNode* left;
treeNode* right;
} ;
treeNode* root;
public:
treeNode* Insert( KeyCodePair data);
bool Search(KeyCodePair data);
treeNode* getNewNode(KeyCodePair data);
Tree();
};
#endif
KeyCodePair.cpp
#include "KeyCodePair.h"
KeyCodePair::KeyCodePair(string keyparam, int codeparam) {
key = keyparam;
code = codeparam;
}
KeyCodePair::KeyCodePair() {
}
string KeyCodePair::getKey() {
return key;
}
int KeyCodePair::getCode() {
return code;
}
KeyCodePair.h
#ifndef KEYCODEPAIR_H
#define KEYCODEPAIR_H
#include <iostream>
using namespace std;
class KeyCodePair {
private:
string key;
int code;
public:
KeyCodePair();
KeyCodePair(string key, int code);
string getKey();
int getCode();
};
#endif
And Finally this is the main:
#include <iostream>
#include <string>
#include "Tree.h"
#include "KeyCodePair.h"
using namespace std;
int main()
{
Tree tree = Tree();
KeyCodePair testPair = KeyCodePair("teststring1",10);
KeyCodePair qwePair = KeyCodePair("teststring2", 20);
cout << tree.Insert(testPair) << endl;
cout << tree.Insert(qwePair) << endl; // problem on second insert
if (tree.Search(testPair) == true) cout << "Found\n";
else cout << "Not Found\n";
cin.get();
return 0;
}
Let's take a look at your insert function:
Tree::treeNode* Tree::Insert(KeyCodePair data) {
if (root == NULL) {
root = getNewNode(data);
}
else if (data.getCode() <= root->data.getCode()) {
root->left = Insert(data);
}
else {
root->right = Insert(data);
}
return root;
}
What you do here is you take in the data to be inserted, and you look at the root. If there is no root, you add a new node containing the data and assign that to the root (which is why your first insert works). However, once there is a root, you then figure out if the new node should be placed to the left or right of the root, and then recursively call Insert() with the same data. This next call to Insert will do nothing different, and look at the same root of the tree over and over to most likely produce an infinite loop.
What you have to do is using your data, first traverse all the way down the tree to the position at which you want to insert your node, then insert it and assign the pointers. Some code for this might look like so:
Tree::Insert(KeyCodePair data) {
// currPos will end up being the position where we want to insert
Tree::treeNode* currPos = root;
while (currPos != NULL) {
if (data.getCode() <= currPos->data.getCode())
currPos = currPos->left;
else if (data.getCode() > currPos->data.getCode())
currPos = currPos->right;
}
// Insert at currPos and reassign the left or right pointer of
// the parent
}
The problem is that your insert only considers the root node. You need to traverse down the tree to the point where you do the insert:
class Tree {
...
public:
treeNode* Insert(KeyCodePair data);
...
};
Step 1: Change your interface
class Tree {
...
// The insert that does the work
// We pass in the current position in the tree.
treeNode* Insert(treeNode* node, KeyCodePair data);
public:
// The public interface that accepts the data and calls the internal Insert
void Insert(KeyCodePair data);
...
};
Step 2: Use the public Insert to call the internal Insert.
void Tree::Insert(KeyCodePair data) {
// Use the internal Insert() passing the root as the starting point.
// If a new value is needed it will be returned otherwise the original
// value is returned.
root = Insert(root, data);
}
Step 3: Modify the OP Insert into an Internal Insert.
Tree::treeNode* Tree::Insert(treeNode* node, KeyCodePair data) {
if (node == NULL) {
// If we have reached the tip of the tree then
// return the new node so it can be inserted.
return getNewNode(data);
}
// Otherwise we have a node so we need to find the node
// were the data will be inserted.
// so move to the next level. Assign the result as the next
// level could be null.
if (data.getCode() <= root->data.getCode()) {
node->left = Insert(node->left, data);
}
else {
node->right = Insert(node->right, data);
}
// Return this node
// So it stays in the chain.
return node;
}
I am writing the the answer for a test sample given in testdome https://www.testdome.com/for-developers/solve-question/9708
The question is about binary search tree:
Binary search tree (BST) is a binary tree where the value of each node is larger or equal to the values in all the nodes in that node's left subtree and is smaller than the values in all the nodes in that node's right subtree.
Write a function that checks if a given binary search tree contains a given value.
For example, for the following tree:
n1 (Value: 1, Left: null, Right: null)
n2 (Value: 2, Left: n1, Right: n3)
n3 (Value: 3, Left: null, Right: null)
Call to contains(n2, 3) should return true since a tree with root at n2 contains number 3.
I modified the code as below, the output looks working well, but the test result tells one fail exist as: Performance test on a large tree: Time limit exceeded
Can you help to modified my mode to fix this fail?
#include <stdexcept>
#include <string>
#include <iostream>
class Node
{
public:
Node(int value, Node* left, Node* right)
{
this->value = value;
this->left = left;
this->right = right;
}
int getValue() const
{
return value;
}
Node* getLeft() const
{
return left;
}
Node* getRight() const
{
return right;
}
private:
int value;
Node* left;
Node* right;
};
class BinarySearchTree
{
public:
static bool contains(const Node& root, int value)
{
Node* tree;
int val = root.getValue();
std::cout<<"current node's value is:"<<val<<'\n';
if (val==value)
{
return true;
}
else if (val>value)
{
tree = root.getLeft();
if(tree != NULL)
{
std::cout<<"left node's value is:"<<tree->getValue()<<'\n';
return contains(*tree, value);
}
else
{
return false;
}
}
else
{
tree = root.getRight();
if(tree != NULL)
{
std::cout<<"right node's value is:"<<tree->getValue()<<'\n';
return contains(*tree, value);
}
else
{
return false;
}
}
//throw std::logic_error("Waiting to be implemented");
}
};
#ifndef RunTests
int main()
{
Node n1(1, NULL, NULL);
Node n3(3, NULL, NULL);
Node n2(2, &n1, &n3);
std::cout << BinarySearchTree::contains(n2, 3);
}
#endif
Remove std::cout will do. Printing to terminal has a huge time cost.
Oh, A better solution here. Why do you want to use temporary variables? While using recursion remember that the temporary variables do get stored on function's calling stack also don't use print statements.
static bool contains(const Node& root, int value)
{
if(root.getValue() == value){
return true;
}
else if(root.getValue() < value && root.getRight() != NULL){
return contains(*(root.getRight()), value);
}
else if(root.getLeft() != NULL){
return contains(*(root.getLeft()), value);
}
return false;
}
The segmentation fault occurs in the insert function specifically at the *root = x; in the first if statement. The functions were already laid out and we just had to implement them so I cant add another parameter or anything. Ive been stuck on this for a while and have no idea what it could be. The root pointer was allocated memory so I really dont know what the problem is. Any help is appreciated, thanks.
#include "treeNode.h"
#include <iomanip>
template <class V>
class tree {
TreeNode<V> * root;
TreeNode<V> * cur;
int size;
public:
// default constructor
// by default, the tree is empty
tree(){
root = nullptr;
size = 0;
}
// search value x in tree rooted at node t
bool treeSearch(V x, TreeNode<V>* t){
if(t == nullptr) return false;
if(t->getDatum() == x) return true;
return treeSearch(x, t->getLeft()) || treeSearch(x, t->getRight());
}
bool treeSearch(V x){
treeSearch(x, root);
}
// binary search value x in tree rooted at node t
bool treeBSearch(V x, TreeNode<V>* t){
if(t == nullptr) return false;
if(t->getDatum() == x) return true;
if(t->getDatum() > x)
return treeBSearch(x, t->getLeft());
else
return treeBSearch(x, t->getRight());
}
bool treeBSearch(V x){
return treeBSearch(x, root);
}
// check node t is leaf
bool isLeaf(TreeNode<V>* t){
if(t != nullptr && t->getLeft() == nullptr && t->getRight() == nullptr){
return true;
}else{
return false;
}
}
// find the height of the tree rooted at node t
int height(TreeNode<V>* t){
if(t == nullptr) return -1;
if(isLeaf(t)) return 0;
return 1 + std :: max(height(t->getLeft()), height(t->getRight()));
}
int height(){
return height(root);
}
// find the number of nodes of tree rooted at t
int nNodes(TreeNode<V>* t){
if(t == nullptr) return 0;
return 1 + nNodes(t->getLeft()) + nNodes(t->getRight());
}
int nNodes(){
return nNodes(root);
}
// insert value x to the current tree object
void insert(V x){
if(root == nullptr){
*root = x;
}
else{
cur = root;
while(cur != nullptr){
if(cur->getDatum() < x){
if(cur->getLeft() == nullptr){
cur->setDatum(x);
cur->setLeft(cur);
}
else{
cur = cur->getLeft();
}
}
else{
if(cur->getRight() == nullptr){
cur->setLeft(cur);
}
else{
cur = cur->getRight();
}
}
}
}
}
// print out the values of tree rooted at x
// it shows the hierarchy of the tree
// it will be useful for debugging
void print(TreeNode<V> * x, int indent){
if(x == nullptr) return;
if (x->getRight() != nullptr) {
print(x->getRight(), indent+4);
}
if (indent != 0) {
cout << std::setw(indent) << ' ';
}
if(x->getRight() != nullptr){
cout << " /\n" << std::setw(indent) << ' ';
}
cout << x->getDatum() << endl;
if (x->getLeft() != nullptr) {
cout << std::setw(indent) << ' ' <<" \\\n";
print(x->getLeft(), indent+4);
}
}
void print(){
int count = 0;
print(root, count);
}
};
This is the treeNode.h file that has the constructors for each function.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
template <class T>
class TreeNode{
T datum;
TreeNode<T>* left, * right;
public:
// constructor with datum value, left and right are nullptr
TreeNode(T x){
datum = x;
left = nullptr;
right = nullptr;
}
// constructor with datum value, left and right values
TreeNode(T x, TreeNode<T>* lft, TreeNode<T>* rgt){
datum = x;
left = lft;
right = rgt;
}
//destructor releases left and right nodes, if not nullptr
~TreeNode(){
if (left) {
delete left;
}
if (right) {
delete right;
}
}
// get datum value
T getDatum(){
return datum;
}
// get left pointer
TreeNode<T>* getLeft(){
return left;
}
// get right pointer
TreeNode<T>* getRight(){
return right;
}
// set the left pointer
void setLeft(TreeNode<T>* p){
left = p;
}
// set the right pointer
void setRight(TreeNode<T>* p){
right = p;
}
};
This should be obvious:
if(root == nullptr){
*root = x;
^ ~~~~ dereferencing null pointer causes UB
}
root is nullptr, but you dereferece it and assign - this is UB undefined behaviour, this particular one causes segment faults.
How to solve it - you should instead of dereferencing null pointer, assign value to it:
if(root == nullptr){
root = new TreeNode<V>( x );
}
This is part of a lab for school dealing with recursion and binary tree. If I go to insert 4 or 5 numbers and output the result I get just 3 numbers back. Here is the code for insert:
Node *insert(Node *t, int key) {
Node *insertParent;
Node *result=NULL;
if (t!=NULL) {
result=search(t,key,insertParent);
} else {
t=new Node;
t->data=key;
t->leftchild=NULL;
t->rightchild=NULL;
return t;
}
if (result==NULL) {
if (insertParent->data>key) {
insertParent->leftchild=new Node;
insertParent->leftchild->data=key;
insertParent->leftchild->leftchild=NULL;
insertParent->leftchild->rightchild=NULL;
return insertParent->leftchild;
} else if (insertParent->data<key) {
insertParent->rightchild=new Node;
insertParent->rightchild->data=key;
insertParent->rightchild->leftchild=NULL;
insertParent->rightchild->rightchild=NULL;
return insertParent->rightchild;
}
} else
return NULL;
}
But I believe the trouble is within the search function, specifically the node pointer by reference parent:
Node* search(Node *t, int key, Node *&parent) {
if (t!=NULL) {
parent=t;
if (t->data==key)
return t;
else if (t->data>key)
return search(t->leftchild,key,t);
else
return search(t->rightchild,key,t);
} else
return NULL;
}
I have a function that outputs the tree and have checked it against a tree I built manually and it works fine:
void inorder(Node *t)
{
if (t!=NULL) {
if (t->leftchild!=NULL)
inorder(t->leftchild);
cout << t->data << ", ";
if (t->rightchild!=NULL)
inorder(t->rightchild);
}
}
Not looking for an answer just looking for an area I should look at.
Your suspicion is correct. Trace how the top-level 'parent' parameter gets updated once you search more than one node deep.
Node* search(Node *t, int key, Node *&parent)
{
if(t!=NULL)
{
parent=t;
if (t->data==key)
return t;
else if (t->data>key)
return search(t->leftchild, key, parent); // use “parent” because you want to assign parent to this variable
else
return search(t->rightchild,key, parent);
}
else return NULL;
}
So I discovered my problem was with the search function. It did have to do with the reference parent node variable. I had to use four else/ifelse statement to be able to decide which way to go, recursively or not.
Node* search(Node *t, int key, Node *&parent) {
if (t!=NULL) {
if (t->data==key) {
parent=NULL;
return t;
} else if (t->data>key && t->leftchild!=NULL) {
return search(t->leftchild,key,parent); // think this needs returned
} else if (t->data>key && t->leftchild==NULL) {
parent=t;
return NULL;
} else if (t->data<key && t->rightchild!=NULL) {
return search(t->rightchild,key,parent); //think this needs returned
} else if (t->data<key && t->rightchild==NULL) {
parent=t;
return NULL;
}
} else {
parent=NULL;
return NULL;
}
}
This change in the search function necessitated a change in the insert function:
Node *insert(Node *t, int key) {
Node *insertParent=NULL;
Node *result=NULL;
if (t!=NULL) {
result=search(t,key,insertParent);
} else {
t=new Node;
t->data=key;
t->leftchild=NULL;
t->rightchild=NULL;
return t;
}
if (insertParent==NULL && result!=NULL) {
return NULL;
} else if (insertParent!=NULL && result==NULL) {
//key not found need to add
if (insertParent->data>key) {
insertParent->leftchild=new Node;
insertParent->leftchild->data=key;
insertParent->leftchild->leftchild=NULL;
insertParent->leftchild->rightchild=NULL;
return insertParent->leftchild;
} else {
insertParent->rightchild=new Node;
insertParent->rightchild->data=key;
insertParent->rightchild->leftchild=NULL;
insertParent->rightchild->rightchild=NULL;
return insertParent->rightchild;
}
}
}
Thanks to all who helped...
(Also: I answered my own question. Is this what I should of done or should I of edited my post? Would think that people would rather see the whole process and not have me delete the old non-working code...)