Why does this code run for VS but not gcc/g++? - c++

I'm trying to implement a Red Black Tree using VS 2019 as my IDE. It seems to work in VS but when I try to compile and run using anything else, it results in a seg fault whenever my insert function is called more than once. (I've tried online compilers and sending it to a friend) I'm stuck as I don't know where to start trying to fix my error. I've heard that VS handles dynamic memory differently but I'm not too sure.
Below is my rotate, BST insert and insert functions.
#include <iostream>
#include <vector>
// default constructor
// creates empty tree, root is nullptr
class NodeT
{
public:
// public variables
double key;
double value;
NodeT* left;
NodeT* right;
NodeT* parent;
bool isBlack;
// constructors
NodeT()
{
key = 0;
value = 0;
left = nullptr;
right = nullptr;
parent = nullptr;
isBlack = false;
}
NodeT(double keyset, double valueset, bool isBlackset)
{
key = keyset;
value = valueset;
left = nullptr;
right = nullptr;
parent = nullptr;
isBlack = isBlackset;
}
};
class RedBlackTree
{
public:
// default constructor, sets all to null
RedBlackTree();
// insert
// inserts the first parameter key, and value second parameter into the tree
// returns true if done, false if there are duplicates, dont insert
bool insert(double insert_key, double insert_value);
public:
NodeT* root;
void leftrotate(NodeT* to_rotate);
void rightrotate(NodeT* to_rotate);
bool bstinsert(NodeT* insert);
};
RedBlackTree::RedBlackTree()
{
root = nullptr;
}
void RedBlackTree::leftrotate(NodeT* to_rotate)
{
NodeT* new_parent = nullptr;
new_parent = to_rotate->right;
to_rotate->right = new_parent->left;
if (new_parent->left != nullptr)
{
new_parent->left->parent = to_rotate;
}
new_parent->parent = to_rotate->parent;
if (to_rotate->parent == nullptr)
{
root = new_parent;
}
else if (to_rotate == to_rotate->parent->left)
{
to_rotate->parent->left = new_parent;
}
else
{
to_rotate->parent->right = new_parent;
}
new_parent->left = to_rotate;
to_rotate->parent = new_parent;
}
void RedBlackTree::rightrotate(NodeT* to_rotate)
{
NodeT* new_parent = to_rotate->left;
to_rotate->left = new_parent->right;
if (new_parent->right != nullptr)
{
new_parent->right->parent = to_rotate;
}
new_parent->parent = to_rotate->parent;
if (to_rotate->parent == nullptr)
{
root = new_parent;
}
else if (to_rotate == to_rotate->parent->right)
{
to_rotate->parent->right = new_parent;
}
else
{
to_rotate->parent->left = new_parent;
}
new_parent->right = to_rotate;
to_rotate->parent = new_parent;
}
bool RedBlackTree::bstinsert(NodeT* insert)
{
NodeT* parent = root;
NodeT* search = root;
if (root == nullptr)
{
root = insert;
}
else
{
while (search != nullptr)
{
parent = search;
if (insert->key < parent->key)
{
search = parent->left;
}
else if (insert->key > parent->key)
{
search = parent->right;
}
else
{
return false;
}
}
if (insert->key < parent->key)
{
parent->left = insert;
insert->parent = parent;
return true;
}
else if(insert->key > parent->key)
{
parent->right = insert;
insert->parent = parent;
return true;
}
else
{
return false;
}
}
}
bool RedBlackTree::insert(double insert_key, double insert_value)
{
NodeT* y = nullptr;
NodeT* x = new NodeT(insert_key, insert_value, false);
bool dupe = bstinsert(x);
if (dupe == false)
{
return false;
}
while (x != root && x->parent->isBlack == false)
{
if (x->parent == x->parent->parent->left)
{
y = x->parent->parent->right;
if (y == nullptr || y->isBlack == true)
{
if (x == x->parent->right)
{
x = x->parent;
leftrotate(x);
}
x->parent->isBlack = true;
x->parent->parent->isBlack = false;
rightrotate(x->parent->parent);
}
else if (y->isBlack == false)
{
x->parent->isBlack = true;
y->isBlack = true;
x->parent->parent->isBlack = false;
x = x->parent->parent;
}
}
else
{
y = x->parent->parent->left;
if (y == nullptr || y->isBlack == true)
{
if (x == x->parent->left)
{
x = x->parent;
rightrotate(x);
}
x->parent->isBlack = true;
x->parent->parent->isBlack = false;
leftrotate(x->parent->parent);
}
else if (y->isBlack == false)
{
x->parent->isBlack = true;
y->isBlack = true;
x->parent->parent->isBlack = false;
x = x->parent->parent;
}
}
}
root->isBlack = true;
return true;
}
Calling this in main results in an seg fault except when in VS:
int main()
{
RedBlackTree test;
test.insert(47, 1);
test.insert(32, 2);
}
Thanks for taking the time to read this. Any help is appreciated.

