Why is my splay tree not saving any values? - c++
I am just looking for an explanation as to why my tester is saying that my nodes are not being saved. The tester says that inserting is fine, and it tests to see if they are properly lined up. But when it goes back to count the nodes it's saying that only two of them are linked. I've provided what the output is and my code below. I think there is a problem with my rotate function but when I drew a diagram and went step by step it seemed fine. Is it possible that my splay function is wrong? The "Testing tree insertion..." thinks that it's fine so I don't know what to do.
---- Beginning tree tests ----
Testing tree insertion...21 23 27 38 32 33 16 11 26 8 15 6 30 13 0 40 20 3 9 34 14 17 37 18 28 24 2 10 7 35 19 29 25 22 36 39 1 4 12 31 5
FAILED: tree does not have the correct number of nodes. (expected 41, found 2)
--- Tree structure ---
5
├─ 31 [p = 5]
└─(null)
/*
* assign4_test.cc
* Assignment 4 (BST) test runner.
*/
#include <algorithm>
#include <cassert>
#include <iostream>
#include <random>
#include <set>
#include <vector>
using namespace std;
using std::cout;
std::vector<unsigned> make_random_permutation(
std::size_t len,
int seed = 1)
{
std::default_random_engine generator(seed);
std::vector<unsigned> ret(len, 0);
// Initialize vector to 0...len-1
for(std::size_t i = 0; i < len; ++i)
ret.at(i) = i;
std::shuffle(ret.begin(), ret.end(), generator);
return ret;
}
// Node structure
struct node {
int key;
node* left;
node* right;
node* parent;
};
/*
* User-implemented functions
*/
void rotate(node* child, node* parent); // Rotation
bool find(node*& root, int value); // Search
node* insert(node* root, int value); // Insertion
node* insertRec(node*root, int value);
//node* remove(node* root, int value); // Deletion
node* splay(node* t); // Splay
void rotate(node* child, node* parent){
if(parent->left == child){
child->parent = parent->parent;
if(parent->parent != nullptr){
if(child->key < parent->parent->key){
parent->parent->left = child;
}
else
parent->parent->right = child;
}
parent->parent = child;
parent->left = child->right;
if(child->right != nullptr)
child->right->parent = parent;
child->right = parent;
}
else{
child->parent = parent->parent;
if(parent->parent != nullptr){
if(child->key < parent->parent->key){
parent->parent->left = child;
}
else
parent->parent->right = child;
}
parent->parent = child;
parent->right = child->left;
if(child->left != nullptr)
child->left->parent = parent;
child->left = parent;
}
}
node* insertRec(node* root, int value){
node* newNode = new node();
newNode->key = value;
if(root == nullptr)
return newNode;
else if(value < root->key){
root->left = insertRec(root->left, value);
root->left->parent = root;
}
else{
root->right = insertRec(root->right, value);
root->right->parent = root;
}
}
node* insert(node* root, int value){
root = splay(insertRec(root,value));
return root;
}
bool find(node*& root, int value){
node* temp = root;
if(temp == nullptr)
return false;
else if(temp->key == value){
root = splay(temp);
return true;
}
else if(value > temp->key)
return find(temp->right, value);
else
return find(temp->left, value);
}
node* splay(node* t){
while(t->parent != nullptr){
if(t->parent->parent == nullptr)
rotate(t, t->parent);
else{
rotate(t,t->parent);
rotate(t,t->parent);
}
}
return t;
}
/******************************************************************************
Tree structure checking
******************************************************************************/
// Balance measurement, returns a balance factor between 0 (not possible) and 1
// (perfectly balanced).
float balance(node* root) {
if(!root)
return 1.0; // Empty tree is perfectly balanced
else if(!root->left) {
// One subtree, on the right
return 0.5 * balance(root->left);
}
else if(!root->right) {
return 0.5 * balance(root->right);
}
else // Two subtrees
return (balance(root->right) + balance(root->left)) / 2;
}
// Safe find, that does not modify the tree structure
bool safe_find(node* root, int value) {
if(!root)
return false;
else if(root->key == value)
return true;
else if(value < root->key)
return safe_find(root->left, value);
else // value < root->key
return safe_find(root->right, value);
}
int count_nodes(node* root) {
if(!root)
return 0;
else
return 1 + count_nodes(root->left) + count_nodes(root->right);
}
int tree_height(node* root) {
if(!root)
return 0;
else
return 1 + std::max(tree_height(root->left), tree_height(root->right));
}
// Pretty-print a tree. This does cycle-checking at the same time, so that if
// there's a cycle in the tree we won't get stuck in a loop.
void print(node* root, int level, int parents, bool left_child, std::set<node*>& nodes) {
if(level == 0)
cout << "--- Tree structure ---\n";
// Print indent for node
for(int i = 0; i < level-1; ++i)
if(parents & (1 << i))
cout << " │ ";
else
cout << " ";
if(level > 0)
cout << (left_child ? " ├─" : " └─");
if(root == nullptr) {
cout << "(null)" << std::endl;
}
else if(nodes.count(root) > 0) {
// Already printed this node somewhere else
cout << "CYCLE (" << root->key << ")" << std::endl;
}
else {
nodes.insert(root); // Visit root
// Print children
cout.width(3);
cout << root->key;
if(root->parent != nullptr)
cout << " [p = " << root->parent->key << "]";
cout << std::endl;
// Print children
if(root->left || root->right) {
// We only print both children if one of them is non-null.
// If both are null we don't print anything, to avoid making a huge
// mess.
// We print the children in the order right, left so that you can
// turn your head (or your screen) to the left and the tree will
// be correct.
print(root->right, level+1, parents | (1 << level), true, nodes);
print(root->left, level+1, parents, false, nodes);
}
}
}
void print(node* root) {
std::set<node*> nodes;
print(root, 0, 0, true, nodes);
}
/* check_for_cycles(n)
Traverse the tree (preorder) starting at n, checking for cycles of nodes.
Note that this does not check for parent-pointer cycles, only child-pointer
cycles.
*/
bool check_for_cycles(node* n, std::set<node*>& nodes) {
if(nodes.count(n) > 0)
return false;
else {
nodes.insert(n); // Mark n as seen
// Explore left and right subtrees
bool ret = true;
if(n->left)
ret = ret && check_for_cycles(n->left, nodes);
if(n->right)
ret = ret && check_for_cycles(n->right, nodes);
return ret;
}
}
bool check_for_cycles(node* n) {
std::set<node*> nodes;
if(!check_for_cycles(n, nodes)) {
cout << "FAILED: tree structure contains a cycle.\n";
return false;
}
else
return true;
}
// Check the pointer structure of the tree (parent/child) to make sure it is
// correct.
bool check_tree_pointers(node* root, bool is_root = true) {
if(!root)
return true;
else {
if(is_root && root->parent != nullptr) {
cout << "FAILED: root->parent should always be null.\n";
return false;
}
// Child child nodes (if they exist) to make sure their parents
// point back to root.
if(root->left) {
if(root->left->parent != root) {
cout << "FAILED: found node " << root->left->key
<< " with incorrect parent pointer.\n";
return false;
}
if(root->left->key >= root->key) {
cout << "FAILED: found node " << root->left->key
<< " which is on the wrong side of parent.\n";
return false;
}
}
if(root->right) {
if(root->right->parent != root) {
cout << "FAILED: found node " << root->right->key
<< " with incorrect parent pointer.\n";
return false;
}
if(root->right->key <= root->key) {
cout << "FAILED: found node " << root->right->key
<< " which is on the wrong side of parent.\n";
return false;
}
}
if(root->right && root->left) {
// Both children, if they exist, have valid parent pointers.
// So now we check both subtrees recursively.
return check_tree_pointers(root->left, false) &&
check_tree_pointers(root->right, false);
}
return true;
}
}
bool check_tree_values(node* root,
int low = std::numeric_limits<int>::min(),
int high = std::numeric_limits<int>::max()) {
if(!root)
return true;
else if(root->key <= low) {
cout << "FAILED: found node " << root->key << " improperly placed.\n";
return false;
}
else if(root->key >= high) {
cout << "FAILED: found node " << root->key << " improperly placed.\n";
return false;
}
else { // root->key is in the correct range
return check_tree_values(root->left, low, root->key) &&
check_tree_values(root->right, root->key, high);
}
}
bool check_tree(node* root) {
if(root->parent != nullptr) {
cout << "FAILED: Root of tree must have null parent pointer";
cout << " (root->parent->key = " << root->parent->key << ")\n";
return false;
}
return check_for_cycles(root) &&
check_tree_pointers(root) &&
check_tree_values(root);
}
/******************************************************************************
Tree testing
******************************************************************************/
template<typename Func>
struct scope_exit {
scope_exit(Func f) : exit(f)
{}
~scope_exit() {
exit();
}
Func exit;
};
template<typename Func>
scope_exit<Func> make_scope_exit(Func f) {
return scope_exit<Func>(f);
}
// To test the tree functions, we generate a random permutation of the integers
// from -20 to 20 and insert them into the tree. Then, we generate another
// permutation and find them in that order. Finally, we generate another
// permutation and remove them in that order. After every operation, we perform
// a full check of the tree structure. The test stops if the tree structure is
// not valid at any point.
bool test_rotate() {
// This is a huge mess. I need to come up with a better way to test
// left/right rotations. Maybe use member-pointers to abstract over
// the orientation?
// Root of the pseudo-tree
node* root = new node{10000, nullptr, nullptr, nullptr};
/* Left-rotation tree:
p
/ \
c Z
/ \
X Y
*/
node* X = new node{-10, nullptr, nullptr, nullptr};
node* Y = new node{-20, nullptr, nullptr, nullptr};
node* Z = new node{-30, nullptr, nullptr, nullptr};
node* child = new node{2, X, Y, nullptr};
node* parent = new node{1, child, Z, root};
// This is to avoid memory leaks: the function will be called when this
// function returns.
auto exiter = make_scope_exit([&]() {
delete X;
delete Y;
delete Z;
delete child;
delete parent;
});
child->parent = parent;
X->parent = Y->parent = child;
Z->parent = parent;
rotate(child, parent);
/* New structure should be
c
/ \
X p
/ \
Y Z
*/
if(child->parent != root) {
cout << "FAILED: parent's parent is not preserved.\n";
return false;
}
if(child->right != parent) {
cout << "FAILED: rotate did not make parent into child.\n";
return false;
}
if(child->left != X) {
cout << "FAILED: left child of child should be unchanged\n";
return false;
} else if(parent->left != Y) {
cout << "FAILED: child's right child should become right-child of parent.\n";
return false;
} else if(parent->right != Z) {
cout << "FAILED: right child of parent should be unchanged.\n";
return false;
}
else if(parent->parent != child) {
cout << "FAILED: parent->parent is not original child.\n";
return false;
}
else if(!check_for_cycles(child)) {
cout << "FAILED: rotation created a cycle\n";
print(child);
return false;
}
// Right-rotation
delete child; delete parent;
child = new node{2, Y, Z, nullptr};
parent = new node{1, X, child, root};
child->parent = parent;
X->parent = parent;
Y->parent = Z->parent = child;
rotate(child, parent);
if(child->parent != root) {
cout << "FAILED: parent's parent is not preserved.\n";
return false;
}
if(child->left != parent) {
cout << "FAILED: rotate did not make parent into child.\n";
return false;
}
if(parent->left != X) {
cout << "FAILED: left child of parent should be unchanged.\n";
return false;
}
else if(child->right != Z) {
cout << "FAILED: right child of child should be unchanged.\n";
return false;
}
else if(parent->right != Y) {
cout << "FAILED: left child of child should become right child of parent\n";
return false;
}
else if(parent->parent != child) {
cout << "FAILED: parent->parent is not original child.\n";
return false;
}
else if(!check_for_cycles(child)) {
cout << "FAILED: rotation created a cycle\n";
print(child);
return false;
}
// Do a quick test with null children and null root
// If the user made a mistake here, this will most likely segfault.
delete child;
delete parent;
child = new node{1, nullptr, nullptr, nullptr};
parent = new node{0, child, nullptr, nullptr};
child->parent = parent;
rotate(child, parent);
if(parent->parent != child) {
cout << "FAILED: parent did not become the child\n";
return false;
}
else if(child->right != parent) {
cout << "FAILED: parent did not become right child\n";
return false;
}
return true;
}
bool test_tree() {
node* t = nullptr; // Empty tree
// Generate test data
std::vector<unsigned> test = make_random_permutation(41, 12);
// Insert a random permutation
cout << "Testing tree insertion...";
for(unsigned u : test) {
const int i = static_cast<int>(u);
cout << u << " ";
t = insert(t, i);
if(!check_tree(t)) {
print(t);
return false; // Stop if the check fails.
}
if(t->key != i) {
cout << "FAILED: After inserting " << i << " it should be splayed to the root\n";
print(t);
return false;
}
}
cout << std::endl;
int cn = count_nodes(t);
if(cn != 41) {
cout << "FAILED: tree does not have the correct number of nodes. ";
cout << "(expected 41, found " << cn << ")\n";
print(t);
return false;
}
else {
cout << "OK so far...\n";
print(t);
}
// Find a random permutation
cout << "Testing tree find()...";
for(unsigned u : test) {
const int i = static_cast<int>(u);
cout << i << " ";
if(!find(t, i)) {
cout << "FAILED: find() couldn't find " << i << "\n";
return false;
}
if(t->key != i) {
cout << "FAILED: find() did not splay target to the root.\n";
print(t);
return false;
}
if(!check_tree(t)) {
print(t);
return false;
}
}
cout << std::endl;
print(t);
// We no longer test removal, because students are not required to implement
// remove(). It's too fiddly to get right, too many edge cases.
/*
// Remove a random permutation
cout << "Testing tree removal...\n";
for(unsigned u : test) {
const int i = static_cast<int>(u);
t = remove(t, i);
if(!check_tree(t)) {
print(t);
return false;
}
if(safe_find(t,i)) {
cout << "FAILED: removed element " << i << " is still present in the tree\n";
print(t);
return false;
}
}
if(t != nullptr) {
cout << "FAILED: Tree not empty after removing all elements.\n";
print(t);
return false;
}
*/
return true;
}
int main() {
cout << "---- Beginning tree tests ----\n";
if(test_rotate() && test_tree())
cout << "---- All tests successful ----\n";
return 0;
}
Related
Getting segmentation fault when trying to print binary tree nodes in C++ [duplicate]
This question already has answers here: What is a debugger and how can it help me diagnose problems? (2 answers) What is a segmentation fault? (18 answers) Why dereferencing a null pointer is undefined behaviour? (13 answers) Closed 7 months ago. I have an implementation of a binary tree using pointers. I am trying to print its nodes using preorder depth first traversal using recursion. When the program gets to right nodes it says segmentation fault. The problem is that I cannot find the error/mistake in the binary tree implementation. Program works when i use different btree implementation, so I assume the problem is in this btree implementation using pointers. Below is my binary tree implementation #include "../data-structures/trees/binary-tree-pointers/tree.h" using namespace std; void PrintTree(BinaryTree<int> tree, BinaryTree<int>::node node) { cout << tree.Label(node) << endl; if (tree.LeftChild(node) != tree.lambda) PrintTree(tree, tree.LeftChild(node)); if (tree.RightChild(node) != tree.lambda) PrintTree(tree, tree.RightChild(node)); } int main() { BinaryTree<int> tree; BinaryTree<int>::node node; tree.CreateRoot(1); tree.CreateLeftChild(tree.Root(), 2); tree.CreateRightChild(tree.Root(), 3); node = tree.Root(); node = tree.LeftChild(node); tree.CreateLeftChild(node, 4); tree.CreateRightChild(node, 5); node = tree.LeftChild(node); tree.CreateLeftChild(node, 7); node = tree.Root(); node = tree.RightChild(node); tree.CreateRightChild(node, 8); PrintTree(tree, tree.Root()); return 0; } Here is my binary tree implementation: #include <iostream> #include <cstdlib> template <typename nodeType> class BinaryTree { private: struct Tnode { Tnode *parent, *left, *right; nodeType label; }; Tnode *B; public: typedef Tnode* node; const node lambda = NULL; void Del(node n) { if (n->left != NULL) Del(n->left); if (n->right != NULL) Del(n->right); delete n; } void Prnt(node n) { std::cout << n->label << " "; if (n->left != NULL) Prnt(n->left); if (n->right != NULL) Prnt(n->right); } BinaryTree() { B = NULL; } BinaryTree(nodeType x) { B = new Tnode; B->parent = B->left = B->right = NULL; B->label = x; } bool IsEmpty() { return B == lambda; } nodeType Label(node n) { if (n == lambda) { std::cout << "That node doesn't exist!" << std::endl; exit(EXIT_FAILURE); } return n->label; } node Root() { return B; } node Parent(node n) { if (n == lambda) { std::cout << "That node doesn't exist!" << std::endl; exit(EXIT_FAILURE); } return n->parent; } node LeftChild(node n) { if (n == lambda) { std::cout << "That node doesn't exist!" << std::endl; exit(EXIT_FAILURE); } return n->left; } node RightChild(node n) { if (n == lambda) { std::cout << "That node doesn't exist!" << std::endl; exit(EXIT_FAILURE); } return n->right; } void ChangeLabel(node n, nodeType x) { if (n == lambda) { std::cout << "That node doesn't exist!" << std::endl; exit(EXIT_FAILURE); } n->label = x; } void CreateRoot(nodeType x) { if (!this->IsEmpty()) { std::cout << "Can't create root! Tree is not empty!" << std::endl; exit(EXIT_FAILURE); } B = new Tnode; B->parent = B->left = B->right = NULL; B->label = x; } void CreateLeftChild(node n, nodeType x) { if (n == lambda) { std::cout << "That node doesn't exist!" << std::endl; exit(EXIT_FAILURE); } if (n->left != lambda) { std::cout << "Can't create left node! It already exists" << std::endl; exit(EXIT_FAILURE); } Tnode *newNode = new Tnode; newNode->left = newNode->right = NULL; newNode->parent = n; newNode->label = x; n->left = newNode; } void CreateRightChild(node n, nodeType x) { if (n == lambda) { std::cout << "That node doesn't exist!" << std::endl; exit(EXIT_FAILURE); } if (n->right != lambda) { std::cout << "Can't create right node! It already exists" << std::endl; exit(EXIT_FAILURE); } Tnode *newNode = new Tnode; newNode->label = x; newNode->left = newNode->right = NULL; newNode->parent = n; n->right = newNode; } void Delete(node n) { if (n == lambda) { std::cout << "That node doesn't exist!" << std::endl; exit(EXIT_FAILURE); } if (n->parent != NULL) { if (n->parent->left == n) n->parent->left = NULL; else n->parent->right = NULL; Del(n); } else { Del(n); B = NULL; } } void Print() { Prnt(B); std::cout << std::endl; } ~BinaryTree() { if (B != lambda) Del(B); } };
AVL-tree node misses content of an included structure and I cannot find why
Consider the following AVL-tree implementation. Each node contains a list of numbers.The key is named workload, but consider it as a plain double variable. If a key is equal to the key of an already existing node, the number gets pushed into the list. Every time I pop a number from a list, I perform a check, if the node's list is empty -> remove the node. But, after the element with key=3 gets removed completely, the list of the node with key=4 is suddenly empty. I've been trying to solve it for over 10 hours now, it's actually the first time I ever needed to ask something here. Pardon me if I miss a few things. #include<iostream> #include <list> using namespace std; class BST { struct node { double workload; list<int> numbers; node* left; node* right; int height; }; node* root; unsigned long long size; bool empty; void makeEmpty(node* t) { if(t == NULL) return; makeEmpty(t->left); makeEmpty(t->right); delete t; } node* insert(double workload,int number, node* t) { if(t == NULL) { t = new node; t->workload = workload; t->numbers.push_back(number); t->height = 0; t->left = t->right = NULL; } else if(t->workload == workload){ t->numbers.push_back(number); } else if(workload < t->workload) { t->left = insert(workload, number, t->left); if(height(t->left) - height(t->right) == 2) { if(workload < t->left->workload) t = singleRightRotate(t); else t = doubleRightRotate(t); } } else if(workload > t->workload) { t->right = insert(workload, number, t->right); if(height(t->right) - height(t->left) == 2) { if(workload > t->right->workload) t = singleLeftRotate(t); else t = doubleLeftRotate(t); } } //if x == t->workload instead of using int workload. its a list and we push into it. t->height = max(height(t->left), height(t->right))+1; return t; } node* singleRightRotate(node* &t) { node* u = t->left; t->left = u->right; u->right = t; t->height = max(height(t->left), height(t->right))+1; u->height = max(height(u->left), t->height)+1; return u; } node* singleLeftRotate(node* &t) { node* u = t->right; t->right = u->left; u->left = t; t->height = max(height(t->left), height(t->right))+1; u->height = max(height(t->right), t->height)+1 ; return u; } node* doubleLeftRotate(node* &t) { t->right = singleRightRotate(t->right); return singleLeftRotate(t); } node* doubleRightRotate(node* &t) { t->left = singleLeftRotate(t->left); return singleRightRotate(t); } node* findMin(node* t) { if(t == NULL) return NULL; else if(t->left == NULL) return t; else return findMin(t->left); } node* findMax(node* t) { if(t == NULL) return NULL; else if(t->right == NULL) return t; else return findMax(t->right); } node* find(node* t,double workload){ if (t->workload == workload){ return t; } else if(workload < t->workload && t->left!=NULL) return find(t->left,workload); else if(workload > t->workload && t->right!=NULL) return find(t->right,workload); else{ cout << "Null node encountered" << endl; return t; } } node* remove(double x, node* t) { node* temp; // Element not found if(t == NULL) return NULL; // Searching for element if(x < t->workload) t->left = remove(x, t->left); else if(x > t->workload) t->right = remove(x, t->right); // Element found // With 2 children else if(t->left && t->right) { temp = findMin(t->right); t->workload = temp->workload; t->right = remove(t->workload, t->right); } // With one or zero child else { temp = t; if(t->left == NULL) t = t->right; else if(t->right == NULL) t = t->left; delete temp; } if(t == NULL) return t; t->height = max(height(t->left), height(t->right))+1; // If node is unbalanced // If left node is deleted, right case if(height(t->left) - height(t->right) == -2) { // right right case if(height(t->right->right) - height(t->right->left) == 1) return singleLeftRotate(t); // right left case else return doubleLeftRotate(t); } // If right node is deleted, left case else if(height(t->right) - height(t->left) == 2) { // left left case if(height(t->left->left) - height(t->left->right) == 1){ return singleRightRotate(t); } // left right case else return doubleRightRotate(t); } return t; } int height(node* t) { return (t == NULL ? -1 : t->height); } int getBalance(node* t) { if(t == NULL) return 0; else return height(t->left) - height(t->right); } void inorder(node* t) { if(t == NULL) return; inorder(t->left); cout << t->workload<< " "; inorder(t->right); } //Reverse inorder (Sorted highest to lowest) void rinorder(node* t) { if(t == NULL) return; rinorder(t->right); cout << t->workload << " "; rinorder(t->left); } void preorder(node* t) { if (t == NULL) return; cout << t->workload << " "; preorder(t->left); preorder(t->right); } void postorder(node* t) { if (t == NULL) return; postorder(t->left); postorder(t->right); cout << t->workload << " "; } public: BST() { root = NULL; } void insert(double workload, int number) { root = insert(workload, number, root); } void remove(double workload) { root = remove(workload, root); } void displayrin() { cout << "Rinorder: "; rinorder(root); cout << endl; } void displayin() { cout << "Inorder: "; inorder(root); cout << endl; } void displaypost() { cout << "Postorder: "; postorder(root); cout << endl; } void displaypre() { cout << "Preorder: "; preorder(root); cout << endl; } double getMax(){ return findMax(root)->workload; } int getMaxNum(){ return find(root,getMax())->numbers.front(); } int getNum(double workload){ return find(root,workload)->numbers.front(); } //We pop a Num from a node void popnumber(double workload){ node *t = find(root,workload); if(t!=NULL){ if(!t->numbers.empty()){ t->numbers.pop_front(); //If the Num list of the node is empty, remove node if(t->numbers.empty()){ remove(t->workload); } } } } }; int main() { BST t; //key value pairs t.insert(2,1); t.insert(3,1); t.insert(3,2); t.insert(4,7); cout << t.getNum(4) << endl; cout << t.getNum(3)<<endl; t.popnumber(3); cout << t.getNum(3)<<endl; t.popnumber(3); t.displayin(); t.displaypost(); t.displaypre(); t.displayrin(); cout << t.getNum(4) << endl; cout << "The max is : " << t.getMax() << endl; cout << "The top Num of the Max is : " << t.getMaxNum() << endl; return 0; }
As mentioned in the comments, the problem is in the "Element found With 2 children" section of remove. To remove the element, you find the next element in the tree. Your implementation then wants to copy the contents of the found node (temp). You copy the workload value, so that both t and temp have the same workload value (4). You do not copy the numbers list. The t node has a workload of 4 and an empty numbers list, while temp has a workload of 4 and a numbers list consisting of one element, 7. You then delete temp, losing the list. One fix would be to copy (or move) numbers from temp to t before removing it from the tree. Adding a MoveData method to node that would move the data fields (while not altering the tree specific fields) would make it easier to add new data fields. Another fix would be to change how you're doing the data update. If you update all pointers (and other tree related fields like height), then you don't have to worry about the data (and any pointers/iterators to the nodes would not be invalidated).
Insert function recreates root node
I'm trying to create a non-recursive insert() function. The only example I have in the book is a recursive one and I'm trying to convert it. Just so you have an idea of what I'm trying to accomplish and why I'll include the instructions. Write a class for implementing a simple binary search tree capable of storing numbers. The class should have member functions: void insert(double x) bool search(double x) void inorder(vector <double> & v) The insert function should not use recursion directly or indirectly by calling a recursive function. There is more, but I think this gives the idea behind what I'm asking about. As of now the function just keep recreating the root node. Here is what I have. #include "stdafx.h" #include <iostream> #include <vector> class BinaryTree { private: struct TreeNode { double value; TreeNode *left; TreeNode *right; TreeNode(double value1, TreeNode *left1 = nullptr, TreeNode *right1 = nullptr) { value = value1; left = left1; right = right1; } }; TreeNode *root; //pointer to the root of the tree bool search(double x, TreeNode *t) { while (t) { std::cout << "running through t." << std::endl; if (t->value == x) { return true; } else if (x < t->value) { std::cout << "wasn't found, moving left." << std::endl; search(x, t->left); } else { std::cout << "wasn't found, moving right." << std::endl; search(x, t->right); } } std::cout << "wasn't found." << std::endl; return false; } public: std::vector<TreeNode> v; BinaryTree() { root = nullptr; } void insert(double x) { TreeNode *tree = root; if (!tree) { std::cout << "Creating tree." << x << std::endl; root = new TreeNode(x); return; } while (tree) { std::cout << "Adding next value." << std::endl; if (tree->value == x) return; if (x < tree->value) { tree = tree->left; tree->value = x; } else { tree = tree->right; tree->value = x; } } } bool search(double x) { return search(x, root); } /*void inOrder(TreeNode *v) const { while (root != nullptr) { inOrder(root->left); v.push_back(root->value); inOrder(root->right); v.push_back(root->value); } }*/ }; int main() { BinaryTree t; std::cout << "Inserting the numbers 5, 8, 3, 12, and 9." << std::endl; t.insert(5); t.insert(8); t.insert(3); t.insert(12); t.insert(9); std::cout << "Looking for 12 in tree." << std::endl; if (t.search(12)) { std::cout << "12 was found." << std::endl; } std::cout << "Here are the numbers in order." << std::endl; return 0; }
You have to add one more level of dereference if you want your code to work. And of course create the new node at the end of the function. The following code should work: void insert(double x) { TreeNode **tree = &root; while (*tree) { std::cout << "Adding next value." << std::endl; if ((*tree)->value == x) return; if (x < (*tree)->value) { tree = &(*tree)->left; } else { tree = &(*tree)->right; } } if (!(*tree)) { std::cout << "Creating tree." << x << std::endl; *tree = new TreeNode(x); return; } } And your search method should looks like: bool search(double x) { TreeNode *node = root; while (node) { if (node->value == x) { return true; } else if (x < node->value) { node = node->left; } else { node = node->right; } } std::cout << "wasn't found." << std::endl; return false; } Result of your main function, with my code: Inserting the numbers 5, 8, 3, 12, and 9. Creating tree.5 Adding next value. Creating tree.8 Adding next value. Creating tree.3 Adding next value. Adding next value. Creating tree.12 Adding next value. Adding next value. Adding next value. Creating tree.9 Looking for 12 in tree. 12 was found.
How to implement insert function, with no pointer node as a parameter, in binary tree?
tree.h file that implements all the methods. The insert function is in this file. Everything I try requires a the use of a tree pointer node to be passed as a parameter but we cant change the method headers at all for this assignment so Im lost as to how to implement it. Any help is greatly appreciated thanks!! #include "treeNode.h" #include <iomanip> template <class V> class tree { TreeNode<V> * root; 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){ } // 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); } }; treeNode.h file that has declares methods #include #include #include 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; } }; test.cpp file that tests whether or not the methods work #include "tree.h" int main(){ tree<int> myTree; myTree.insert(5); myTree.insert(3); myTree.insert(2); myTree.insert(4); myTree.insert(8); myTree.insert(6); myTree.insert(7); myTree.insert(9); cout << myTree.treeBSearch(9) << endl; cout << myTree.treeBSearch(11) << endl; cout << myTree.nNodes() << endl; cout << "The Tree Looks Like: " << endl; myTree.print(); tree<int> myTree2; myTree2.insert(4); myTree2.insert(2); myTree2.insert(1); myTree2.insert(3); myTree2.insert(7); myTree2.insert(5); // myTree2.print(); }
Still can't find largest number in binary tree
I still can't find the largest number in my tree, but now I am really not complicating it, I think it should work, there is no error, but it just won't show me in the console. Anyone got an idea? I am getting really frustrated. Here is my entire code: #include <iostream> #include <string> #include <cstdlib> using namespace std; template<class T> class BinaryTree { struct Node { T data; Node* lChildptr; Node* rChildptr; Node(T dataNew) { data = dataNew; lChildptr = NULL; rChildptr = NULL; } }; private: Node* root; void Insert(T newData, Node* &theRoot) { if(theRoot == NULL) { theRoot = new Node(newData); return; } if(newData < theRoot->data) Insert(newData, theRoot->lChildptr); else Insert(newData, theRoot->rChildptr);; } void PrintTree(Node* theRoot) { if(theRoot != NULL) { PrintTree(theRoot->lChildptr); cout<< theRoot->data<<" \n";; PrintTree(theRoot->rChildptr); } } T Largest( Node* theRoot) { if ( root == NULL ){ cout<<"There is no tree"; return -1; } if (theRoot->rChildptr != NULL) return Largest(theRoot->rChildptr); else return theRoot->data; cout<<theRoot->data; }; public: BinaryTree() { root = NULL; } void AddItem(T newData) { Insert(newData, root); } void PrintTree() { PrintTree(root); } T Largest() { return Largest(root); } }; int main() { BinaryTree<int> *myBT = new BinaryTree<int>(); myBT->AddItem(2); myBT->AddItem(5); myBT->AddItem(1); myBT->AddItem(10); myBT->AddItem(15); myBT->PrintTree(); myBT->Largest(); } and here is the part that is supposed to find the largest number (the child that is far right down): T Largest( Node* theRoot) { if ( root == NULL ){ cout<<"There is no tree"; return -1; } if (theRoot->rChildptr != NULL) return Largest(theRoot->rChildptr); else return theRoot->data; cout<<theRoot->data; };
There are two problems in your code in Largest(): It looks like you wanted to execute two statements in the else clause, but you didn't use braces. You wanted to execute the cout print after returning, which is impossible. Switch the order around. So you should replace your fragment of code with this: else { cout << theRoot->data; return theRoot->data; } Incidentally, don't let double semicolons (;;) stay in your code. It's harmless in most cases, but it's always bad style.
Here's a fixed and slightly cleaned-up version that works: #include <iostream> #include <string> #include <cstdlib> using namespace std; template<class T> class BinaryTree { struct Node { T data; Node* lChildptr; Node* rChildptr; Node(T dataNew) { data = dataNew; lChildptr = 0; rChildptr = 0; } }; private: Node* root; void Insert(T newData, Node** theRoot) { if (*theRoot == 0) { *theRoot = new Node(newData); } else if (newData < (*theRoot)->data) Insert(newData, &((*theRoot)->lChildptr)); else Insert(newData, &((*theRoot)->rChildptr)); } void PrintTree(Node* theRoot) { if (theRoot != 0) { PrintTree(theRoot->lChildptr); cout << theRoot->data << " " << endl; PrintTree(theRoot->rChildptr); } } T Largest(Node* theRoot) { if (root == 0) { throw "There is no tree"; } if (theRoot->rChildptr != 0) return Largest(theRoot->rChildptr); else return theRoot->data; } public: BinaryTree() { root = 0; } void AddItem(T newData) { Insert(newData, &root); } void PrintTree() { PrintTree(root); } T Largest() { return Largest(root); } }; int main() { BinaryTree<int> *myBT = new BinaryTree<int>(); cout << "The tree is empty. Trying to find the largest element." << endl; try { cout << "Largest element: " << myBT->Largest() << endl; } catch (const char* e) { cout << "Exception caught: " << e << endl; } myBT->AddItem(15); myBT->AddItem(2); myBT->AddItem(5); myBT->AddItem(1); myBT->AddItem(10); cout << "Tree:" << endl; myBT->PrintTree(); cout << "Largest element: " << myBT->Largest() << endl; } Output: The tree is empty. Trying to find the largest element. Exception caught: There is no tree Tree: 1 2 5 10 15 Largest element: 15