There is at least one error that causes undefined behavior:
The RedBlackTree::bstinsert function fails to return a value when it is supposed to return a bool.
To verify this is the error, a line right before the end of the bstinsert function can be placed to verify that this is an error.
bool RedBlackTree::bstinsert(NodeT* insert)
{
NodeT* parent = root;
NodeT* search = root;
if (root == nullptr)
{
root = insert;
}
else
{
while (search != nullptr)
{
parent = search;
if (insert->key < parent->key)
{
search = parent->left;
}
else if (insert->key > parent->key)
{
search = parent->right;
}
else
{
return false;
}
}
if (insert->key < parent->key)
{
parent->left = insert;
insert->parent = parent;
return true;
}
else if (insert->key > parent->key)
{
parent->right = insert;
insert->parent = parent;
return true;
}
else
{
return false;
}
}
std::cout << "This is undefined behavior\n"; // <-- add this line
}
You will see that the std::cout line will be encountered to confirm that you are returning from bstinsert without returning a value.
Also, the compiler you're using (Visual Studio), would have given a warning to you about this issue. Something similar to this:
warning C4715: 'RedBlackTree::bstinsert': not all control paths return a value
You should not have ignored this warning.

Related

I'm having a segmentation error when I use a dataset of 1000 key values and for some reason the the AVL rotations don't happen around the node

#include "BST.h"
#include "AVL.h"
#include <iostream>
AVLTree::AVLTree() {
}
int AVLTree::max(int a, int b) {
return (a > b)? a : b;
}
int AVLTree::height(std::shared_ptr<BSTNode>N) const {
if (N == nullptr){
return 0;
}
return N->height_;
}
void AVLTree::fixHeight(std::shared_ptr<BSTNode>& N) {
auto h1 = height(N->left_);
auto h2 = height(N->right_);
N->height_ = (h1 > h2 ? h1 : h2) + 1;
}
int AVLTree::getBalance(std::shared_ptr<BSTNode> N) {
if (N == nullptr)
return 0;
return height(N->left_) - height(N->right_);
}
std::shared_ptr<BSTNode> AVLTree::rightRotate(std::shared_ptr<BSTNode>n){
std::shared_ptr<BSTNode>x = n->left_;
std::shared_ptr<BSTNode>T2 = x->right_;
std::weak_ptr<BSTNode>tempParent = n->parent_;
// Perform rotation
x->right_ = n;
n->left_ = T2;
// Update heights
n->height_ = max(height(n->left_), height(n->right_)) + 1;
x->height_ = max(height(x->left_), height(x->right_)) + 1;
tempParent = x;
// Return new root
return x;
}
std::shared_ptr<BSTNode> AVLTree::leftRotate(std::shared_ptr<BSTNode>n){
std::shared_ptr<BSTNode>y = n->right_;
std::shared_ptr<BSTNode>T2 = y->left_;
std::weak_ptr<BSTNode>tempParent = n->parent_;
// Perform rotation
y->left_ = n;
n->right_ = T2;
// Update heights
n->height_ = max(height(n->left_), height(n->right_)) + 1;
y->height_ = max(height(y->left_), height(y->right_)) + 1;
tempParent = y;
// Return new root
return y;
}
void AVLTree::balance(std::shared_ptr<BSTNode> N) {
if(N != root_){
if(getBalance(N) >= -1 && getBalance(N) <= 1){
if(N != root_){
balance(N->parent_.lock());
}
}
if(getBalance(N) == 2){
if(N->key_ < N->left_->key_){
rightRotate(N);
}
if(N->key_ < N->left_->key_){
N->left_ = leftRotate(N->left_);
rightRotate(N);
}
}
if(getBalance(N) == -2){
if(N->key_ > N->right_->key_){
leftRotate(N);
}
if(N->key_ < N->right_->key_){
N->right_ = rightRotate(N->right_);
leftRotate(N);
}
}
}
N->height_= max( height( N->left_ ), height( N->right_ ) ) + 1;
}
void AVLTree::AVLInsert(int key) {
std::shared_ptr<BSTNode>lastNode;
lastNode = BST::Insert(key);
balance(lastNode);
}
So I'm supposed to implement an AVL tree with an input of a JSON file. So for that reason, I' created an AVLTree class. The problem with this class is that when I use a dataset of, say, 1000, it doesn't work, but it works for a dataset of 10. My AVL rotations don't seem to work either and so the tree is never balanced around the root but otherwise, it works perfectly.
The BST::Insert(key) returns the last node aka the node that was just inserted.
I use smart pointers to point to each value and to move them around in the BST. My BST class uses smart pointers so I would love it if someone could help me out using smart pointers.
Yes, this is an assignment but it's just a small bug I haven't been able to figure out.
BSTNode::BSTNode(int key) :
key_(key),
parent_(std::weak_ptr<BSTNode>()),
left_(nullptr),
right_(nullptr) {}
BSTNode::BSTNode(int key, std::weak_ptr<BSTNode> parent) :
key_(key),
parent_(parent),
left_(nullptr),
right_(nullptr) {}
bool BSTNode::IsLeaf() const {
return left_ == nullptr && right_ == nullptr;
}
bool BSTNode::HasLeftChild() const {
return left_ != nullptr;
}
bool BSTNode::HasRightChild() const {
return right_ != nullptr;
}
void BSTNode::DeleteChild(std::shared_ptr<BSTNode> v) {
if (left_ == v) {
left_ = nullptr;
} else if (right_ == v) {
right_ = nullptr;
} else {
std::cerr << "BSTNode::DeleteChild Error: non-child passed as argument\n";
exit(EXIT_FAILURE);
}
}
void BSTNode::ReplaceChild(std::shared_ptr<BSTNode> v, std::shared_ptr<BSTNode> u) {
if (left_ == u || right_ == u) {
std::cerr << "BSTNode::ReplaceChild Error: child passed as replacement\n";
}
if (left_ == v) {
left_ = u;
u->parent_ = v->parent_;
} else if (right_ == v) {
right_ = u;
u->parent_ = v->parent_;
} else {
std::cerr << "BSTNode::ReplaceChild Error: non-child passed as argument\n";
exit(EXIT_FAILURE);
}
}
int BSTNode::height() {
if (this == nullptr){
return -1;
}
return this->height_;
}
int BSTNode::balanceFactor() {
if (this == nullptr){
return 0;
}
return this->right_->height() - this->left_->height();
}
BST::BST() : root_(nullptr), size_(0) {}
std::shared_ptr<BSTNode> BST::Insert(int key) {
if (root_ == nullptr) {
root_ = std::make_shared<BSTNode>(key);
size_++;
return root_;
}
std::shared_ptr<BSTNode> currentNode = root_, lastNode = nullptr;
while (currentNode != nullptr) {
lastNode = currentNode;
if (key < currentNode->key_) {
currentNode = currentNode->left_;
} else {
currentNode = currentNode->right_;
}
}
if (key < lastNode->key_) {
lastNode->left_ = std::make_shared<BSTNode>(key, lastNode);
} else {
lastNode->right_ = std::make_shared<BSTNode>(key, lastNode);
}
size_++;
return lastNode;
}
bool BST::Delete(int key) {
std::shared_ptr<BSTNode> currentNode = root_;
while (currentNode != nullptr) {
if (currentNode->key_ == key) {
if (currentNode->IsLeaf()) {
DeleteLeaf(currentNode);
} else if (currentNode->left_ == nullptr) {
assert(currentNode->right_ != nullptr);
std::shared_ptr<BSTNode> parent = currentNode->parent_.lock();
parent->ReplaceChild(currentNode, currentNode->right_);
size_--; assert(size_ >= 0);
} else if (currentNode->right_ == nullptr) {
assert(currentNode->left_ != nullptr);
std::shared_ptr<BSTNode> parent = currentNode->parent_.lock();
parent->ReplaceChild(currentNode, currentNode->left_);
size_--; assert(size_ >= 0);
} else {
currentNode->key_ = DeleteMin(currentNode);
}
}
currentNode = (key < currentNode->key_) ?
currentNode->left_ : currentNode->right_;
}
return false;
}
int BST::DeleteMin() {
return DeleteMin(root_);
}
void BST::DeleteLeaf(std::shared_ptr<BSTNode> currentNode) {
std::shared_ptr<BSTNode> parent = currentNode->parent_.lock();
if (parent == nullptr) {
// Delete root
root_ = nullptr;
size_--; assert(size_ == 0);
} else {
if (parent->right_ == currentNode) {
parent->right_ = nullptr;
} else if (parent->left_ == currentNode) {
parent->left_ = nullptr;
} else {
std::cerr << "BST::DeleteLeaf Error: inconsistent state\n";
}
size_--; assert(size_ >= 0);
}
}
int BST::DeleteMin(std::shared_ptr<BSTNode> currentNode) {
std::shared_ptr<BSTNode> lastNode = nullptr;
while (currentNode != nullptr) {
lastNode = currentNode;
currentNode = currentNode->left_;
}
int result = lastNode->key_;
std::shared_ptr<BSTNode> parent = lastNode->parent_.lock();
if (parent == nullptr) {
// lastNode is root
if (lastNode->right_ != nullptr) {
root_ = lastNode->right_;
lastNode->right_->parent_.reset();
} else {
root_ = nullptr;
}
} else {
// lastNode under the root
if (lastNode->right_ != nullptr) {
parent->left_ = lastNode->right_;
lastNode->right_->parent_ = parent;
} else {
parent->left_ = nullptr;
}
}
size_--; assert(size_ >= 0);
return result;
}
size_t BST::size() const {
return size_;
}
bool BST::empty() const {
return size_ == 0;
}
bool BST::Find(int key) const {
std::shared_ptr<BSTNode> currentNode = root_;
while (currentNode != nullptr) {
if (currentNode->key_ == key) {
return true;
}
currentNode = (key < currentNode->key_) ?
currentNode->left_ : currentNode->right_;
}
return false;
}
std::string BST::JSON() const {
nlohmann::json result;
std::queue< std::shared_ptr<BSTNode> > nodes;
if (root_ != nullptr) {
result["root"] = root_->key_;
nodes.push(root_);
while (!nodes.empty()) {
auto v = nodes.front();
nodes.pop();
std::string key = std::to_string(v->key_);
if (v->left_ != nullptr) {
result[key]["left"] = v->left_->key_;
nodes.push(v->left_);
}
if (v->right_ != nullptr) {
result[key]["right"] = v->right_->key_;
nodes.push(v->right_);
}
if (v->parent_.lock() != nullptr) {
result[key]["parent"] = v->parent_.lock()->key_;
} else {
result[key]["root"] = true;
}
result[key]["height"] = v->height();
result[key]["balance factor"] = v->balanceFactor();
}
}
result["height"] = root_->height();
result["size"] = size_;
return result.dump(2) + "\n";
}
And this is the AVLCommands.cxx
#include <string>
#include "json.hpp"
#include <iostream>
#include <fstream>
#include "BST.h"
#include "AVL.h"
int main(int argc, char** argv) {
std::ifstream file1;
file1.open(argv[1]);
nlohmann::json jsonObject;
if (file1.is_open()) {
file1 >> jsonObject;
} else {
std::cout << "Invalid Arguments";
}
AVLTree avl_tree;
int numOps = jsonObject["metadata"]["numOps"];
if(numOps == 10){
for(int i = 0; i < numOps; i++ ){
std::string num;
if(i < 9){
num = "0" + std::to_string(i+1);
}
else{
num = std::to_string(i+1);
}
avl_tree.AVLInsert(jsonObject[num]["key"]);
}
}
if(numOps == 1000){
for(int i = 1; i <= numOps; i++ ){
std::string num;
if(i < 10 && i > 0){
num = "000" + std::to_string(i);
avl_tree.AVLInsert(jsonObject[num]["key"]);
}
if(i < 100 && i >= 10){
num = "00" + std::to_string(i);
avl_tree.AVLInsert(jsonObject[num]["key"]);
}
if(i < 1000 && i >= 100){
num = "0" + std::to_string(i);
avl_tree.AVLInsert(jsonObject[num]["key"]);
}
if(i == 1000){
num = std::to_string(i);
avl_tree.AVLInsert(jsonObject[num]["key"]);
}
}
}
std::cout << avl_tree.JSON() << "\n";
}

Doubly Linked List fails to add or delete valid entries

I've run it many times. I tried fixing my deleteNode() and addNode(), but it did not work. The output showed me that it failed to add some valid entries in my list, which resulted in failing to delete these valid entries. Someone please help me find the errors... I think either my isEmpty() is wrong or the addNode got messed up.
// Add nodes and makes it work in any cases: backward/forward
bool LinkedList::addNode(int id, string str) {
bool result = false;
if (id >= 0 && !(idExists(id))) {
Node *current = head;
Node *temp = new Node;
temp->data.data = str;
temp->data.id = id;
temp->forward = NULL;
temp->back = NULL;
// Kinds of adding cases
if(head == NULL) { // Check if list is empty
addHead(temp, current);
result = true;
} else {
while(temp->data.id > current->data.id && current->forward != NULL) {
current = current->forward;
}
// Backward
if(current->back == NULL) {
if(temp->data.id > current->data.id) {
if(current->forward == NULL) {
addTail(temp, current);
} else {
addMiddle(temp, current);
}
} else {
addHead(temp, current);
}
result = true;
// Forward
}else if(current->forward == NULL) {
if (temp->data.id > current->data.id) {
addTail(temp, current);
} else {
addMiddle(temp, current);
}
result = true;
}else {
if(temp->data.id > current->data.id) {
addMiddle(temp, current);
result = true;
}
}
}
}
return result;
}
void LinkedList::addHead(Node *temp, Node *current) {
if (head != NULL){
temp->forward = current;
current->back = temp;
head = temp;
} else {
head = temp;
}
}
void LinkedList::addMiddle(Node *temp, Node *current) {
temp->forward = current;
temp->back = current->back;
current->back->forward = temp;
current->back = temp;
}
void LinkedList::addTail(Node *temp, Node *current) {
current->forward = temp;
temp->back = current;
}
// Delete list
bool LinkedList::deleteNode(int id){
bool result = false;
if (idExists(id)) {
Node *current = head;
while (current->forward != NULL && current->data.id != id) {
current = current->forward;
}
if (current->data.id == id && current->forward == NULL) {
if (current->back == NULL) { // Delete head
delete current;
head = NULL;
} else { // delete tail
deleteTail(current);
}
result = true;
} else if (current->data.id == id) {
if (current->back == NULL)
deleteHead(current);
else // delete middle
deleteMiddle(current);
result = true;
}
}
return result;
}
// Helper delete functions
void LinkedList::deleteHead(Node *current) {
head = current->forward;
head->back = NULL;
delete current;
}
void LinkedList::deleteMiddle(Node *current) {
current->back->forward = current->forward;
current->forward->back = current->back;
delete current;
}
void LinkedList::deleteTail(Node *current) {
current->back->forward = NULL;
delete current;
}
bool LinkedList::getNode(int id, Data *data) {
bool didGetNode = false;
if (idExists(id)) {
Node *current = head;
while (current->forward != NULL && current->data.id != id) {
current = current->forward;
}
data->id = current->data.id;
data->data = current->data.data;
didGetNode = true;
}
return didGetNode;
}
// Check whether or not the id exists
bool LinkedList::idExists(int id){
bool exists = false;
if (head != NULL){
Node *current = head;
while (current->forward != NULL && current->data.id != id) {
current = current->forward;
}
if (current->data.id == id) {
exists = true;
}
}
return exists;
}
You probably want to be passing a pointer to a pointer (**) or a pointer to a reference (*&) in functions where you are wanting to make a change to what the address of the node is containing. I hope that this helps you visualize it.
For example:
struct Node { };
void setNull1(Node* temp)
{
temp = nullptr;
}
void setNull2(Node** temp)
{
(*temp) = nullptr;
}
void setNull3(Node*& temp)
{
temp = nullptr;
}
int main()
{
Node* tmp = new Node;
setNull1(tmp);
if (tmp == nullptr)
{
cout << "NULLPTR";
} // tmp is not nullptr
Node* tmp1 = new Node;
setNull2(&tmp1);
if (tmp1 == nullptr)
{
cout << "NULLPTR";
} // tmp1 is nullptr
Node* tmp2 = new Node;
setNull3(tmp2);
if (tmp2 == nullptr)
{
cout << "NULLPTR";
} // tmp2 is nullptr
}
You should also consider writing nullptr instead of NULL.

Seg fault when adding an Edge Node to a Vertex that has no Edges

So first off I know as the title says exactly where my segmentation fault occurs. When I try to add an EdgeNode to a vertex that has no edges to it. I'm bolding the line and if someone could tell me why this is not working.
struct EdgeNode
{
VertexNode* destination;
int weight;
EdgeNode* nextEdge;
};
struct VertexNode
{
string vname;
bool mark;
EdgeNode* edgePtr;
VertexNode* nextVertex;
};
VertexNode* vertices = NULL;
void Graph::AddVertex(string v)
{
VertexNode* newVertexPtr;
VertexNode* tempPtr;
newVertexPtr = new VertexNode;
newVertexPtr->vname = v;
newVertexPtr->nextVertex = NULL;
newVertexPtr->edgePtr = NULL;
tempPtr = vertices;
if ( tempPtr == NULL)
{
vertices = newVertexPtr;
vertices->nextVertex = NULL;
}
else
{
while ( tempPtr->nextVertex != NULL)
{
tempPtr = tempPtr->nextVertex;
}
tempPtr->nextVertex = newVertexPtr;
}
}
void Graph::AddEdge(string s, string d, int w)
{
EdgeNode* newEdgeNodePtr;
EdgeNode* tempEdgePtr;
VertexNode* tempVerticePtr;
VertexNode* dVerticePtr;
tempVerticePtr = vertices;
dVerticePtr = vertices;
try
{
newEdgeNodePtr = new EdgeNode;
delete newEdgeNodePtr;
}
catch(std::bad_alloc)
{
throw GraphFull();
}
newEdgeNodePtr = new EdgeNode;
newEdgeNodePtr->weight = w;
newEdgeNodePtr->nextEdge = NULL;
while(dVerticePtr != NULL)
{
if(dVerticePtr->vname != d)
dVerticePtr = dVerticePtr->nextVertex;
else if(dVerticePtr->vname == d)
{
newEdgeNodePtr->destination = dVerticePtr;
break;
}
}
while(tempVerticePtr != NULL)
{
if(tempVerticePtr->vname != s)
{
tempVerticePtr = tempVerticePtr->nextVertex;
}
if(tempVerticePtr->vname == s)
{
if ( tempVerticePtr->edgePtr == NULL)
{
***//tempVerticePtr->edgePtr = newEdgeNodePtr***;
}
if ( tempVerticePtr->edgePtr != NULL)
{
while ( tempVerticePtr->edgePtr != NULL)
{
tempVerticePtr->edgePtr = tempVerticePtr->edgePtr->nextEdge;
}
tempVerticePtr->edgePtr->nextEdge = newEdgeNodePtr;
}
break;
}
}
}
I have a feeling that the problem that you are having isn't at the specified line of code you have highlighted for us.
The problem is in the following lines of code :
if(tempVerticePtr->vname != s)
{
tempVerticePtr = tempVerticePtr->nextVertex;
}
if(tempVerticePtr->vname == s)
{
if ( tempVerticePtr->edgePtr == NULL)
{
***//tempVerticePtr->edgePtr = newEdgeNodePtr***;
}
...
}
From what I understand, you are iterating through a linked list via the variable tempVerticePtr. In the first if statement, if vname does not equal to your parameter s, you iterate to the next vertex in your linked list (note that the value of tempVerticePtr may be NULL from that point).
The problem arises in the second if statement. In the case of tempVerticePtr being NULL, your if statement will try to check the vname of a NULL pointer, which would most likely break your program.
The fix in this case would be replacing if (...) with else if (...).

Add-Leaf function "hanging", custom BST Class in C++

This problem is a little more complicated than previous ones I've brought here, so I'll try to be very explicit about what I've narrowed it down to.
I'm writing a Binary Search Tree data class in C++ that functions like a standard BST except that it stores duplicates of Odd numbers using a "count" field in the BST node.
I've written a test driver to test the member functions of the class and have run into an error that I cannot seem to solve. When I attempt to add a set number of random integers to a BST object none of them seem to make it into the tree. To check the contents I use a printInOrder function that I have confirmed works properly so I know the problem isn't there.
For starters, I'll post the addLeaf, printInOrder, and createLeaf functions, and the small block of code where I call them in my driver file.
bool fixedDupBST::addLeaf(int key)
{
if(root == nullptr){
root = createLeaf(key);
assert(root != nullptr);
}
else {
node *prev = nullptr;
node *scanPtr = root;
bool right, dupe = false;
while(scanPtr != nullptr) {
prev = scanPtr;
if(key < scanPtr->key) {
scanPtr = scanPtr->left;
right = false;
}
else if (key == scanPtr->key) {
if (scanPtr->keyCount >= 1)
dupe = true;
else{
dupe = false;
scanPtr = nullptr;
}
}
else {
scanPtr = scanPtr->right;
right = true;
}
}
if (dupe)
prev->keyCount++;
else if (!dupe)
return false;
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
}
return true;
}
fixedDupBST::node* fixedDupBST::createLeaf(int key)
{
node* newNode = new node;
assert(newNode != nullptr);
newNode->key = key;
newNode->left = nullptr;
newNode->right = nullptr;
if (key % 2 != 0)
newNode->keyCount = 1;
else
newNode->keyCount = 0;
return newNode;
}
void fixedDupBST::printInOrder()
{
printInOrderPr(root);
}
void fixedDupBST::printInOrderPr(node* Ptr)
{
if(root != nullptr) {
if(Ptr->left != nullptr){
printInOrderPr(Ptr->left);
}
cout << Ptr->key << ' ';
if(Ptr->right != nullptr) {
printInOrderPr(Ptr->right);
}
}
else {
cout << "The tree is empty" << endl;
}
return;
}
void testInsert(fixedDupBST &BST)
{
int temp;
for (int i = 0; i < TEST_PARAM; i++) {
temp = randNum();
BST.addLeaf(temp);
}
BST.printInOrder();
return;
}
The problem I'm getting is that when I call printInOrder() it always gives "The tree is empty". At first I thought it might be a problem with how I was passing parameters in the class member functions (pass by references vs pass by value) but that didn't provide any solutions. If there are any problems at all with the rest of the function it doesn't seem to matter because root never gets assigned to that first node, (hence why print in order just says "the tree is empty".
I need a second set of eyes on this; thanks in advanced for you help, and let me know if I can rephrase my question or provide more information to help make the situation clearer.
EDIT: R Sahu had the error correct, but his answer is a little off. I realized that a bool wouldn't work cleanly for what I was trying to do because there are actually 3 cases:
The number is a duplicate and is odd,
the number is a duplicate and is even
and the number is NOT a duplicate.
The problem stemmed from the fact that the quit condition for the while loop was scanPtr being null, and the if/else-if statement at the end had no way of knowing if it was null because it reached the end of a subtree and was ready to insert, or if I had manually set it to null upon finding a duplicate in order to break the loop appropriately.
Here is the solution I came up with.
bool fixedDupBST::addLeaf(int key)
{
if(root == nullptr){
root = createLeaf(key);
assert(root != nullptr);
}
else {
node *prev = nullptr;
node *scanPtr = root;
bool right;
int dupe = 0; // switch variable
while(scanPtr != nullptr) {
prev = scanPtr;
if(key < scanPtr->key) {
scanPtr = scanPtr->left;
right = false;
}
else if (key == scanPtr->key) {
if (key % 2 != 0) {
dupe = 1;
scanPtr = nullptr;
}
else{
dupe = 2;
scanPtr = nullptr;
}
}
else {
scanPtr = scanPtr->right;
right = true;
}
}
if (dupe == 2)
return false;
if (dupe == 1)
prev->keyCount++;
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
}
return true;
}
Everything works appropriately now.
You have a logic error in this block.
if (dupe)
prev->keyCount++;
else if (!dupe) // This is pointless
// dupe is either true or false.
// Your code will never get to the next "else if"
return false;
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
What you need is:
if (dupe) {
prev->keyCount++;
return false; // I think you want to return false here but I am not sure
}
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
R Sahu had the error correct, but his answer is a little off. I realized that a bool wouldn't work cleanly for what I was trying to do because there are actually 3 cases:
1: The number is a duplicate and is odd.
2: the number is a duplicate and is even.
3: the number is NOT a duplicate.
The problem stemmed from the fact that the quit condition for the while loop was scanPtr being null, and the if/else-if statement at the end had no way of knowing if it was null because it reached the end of a subtree and was ready to insert, or if I had manually set it to null upon finding a duplicate in order to break the loop appropriately.
Here is the solution I came up with.
bool fixedDupBST::addLeaf(int key)
{
if(root == nullptr){
root = createLeaf(key);
assert(root != nullptr);
}
else {
node *prev = nullptr;
node *scanPtr = root;
bool right;
int dupe = 0; // switch variable
while(scanPtr != nullptr) {
prev = scanPtr;
if(key < scanPtr->key) {
scanPtr = scanPtr->left;
right = false;
}
else if (key == scanPtr->key) {
if (key % 2 != 0) {
dupe = 1;
scanPtr = nullptr;
}
else{
dupe = 2;
scanPtr = nullptr;
}
}
else {
scanPtr = scanPtr->right;
right = true;
}
}
if (dupe == 2)
return false;
if (dupe == 1)
prev->keyCount++;
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
}
return true;
}
Everything works appropriately now.

Access violation reading location 0x00000000 in binary search tree

Just showing how the node of the binary tree looks like. I'm not sure what is wrong but I have a feeling it has something to do with the function being private. How I can compare the private data so I can see if the value I am looking for is inside that node?
class binarytree
{
private:
class node
{
public:
int data;
node * left;
node * right;
node (int x)
{
data = x;
left=NULL;
right=NULL;
}
};
node * root;
This is how I insert the node
void insert(int x, node * &r)
{
if(r==NULL)
{
r= new node(x);
}
else
{
if(x < r->data)
{
//insert left
insert(x, r->left);
}
else
{
//insert right
insert(x, r->right);
}
}
}
Here is the part of the code that gives me trouble when I try to compare x to r->data the program crashes and gives me the error message " Access violation reading location 0x00000000"
void remove(int x, node * &r)
{
if(x == r->data)
{
if(r->right == NULL && r->left == NULL)
{
r = NULL;
}
else if(r->right == NULL && r->left != NULL)
{
r = r->left;
}
else if(r->right != NULL && r->left == NULL)
{
r = r->right;
}
else
{
node * temp;
temp =r;
r = r->left;
while(r->right != NULL)
{
r = r->right;
}
r->right = temp->right;
delete temp;
}
}
else if ( x < r->data)
{
remove(x, r->left);
}
else if (x > r->data)
{
remove(x , r->left);
}
}
This is where the functions are publicly. Then I call the private functions so I can manipulate the private tree.
public:
binarytree()
{
root = NULL;
}
~binarytree()
{
//tooo: write this
}
//return true if empty, false if not
bool empty()
{}
void insert(int x)
{
insert(x, root);
}
void remove(int x)
{
remove(x,root);
}
};
EDIT: Here is another function of the program that works but might be causing r to point to NULL.
int extractMin(node * &r)
{
if(r->left == NULL)
{
if(r->right == NULL)
{
return r->data;
}
else
{
int x = r->data;
r = r->right;
return x;
}
}
else
{
return extractMin(r->left);
}
}
Here is the new function to check to see if r is NULL
void remove(int x, node * &r)
{
if(r == NULL)
{
cout<<"why am I null?"<<endl;
}
else
{
if(x == r->data)
{
if(r->right == NULL && r->left == NULL)
{
r = NULL;
}
else if(r->right == NULL && r->left != NULL)
{
r = r->left;
}
else if(r->right != NULL && r->left == NULL)
{
r = r->right;
}
else
{
node * temp;
temp =r;
r = r->left;
while(r->right != NULL)
{
r = r->right;
}
r->right = temp->right;
delete temp;
}
}
else if ( x < r->data)
{
remove(x, r->left);
}
else if (x > r->data)
{
remove(x , r->left);
}
}
}
you should always check for NULL before trying to get to the inner members:
void remove(int x, node * &r)
{
if(r != NULL)
{
// Your code
}
}
you call to remove with r as NULL and then try to check r.Left. then here you have access violation
also i must ask, did any if this worked for you? specifically insert wont work this way.
try
void insert(int x, node * &r)
{
if(r==NULL)
{
r= new node(x);
}
else
{
if(x < r->data)
{
if(r->left != NULL)
{
//insert left
insert(x, r->left);
}
else
{
r->left = new node(x);
}
}
else
{
if(r->right != NULL)
{
//insert right
insert(x, r->right);
}
else
{
r->left = new node(x);
}
}
}
}
r is null somehow. You need to check if the r passed in is NULL, or check if the root is non-null, and call remove on children only if they exist.
Well it the error says, r is pointing to NULL when you try to derefference it.
So you have to make sure when you assign memmory to r it doesn't return NULL.
binarytree()
{
root = NULL;
}
void remove(int x)
{
remove(x,root);
}
In your case you are trying to derefference NULL (as the error says) This happens in your code when you are calling a remove before you have called an insert.
You simply should check at the beginning of remove for r isn't pointing to NULL.
Or even better, make sure you won't parse in r when its NULL.
You are comparing x to the root. When your tree is empty, root == nullptr. You should check to see if r == nullptr first, as in:
bool remove(int x, node * &r) {
if(!r) {
return false; // Indicate whether removal succeeded
}
//... etc.
}