C++ - Creating Binary Search Tree Class, one Node disappears after rotate - c++

I am trying to create a custom Binary Search Tree, and I have everything done except for the rotate function, which seems to be not moving a node over. The rotate function only gets called when a node is searched and found, and if the node has a right child. For simplicity I will only add the functions that are used in this, to make it shorter:
#include <iostream>
using namespace std;
template <typename T>
class MRBST {
public:
MRBST();
~MRBST();
void push(const T &);
bool search(const T &);
void PrintPreorder();
private:
struct Node {
T data;
Node *left;
Node *right;
Node (const T & theData, Node *lt, Node *rt)
: data(theData), left(lt), right(rt) {}
};
Node *root;
void push(const T &, Node * &) const;
void remove(const T &, Node * &) const;
Node* findMin(Node *t) const {
if (t == NULL) {
return NULL;
}
if (t->left == NULL) {
return t;
}
return findMin(t->left);
}
void preorder(Node * &);
bool search(const T &, Node *);
Node* findNode(const T & x, Node * t) {
if (t == NULL) {
return NULL;
}
if (x < t->data) {
return findNode(x, t->left);
} else if (x > t->data) {
return findNode(x, t->right);
} else if (x == t->data) {
return t;
}
return NULL;
}
void rotate(Node *);
};
template <typename T>
void MRBST<T>::PrintPreorder() {
preorder(root);
cout << endl;
}
template <typename T>
void MRBST<T>::preorder(Node * & t) {
if (t != NULL) {
cout << t->data << endl;
preorder(t->left);
preorder(t->right);
}
}
template <typename T>
bool MRBST<T>::search(const T & x) {
if (search(x, root)) {
Node *temp = findNode(x, root);
rotate(temp);
return true;
} else {
return false;
}
}
template <typename T>
void MRBST<T>::rotate(Node * k1) {
if (k1->right == NULL) {
return;
} else {
Node *temp = k1->right;
k1->right = temp->left;
temp->left = k1;
}
}
template <typename T>
bool MRBST<T>::search(const T & x, Node *t) {
if (t == NULL) {
return false;
} else if (x < t->data) {
return search(x, t->left);
} else if (x > t->data) {
return search(x, t->right);
} else {
return true;
}
}
I have a simple testing file that just adds some numbers to the tree, and then searches, followed by a print out in Preordering.
#include <iostream>
#include "MRBST.h"
using namespace std;
int main() {
MRBST<int> binaryTree;
binaryTree.push(5);
binaryTree.push(20);
binaryTree.push(3);
binaryTree.push(3);
binaryTree.push(4);
binaryTree.push(22);
binaryTree.push(17);
binaryTree.push(18);
binaryTree.push(8);
binaryTree.push(9);
binaryTree.push(1);
binaryTree.PrintPreorder();
cout << endl;
binaryTree.search(17);
binaryTree.PrintPreorder();
cout << endl;
}
With the output looking a something like this:
5
3
1
4
20
17
8
9
18
22
5
3
1
4
20
17
8
9
22
If anyone could give some insight into what is going wrong with my rotate function, that would be a great help.

Why are you doing rotate on search? It should be read-only.
You're losing the node because of that.
Look at your rotate:
Node *temp = k1->right;
k1->right = temp->left;
temp->left = k1;
Assume k1=x has right=y and left=z, look step by step:
Node *temp = k1->right;
temp =k1->right = y, k1 = x, k1->left = z
k1->right = temp->left;
k1->right = ?, k1->left = z, temp = y
temp->left = k1;
k1->right = ?, k1->left = z, temp->left = x.
Now - where did Y go? You lost it.

Look closely at your rotate() function, step by step, to see whether it does what you want it to do or not.

Related

AVL Tree Nodes (Print)

I'm currently working through AVL trees and am curious why the output (pre order traversal) is only showing two levels of indentation, as if one of the second order nodes is pointing to three separate 3rd level node. I'm note sure if this is an issue with my print function, or the actual code.
#include <iostream>
#include <list>
#include <vector>
#include <iomanip>
using namespace std;
template <class T>
class BST;
template <class T>
class BSTNode{
T data;
BSTNode<T>* parent;
BSTNode<T>* left;
BSTNode<T>* right;
int height;
public:
BSTNode(T data = T(), BSTNode<T>* parent = nullptr, BSTNode<T>* left = nullptr,
BSTNode<T>* right = nullptr, int height = 0) : data(data), parent(parent), left(left), right(right), height(height){}
friend class BST<T>;
int getSize() const;
};
template <class T>
class BST{
public:
BSTNode<T>* root = nullptr;
BST() {}
~BST();
BST(const BST& rhs) {*this = rhs;};
BST& operator=(const BST& rhs);
void printPreOrder(BSTNode<T>* p, int indent);
void insert(T item, BSTNode<T> * & node);
void remove(BSTNode<T>*& temp); //pass pointer by reference because we will be changing the pointer
void clear(BSTNode<T>*& root); //clears the entire tree;
BST<T>* clone(BSTNode<T>* start);
void rotateRight(BSTNode<T> * & node); //rotate the left child (the left child becomes the parent and parent becomes the right child)
void rotateLeft(BSTNode<T> * & node); //rotate the right child (the right child becomes the parent and the parent becomes the left child)
void doubleRotateRight(BSTNode<T> *& node); //same result as rotate right
void doubleRotateLeft(BSTNode<T> *& node); //same result as rotate left
int height(BSTNode<T> * node); //return height
void balance(BSTNode<T> * &node);
};
template <class T>
int BSTNode<T>::getSize() const {
int count = 1;
if(left != nullptr){
count += left->getSize();
};
if(right != nullptr){
count += right->getSize();
};
return count;
}
template <class T>
void BST<T>::printPreOrder(BSTNode<T>* p, int indent){
if(p) {
if (indent) {
std::cout << std::setw(indent) << '\t';
}
cout<< p->data << "\n ";
if(p->left) printPreOrder(p->left, indent+2);
if(p->right) printPreOrder(p->right, indent+2);
}
}
template <class T>
void BST<T>::insert(T item, BSTNode<T> * & node){
if(!node){
node = new BSTNode<T>(item);
}
else if(item < node->data){
insert(item, node->left);
}
else{
insert(item, node->right);
}
balance(node);
}
template <class T>
void BST<T>::remove(BSTNode<T>*& temp){
if(temp->left == nullptr && temp->right == nullptr){
if(temp->parent == nullptr){
root = nullptr;
}
else if(temp->parent->left == temp){
temp->parent->left = nullptr;
}
else{
temp->parent->right = nullptr;
}
delete temp;
}
else if(temp->left == nullptr){ //promote right
BSTNode<T>* toDelete = temp->right;
temp->data = toDelete->data;
temp->left = toDelete->left;
temp->right = toDelete->right;
if(temp->left){
temp->left->parent = temp->left;
}
if(temp->right){
temp->right->parent = temp;
}
delete toDelete;
}
else if(temp->right == nullptr){ //promote left
BSTNode<T>* toDelete = temp->left;
temp->data = toDelete->data;
temp->left = toDelete->left;
temp->right = toDelete->right;
if(temp->left){
temp->left->parent = temp->left;
}
if(temp->right){
temp->right->parent = temp;
}
delete toDelete;
}
else{
BSTNode<T>* maxOfLeft = temp->left;
while(maxOfLeft){
maxOfLeft = maxOfLeft->right;
}
temp->data = maxOfLeft->data;
remove(maxOfLeft);
}
balance(temp);
}
template <class T>
void BST<T>::clear(BSTNode<T>*& root) {
if (root) {
if (root->left) {
clear(root->left);
}
if (root->right) {
clear(root->right);
}
delete root;
}
root = nullptr;
};
template <class T>
BST<T>::~BST(){
clear(root);
}
template <class T>
BST<T>* BST<T>::clone(BSTNode<T>* start){
if(!start){
return nullptr;
}
else{
return new BSTNode<T>(start->data, clone(start->left), clone(start->right));
}
}
template <class T>
BST<T>& BST<T>::operator=(const BST<T>& rhs){
if(this == &rhs){
return *this;
}
clear(root);
root = clone(rhs.root);
return *this;
}
template <class T>
void BST<T>::rotateRight(BSTNode<T> * & node){
BSTNode<T> * newParent = node->left;
node->left = newParent->right;
newParent->right = node;
node->height = max(height(node->right),height(node->left)) + 1;
newParent->height = max(height(newParent->left), node->height) + 1;
node = newParent; //set new root (we can't access newParent outside of this function!)
}
template <class T>
void BST<T>::rotateLeft(BSTNode<T> * & node){
BSTNode<T> * newParent = node->right;
node->right = newParent->left;
newParent->left = node;
node->height = max(height(node->right), height(node->left)) + 1;
newParent->height = max(height(newParent->right), node->height) + 1;
node = newParent; //set new root (we can't access newParent outside of this function!)
}
template <class T>
int BST<T>::height(BSTNode<T> *node){
if(node){
return node->height;
};
return -1;
}
template <class T>
void BST<T>::doubleRotateRight(BSTNode<T> * &node){
rotateLeft(node->left);
rotateRight(node);
}
template<class T>
void BST<T>::doubleRotateLeft(BSTNode<T> * &node){
rotateRight(node->right);
rotateLeft(node);
}
template<class T>
void BST<T>::balance(BSTNode<T> * &node){
if(!node){
return;
}
if(height(node->left) > height(node->right) + 1){
if(height(node->left->left) >= height(node->left->right)){
rotateRight(node);
}
else{
doubleRotateRight(node);
};
};
if(height(node->right) > height(node->left) + 1){
if(height(node->right->right) >= height(node->right->left)){
rotateLeft(node);
}
else{
doubleRotateLeft(node);
}
}
node->height = max(height(node->right), height(node->left)) + 1;
}
int main() {
vector<int>data = {5, 3, 4, 2, 1, 2, 6, 7};
BST<int> test;
for(int r : data){
test.insert(r, test.root);
}
test.printPreOrder(test.root,0);
cout << endl;
return 0;
}
Here is the output I am getting:
3
2
1
2
5
4
6
7
From my understanding, I should be getting the following output:
3
2
1
2
5
4
6
7
Don't use tabs.
Consider this example:
#include <iostream>
#include <iomanip>
int main() {
for (int indent=0;indent<5;++indent) {
if (indent) {
std::cout << std::setw(indent) << "\t" << "tabs" << "\n";
std::cout << std::setw(indent) << " " << "spaces" << "\n";
}
}
}
Possible output is:
tabs
spaces
tabs
spaces
tabs
spaces
tabs
spaces

Outputing number of leaf nodes in a Binary Search Tree

Im trying to figure out how to calculate the number of leaf nodes in a binary search tree.
I keep getting a run-time error and CodeBlocks keeps crashing at the final return statement. I've seen multiple examples on here and I still can't seem to understand where I'm going wrong.
I'm trying to do this recursively however as i stated previously as soon as i add the function number_of_leaves(p -> left)+ number_of_leaves(p-> right)
CodeBlocks stops working after it prints out:
Empty tree has 0 leaf nodes. Answer:0
Single node has 1 leaf node. Answer 1
Crashes here
.
#include <queue>
#include <stack>
#include <iostream>
#include <vector>
#include <stdlib.h>
#ifndef BINARY_SEARCH_TREE
#define BINARY_SEARCH_TREE
template<class T>
class Stack: public std::stack<T> {
public:
T pop() { T tmp = std::stack<T>::top(); std::stack<T>::pop(); return tmp; }
};
template<class T>
class Queue: public std::queue<T> {
public:
T dequeue() { T tmp = std::queue<T>::front(); std::queue<T>::pop(); return tmp; }
void enqueue(const T& el) { push(el); }
};
template<class T>
class BSTNode {
public:
BSTNode() { left = right = 0; }
BSTNode(const T& e, BSTNode<T> *l = 0, BSTNode<T> *r = 0)
{ el = e, left = l, right = r; }
T el;
BSTNode<T> *left, *right;
};
template<class T>
class BST {
public:
BST() { root = 0; }
~BST() { clear(); }
void clear() { clear(root), root = 0; }
bool is_empty() const { return root == 0; }
void preorder() { preorder(root); }
void inorder() { inorder(root); }
void postorder() { postorder(root); }
void insert(const T&);
T* search(const T& el) const { return search(root, el); }
void find_and_delete_by_copying(const T&);
void find_and_delete_by_merging(const T&);
void breadth_first();
void balance(std::vector<T>, int, int);
bool is_perfectly_balanced() const { return is_perfectly_balanced(root) >= 0; }
int number_of_leaves() const { return number_of_leaves(root); }
T* recursive_search(const T& el) const { return recursive_search(root, el); }
void recursive_insert(const T& el) { recursive_insert(root, el); }
protected:
void clear(BSTNode<T>*);
T* search(BSTNode<T>*, const T&) const;
void preorder(BSTNode<T>*);
void inorder(BSTNode<T>*);
void postorder(BSTNode<T>*);
virtual void visit(BSTNode<T>* p) // virtual allows re-definition in derived classes
{ std::cout << p->el << " "; }
void delete_by_copying(BSTNode<T>*&);
void delete_by_merging(BSTNode<T>*&);
int is_perfectly_balanced(BSTNode<T>*) const; // To be provided (A4)
int number_of_leaves(BSTNode<T>*) const; // To be provided (A4)
void recursive_insert(BSTNode<T>*&, const T&); // To be provided (P6)
T* recursive_search(BSTNode<T>*, const T&) const; // To be provided (P6)
BSTNode<T>* root;
};
#endif
template<class T>
void BST<T>::clear(BSTNode<T> *p)
{
if (p != 0) {
clear(p->left);
clear(p->right);
delete p;
}
}
template<class T>
void BST<T>::insert(const T& el)
{
BSTNode<T> *p = root, *prev = 0;
while (p != 0) { // find a place for inserting new node;
prev = p;
if (el < p->el)
p = p->left;
else
p = p->right;
}
if (root == 0) // tree is empty;
root = new BSTNode<T>(el);
else if (el < prev->el)
prev->left = new BSTNode<T>(el);
else
prev->right = new BSTNode<T>(el);
}
template<class T>
T* BST<T>::search(BSTNode<T>* p, const T& el) const
{
while (p != 0) {
if (el == p->el)
return &p->el;
else if (el < p->el)
p = p->left;
else
p = p->right;
}
return 0;
}
template<class T>
void BST<T>::inorder(BSTNode<T> *p)
{
if (p != 0) {
inorder(p->left);
visit(p);
inorder(p->right);
}
}
template<class T>
void BST<T>::preorder(BSTNode<T> *p)
{
if (p != 0) {
visit(p);
preorder(p->left);
preorder(p->right);
}
}
template<class T>
void BST<T>::postorder(BSTNode<T>* p)
{
if (p != 0) {
postorder(p->left);
postorder(p->right);
visit(p);
}
}
template<class T>
void BST<T>::delete_by_copying(BSTNode<T>*& node)
{
BSTNode<T> *previous, *tmp = node;
if (node->right == 0) // node has no right child;
node = node->left;
else if (node->left == 0) // node has no left child;
node = node->right;
else {
tmp = node->left; // node has both children;
previous = node; // 1.
while (tmp->right != 0) { // 2.
previous = tmp;
tmp = tmp->right;
}
node->el = tmp->el; // 3.
if (previous == node)
previous->left = tmp->left;
else
previous->right = tmp->left; // 4.
}
delete tmp; // 5.
}
// find_and_delete_by_copying() searches the tree to locate the node containing
// el. If the node is located, the function delete_by_copying() is called.
template<class T>
void BST<T>::find_and_delete_by_copying(const T& el)
{
BSTNode<T> *p = root, *prev = 0;
while (p != 0 && !(p->el == el)) {
prev = p;
if (el < p->el)
p = p->left;
else p = p->right;
}
if (p != 0 && p->el == el) {
if (p == root)
delete_by_copying(root);
else if (prev->left == p)
delete_by_copying(prev->left);
else
delete_by_copying(prev->right);
}
else if (root != 0)
std::cout << "el " << el << " is not in the tree" << std::endl;
else
std::cout << "the tree is empty" << std::endl;
}
template<class T>
void BST<T>::delete_by_merging(BSTNode<T>*& node)
{
BSTNode<T> *tmp = node;
if (node != 0) {
if (!node->right) // node has no right child: its left
node = node->left; // child (if any) is attached to its parent;
else if (node->left == 0) // node has no left child: its right
node = node->right; // child is attached to its parent;
else { // be ready for merging subtrees;
tmp = node->left; // 1. move left
while (tmp->right != 0) // 2. and then right as far as possible;
tmp = tmp->right;
tmp->right = // 3. establish the link between the
node->right; // the rightmost node of the left
// subtree and the right subtree;
tmp = node; // 4.
node = node->left; // 5.
}
delete tmp; // 6.
}
}
template<class T>
void BST<T>::find_and_delete_by_merging(const T& el)
{
BSTNode<T> *node = root, *prev = 0;
while (node != 0) {
if (node->el == el)
break;
prev = node;
if (el < node->el)
node = node->left;
else
node = node->right;
}
if (node != 0 && node->el == el) {
if (node == root)
delete_by_merging(root);
else if (prev->left == node)
delete_by_merging(prev->left);
else
delete_by_merging(prev->right);
}
else if (root != 0)
std::cout << "el " << el << " is not in the tree" << std::endl;
else
std::cout << "the tree is empty" << std::endl;
}
template<class T>
void BST<T>::breadth_first()
{
Queue<BSTNode<T>*> queue;
BSTNode<T> *p = root;
if (p != 0) {
queue.enqueue(p);
while (!queue.empty())
{
p = queue.dequeue();
visit(p);
if (p->left != 0)
queue.enqueue(p->left);
if (p->right != 0)
queue.enqueue(p->right);
}
}
}
template<class T>
void BST<T>::balance (std::vector<T> data, int first, int last)
{
if (first <= last) {
int middle = (first + last)/2;
insert(data[middle]);
balance(data,first,middle-1);
balance(data,middle+1,last);
}
}
template<class T>
void BST<T>::recursive_insert(BSTNode<T>*& p, const T& el)
{
if (p == 0) // Anchor case, tail recursion
p = new BSTNode<T>(el);
else if (el < p->el)
recursive_insert(p->left, el);
else
recursive_insert(p->right, el);
}
template<class T>
T* BST<T>::recursive_search(BSTNode<T>* p, const T& el) const
{
if (p != 0) {
if (el == p->el) // Anchor case, tail recursion
return &p->el;
else if (el < p->el)
return recursive_search(p->left, el);
else
return recursive_search(p->right, el);
}
else
return 0;
}
Problem is here***
I've tryed having a seperate counter to count the nodes, but it just prints all 0s. As soon as i add in the number_of_leaves() it crashes
template<class T>
int BST<T>::number_of_leaves(BSTNode<T>*) const {
BSTNode<T> *p = root;
if(p == NULL){
return 0;
}
if(p->left == NULL && p->right==NULL){
return 1;
}
else
return number_of_leaves(p->left) + number_of_leaves(p-> right);
}
Testing file below:
#include "BST.h"
#include <iostream>
using namespace std;
int main()
{
BST<int> a;
cout << "Empty tree has 0 leaf nodes. Answer: " << a.number_of_leaves() << endl;
a.insert(4);
cout << "Single node has 1 leaf node. Answer: " << a.number_of_leaves() << endl;
a.insert(2);
cout << "Linked list of 2 nodes has 1 leaf node. Answer: "
<< a.number_of_leaves() << endl;
a.insert(6);
cout << "Full binary tree of 3 nodes has 2 leaf nodes. Answer: "
<< a.number_of_leaves() << endl;
a.insert(3), a.insert(1), a.insert(5), a.insert(7);
cout << "Full binary tree of 7 nodes has 4 leaf nodes. Answer: "
<< a.number_of_leaves() << endl;
return 0;
}
In number_of_leaves(BSTNode<T>*), you discard the passed argument and always start from root. You then go down recursively and always do precisely the same operations, which leads to StackOverflow (sorry, I couldn't resist :p). You reach the maximum number of function calls and program is terminated.
template<class T>
int BST<T>::number_of_leaves(BSTNode<T>* start) const
{
if(start == NULL)
{
return 0;
}
if(start->left == NULL && start->right==NULL)
{
return 1;
}
return number_of_leaves(start->left) + number_of_leaves(start-> right);
}

Faulty avltree implementation c++

this is my current avltree implementation, avltree.h:
#pragma once
#include <math.h>
#include <algorithm>
#include <iostream>
namespace avltree {
template <class T>
struct node {
static node * null_node;
node *left = null_node;
node *right = null_node;
node *parent = null_node;
int height = 0;
T value;
node(T value) :value(value) {}
node(T value, int height) :height(height), value(value) {}
};
template <class T>
node<T>* node<T>::null_node = new node(0, -1);
template <class T>
struct avltree {
public:
node<T> *root;
avltree(T value);
node<T> *insert(T value);
void print(void);
void print_with_height(void);
private:
node<T> *insert(T value, node<T> *x);
node<T> *left_rotate(node<T> *x);
node<T> *right_rotate(node<T> *x);
void retrace(node<T> *n);
void update_root();
void print(node<T> *n);
void print(node<T> *n, int depth);
void update_height(node<T> *n);
};
template <class T>
avltree<T>::avltree(T value) :root(new node<T>(value)) { }
template <class T>
node<T> *avltree<T>::insert(T value) {
auto n = insert(value, root);
update_root();
return n;
}
template <class T>
void avltree<T>::retrace(node<T> *n) {
while (n != node<T>::null_node) {
update_height(n);
if (n->left->height - n->right->height > 1) {
if (n->left->left->height >= n->left->right->height) {
right_rotate(n);
}
else {
left_rotate(n);
right_rotate(n);
}
}
else
if (n->right->height - n->left->height > 1) {
if (n->right->right->height >= n->right->left->height) {
left_rotate(n);
}
else {
right_rotate(n);
left_rotate(n);
}
}
n = n->parent;
}
}
template <class T>
node<T> *avltree<T>::insert(T value, node<T> *n) {
if (n->value > value) {
if (n->left != node<T>::null_node) {
n->left->height++;
insert(value, n->left);
}
else {
auto new_node = new node<T>(value);
n->left = new_node;
new_node->parent = n;
retrace(n);
return new_node;
}
}
if (n->value < value) {
if (n->right != node<T>::null_node) {
n->right->height++;
insert(value, n->right);
}
else {
auto new_node = new node<T>(value);
n->right = new_node;
new_node->parent = n;
retrace(n);
return new_node;
}
}
update_height(n);
return n;
}
template <class T>
node<T> *avltree<T>::left_rotate(node<T> *x) {
node<T> *y = x->right;
if (y == node<T>::null_node) {
return node<T>::null_node;
}
y->parent = x->parent;
if (x->parent->right == x) {
x->parent->right = y;
}
else {
x->parent->left = y;
}
y->left = x;
x->parent = y;
x->right = y->left;
x->right->parent = x;
update_height(x);
update_height(y);
return x;
}
template <class T>
node<T> *avltree<T>::right_rotate(node<T> *x) {
node<T> *y = x->left;
if (y == node<T>::null_node) {
return node<T>::null_node;
}
y->parent = x->parent;
if (x->parent->right == x) {
x->parent->right = y;
}
else {
x->parent->left = y;
}
y->right = x;
x->parent = y;
x->left = y->right;
x->left->parent = x;
update_height(x);
update_height(y);
return x;
}
template <class T>
void avltree<T>::update_root() {
auto n = root, last = root;
while (n != node<T>::null_node) {
last = n;
n = n->parent;
}
root = last;
}
template <class T>
void avltree<T>::print(void) {
print(root);
cout << endl;
}
template <class T>
void avltree<T>::print(node<T> *n) {
if (n->left != node<T>::null_node) {
print(n->left);
}
cout << n->value << " ";
if (n->right != node<T>::null_node) {
print(n->right);
}
}
template <class T>
void avltree<T>::print(node<T> *n, int height) {
if (n->left != node<T>::null_node) {
print(n->left, height);
}
if (n->height == height) {
std::cout << n->value << ", ";
}
if (n->right != node<T>::null_node) {
print(n->right, height);
}
}
template <class T>
void avltree<T>::print_with_height(void) {
int height = root->height;
for (int height = root->height; height >= 0; height--) {
std::cout << "height = " << height << "\t:";
print(root, height);
std::cout << std::endl;
}
std::cout << std::endl;
}
template <class T>
void avltree<T>::update_height(node<T> *n) {
n->height = std::max(n->left->height, n->right->height) + 1;
}
}
And the following is main file:
#include "stdafx.h"
#include "avltree.h"
int main()
{
avltree::avltree<int> tree(1);
for (int i = 2; i < 128; i++) {
tree.insert(i);
}
tree.print_with_height();
return 0;
}
The problem with above code is that at iteration 124 it will generate an infinite loop inside retrace call in insert. Basically, the nodes will keep being rotated in such a way that root node cannot be reached (resulting in an infinite loop). I have checked the trivial examples (for a few nodes) and they work. Everything for a run is provided, I would appreciate if someone with experience in avltrees could take their time and run this program, perhaps finding out what goes wrong inside retrace/rotations.
Getting an infinite loop like that indicates a likely problem with your rotate functions. A quick look at left_rotate shows
y->left = x;
x->parent = y;
x->right = y->left;
What is y->left in that last assignment? x, so what you're really is x->right = x. This is clearly a problem that needs to be fixed.
A similar problem exists in right_rotate.

c++ access violation with classes [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Hi I am getting an access violation reading error in my linked list header file. The project takes a binary tree and turns it into an ordered linked list. the binary tree header:
#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H
#include "dsexceptions.h"
#include "LinkedList.h"
#include <iostream>
using namespace std;
template <typename Comparable>
class BinarySearchTree
{
public:
BinarySearchTree( ) :root( NULL )
{ }
BinarySearchTree(const BinarySearchTree & rhs) : root(NULL)
{ *this = rhs; }
~BinarySearchTree( )
{ makeEmpty( ); }
const Comparable & findMin( ) const
{
if (isEmpty( ))
throw UnderflowException( );
return findMin(root)->element;
}
const Comparable & findMax( ) const
{
if(isEmpty( ))
throw UnderflowException( );
return findMax( root )->element;
}
bool contains(const Comparable & x) const
{ return contains(x, root); }
bool isEmpty( ) const
{ return root == NULL; }
void printTree(ostream & out = cout)
{
if (isEmpty( ))
out << "Empty tree" << endl;
else
printTree(root, out);
}
void makeEmpty( )
{ makeEmpty(root); }
void insert(const Comparable & x)
{ insert(x, root); }
void remove(const Comparable & x)
{ remove(x, root); }
const BinarySearchTree & operator=(const BinarySearchTree & rhs)
{
if (this != &rhs)
{
makeEmpty( );
root = clone(rhs.root);
}
return *this;
}
void toList(linkedlist l)
{ toList(l, root); }
private:
struct BinaryNode
{
Comparable element;
BinaryNode *left;
BinaryNode *right;
BinaryNode(const Comparable & theElement, BinaryNode *lt, BinaryNode *rt)
: element(theElement), left(lt), right(rt) { }
};
BinaryNode *root;
void toList(linkedlist l, BinaryNode *&t)
{
if(t==NULL)
{ return; }
toList(l,t->left);
l.add(t->element);
toList(l,t->right);
}
void printTree(BinaryNode *&t, ostream & out = cout)
{
if(t==NULL)
{ return; }
printTree(t->left,out);
cout << t->element << endl;
printTree(t->right,out);
}
void insert(const Comparable & x, BinaryNode * & t)
{
if (t == NULL)
t = new BinaryNode(x, NULL, NULL);
else if (x < t->element)
insert(x, t->left);
else if (t->element < x)
insert(x, t->right);
else; // Duplicate; do nothing
}
void remove(const Comparable & x, BinaryNode * & t)
{
if (t == NULL)
return; // Item not found; do nothing
if (x < t->element)
remove(x, t->left);
else if (t->element < x)
remove(x, t->right);
else if (t->left != NULL && t->right != NULL) // Two children
{
t->element = findMin(t->right)->element;
remove(t->element, t->right);
}
else
{
BinaryNode *oldNode = t;
t = (t->left != NULL) ? t->left : t->right;
delete oldNode;
}
}
BinaryNode * findMin(BinaryNode *t) const
{
if (t == NULL)
return NULL;
if (t->left == NULL)
return t;
return findMin(t->left);
}
BinaryNode * findMax(BinaryNode *t) const
{
if (t != NULL)
while (t->right != NULL)
t = t->right;
return t;
}
bool contains(const Comparable & x, BinaryNode *t) const
{
if (t == NULL)
return false;
else if (x < t->element)
return contains(x, t->left);
else if (t->element < x)
return contains(x, t->right);
else
return true; // Match
}
void makeEmpty(BinaryNode * & t)
{
if (t != NULL)
{
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
}
t = NULL;
}
BinaryNode * clone(BinaryNode *t) const
{
if (t == NULL)
return NULL;
else
return new BinaryNode(t->element, clone(t->left), clone(t->right));
}
};
#endif
the linked list header:
#ifndef LINKED_LIST_H
#define LINKED_LIST_H
#include <iostream>
using namespace std;
class linkedlist
{
private:
struct lNode{
int data;
lNode *next;
};
struct lNode *head;
public:
linkedlist()
{ struct lNode *head = new lNode;
head->next = NULL;
}
void add(int n) {
lNode *newlNode = new lNode;
newlNode->data = n;
newlNode->next = NULL;
lNode *cur = head;
while(true) {
if(cur->next == NULL)
{
cur->next = newlNode;
break;
}
cur = cur->next;
}
}
void display() {
lNode *list = head;
while(true)
{
if (list->next == NULL)
{
cout << list->data << endl;
break;
}
cout << list->data << endl;
list = list->next;
}
cout << "done" << endl;
}
};
#endif
the main cpp file:
#include <iostream>
#include "BinarySearchTree.h"
#include "LinkedList.h"
using namespace std;
int main( )
{
BinarySearchTree<int> t;
linkedlist l;
int i;
cout << "inserting nodes into tree" << endl;
t.insert(50);
t.insert(60);
t.insert(30);
t.insert(20);
t.insert(40);
t.insert(70);
t.insert(55);
t.insert(65);
t.insert(25);
t.insert(35);
t.insert(85);
t.insert(100);
t.insert(15);
t.insert(45);
t.insert(95);
t.insert(105);
t.insert(10);
t.insert(75);
t.insert(110);
t.insert(12);
t.insert(92);
t.insert(32);
t.insert(82);
t.insert(22);
t.insert(32);
t.printTree( );
t.toList(l);
cout << "Finished processing" << endl;
l.display();
return 0;
}
The location of the error is in the linked list header file here: if(cur->next == NULL). I do not see how it could be an access error as everything is contained inside that class.
In the code above you have this section of code:
struct lNode *head;
public:
linkedlist()
{ struct lNode *head = new lNode;
head->next = NULL;
}
That code is defining two instances of the head node which I'm sure is not what you want.
The ctor should be something more like this:
linkedlist()
{
head = new lNode;
head->next = NULL;
}
Your code does not test for the empty list -- that is where there are no elements in the list and the head is NULL.
Also, you are missing any constructors which is initializing the class, so it may very well be that head has an undefined value -- also there add method make not use of the loop, or make any recording of the added elements...
So in short, there are a lot of programming issues to fix.

How to compare strings that are passed as a template class?

I have a data structure that uses a template class such that it can store any data type - ints, floats, strings, etc.
Because the data will be organized, I need a way to compare two values. Usually I can use > or <, but in the case of strings that will not work because using the >/< operators on a string won't tell me which comes first alphabetically. For that, I need to use the compare() function.
However since the data structure is a template class, I can't tell it to use the compare() function because it won't recognize the compare() function for anything BUT a string.
As a work-around, I tried writing two compare functions:
template (class t)
int BinaryTree<T>::compareVals(T v1, T v2);
and
template (class t)
int BinaryTree<T>::compareVals(string v1, string v2);
So that in the case of the value being a string type, the program would use the method with the compare() function in it.
However trying to do that, I am getting a compiler error basically telling me I can't overload the function.
So I'm out of ideas. How can I make this template class correctly compare and sort strings as well as numbers?
Thank you very much for your input!
Here is the entire class, for reference:
#ifndef binarytree_class
#define binarytree_class
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::string;
using std::vector;
template <class T>
class BinaryTree{
public:
struct TreeNode{
TreeNode * leftChild,
* rightChild;
T key;
vector<T> data;
int size;
};
BinaryTree();
~BinaryTree();
bool isEmpty();
int getSize();
void add(T key, T data);
void remove(T key);
int getHeight();
bool keyExists(T key);
int getKeyHeight(T key);
void displayAll();
private:
int size;
TreeNode * root;
TreeNode * findParent(TreeNode * start, TreeNode * child); //finds the parent node of child in subtree starting at root start
TreeNode * findNode(TreeNode * node, T input); //find node with data input in subtree at root node
TreeNode * findMin(TreeNode * node);
void removeNode(TreeNode * node); //Small part of algorithm (case: 2 children) borrowed from tech-faq.com/binary-tree-deleting-a-node.html
void displaySubTree(TreeNode * node); //displays subtree starting at node
void sortAdd(TreeNode * eNode, TreeNode * nNode); //adds a new node nNode to subtree starting at root eNode
void destroySubTree(TreeNode * node); //destroys subtree starting at node.
void display(TreeNode * node, string indent, bool last); //Algorithm borrowed from http://stackoverflow.com/questions/1649027/how-do-i-print-out-a-tree-structure
char leftOrRight(TreeNode * eNode, TreeNode * nNode); //compares keys in existing node vs new node and returns L or R
int calcHeight(TreeNode * node, int depth); //calculates the height from node. Algorithm borrowed from wiki.answers.com
int compareVals(T v1, T v2);
int compareVals(string v1, string v2);
};
template <class T>
BinaryTree<T>::BinaryTree<T>() : size(0){}
template <class T>
bool BinaryTree<T>::isEmpty(){
return (!size);
}
template <class T>
int BinaryTree<T>::compareVals(T v1, T v2){
int result;
v1 <= v2? result = -1 : result = 1;
return result;
}
template <class T>
int BinaryTree<T>::compareVals(string v1, string v2){
int result;
result = v1.compare(v2);
if(result >= 0)
result = -1;
else
result = 1;
return result;
}
template <class T>
int BinaryTree<T>::getSize(){
return size;
}
template <class T>
void BinaryTree<T>::add(T key, T data){
bool done = false;
TreeNode * temp;
if(keyExists(key)){
temp = findNode(root,key);
temp->size++;
temp->data.push_back(key);
}
else{
temp = new TreeNode;
temp->leftChild = 0;
temp->rightChild = 0;
temp->key = key;
temp->size = 0;
temp->data.push_back(data);
if(isEmpty())
root = temp;
else
sortAdd(root, temp);
size++;
}
}
template <class T>
void BinaryTree<T>::sortAdd(TreeNode * eNode, TreeNode * nNode){
if(leftOrRight(eNode, nNode) == 'L'){
if(eNode->leftChild == 0)
eNode->leftChild = nNode;
else
sortAdd(eNode->leftChild,nNode);
} else {
if(eNode->rightChild == 0)
eNode->rightChild = nNode;
else
sortAdd(eNode->rightChild,nNode);
}
}
template <class T>
char BinaryTree<T>::leftOrRight(TreeNode * eNode, TreeNode * nNode){
char result;
if(compareVals(nNode->key, eNode->key) == -1)
result = 'L';
else
result = 'R';
return result;
}
template <class T>
void BinaryTree<T>::displayAll(){
display(root,"",true);
}
template <class T>
void BinaryTree<T>::display(TreeNode * node, string indent, bool last){
if(!isEmpty()){
cout << indent;
if(last){
cout << "\\-";
indent += " ";
} else {
cout << "|-";
indent += "| ";
}
cout << node->key << "\n";
if(node->leftChild != 0)
display(node->leftChild, indent, false);
if(node->rightChild != 0)
display(node->rightChild, indent, true);
} else
cout << "TREE IS EMPTY" << "\n\n";
}
template <class T>
int BinaryTree<T>::getHeight(){
if(!root)
cout << "ERROR: getHeight() root is NULL!" << "\n";
int result;
if(isEmpty())
result = 0;
else
result = calcHeight(root, 1);
return result;
}
template <class T>
int BinaryTree<T>::getKeyHeight(T key){
int result = -1;
if(!keyExists(key))
cout << "ERROR: Trying to get height of nonexistant key " << key << "\n";
else{
TreeNode * temp = findNode(root, key);
result = getHeight() - calcHeight(temp,1);
}
return result;
}
template <class T>
int BinaryTree<T>::calcHeight(TreeNode * node, int depth){ //Algorithm borrowed from wiki.answers.com
int leftDepth,
rightDepth,
result;
if(node->leftChild)
leftDepth = calcHeight(node->leftChild, depth+1);
else
leftDepth = depth;
if(node->rightChild)
rightDepth = calcHeight(node->rightChild, depth+1);
else
rightDepth = depth;
if(leftDepth > rightDepth)
result = leftDepth;
else
result = rightDepth;
return result;
}
template <class T>
void BinaryTree<T>::remove(T input){
if(!keyExists(input))
cout << "ERR: trying to remove nonexistant key " << input << "\n";
else{
TreeNode * temp = findNode(root,input);
removeNode(temp);
}
}
template <class T>
bool BinaryTree<T>::keyExists(T key){
bool result;
if(isEmpty())
result = false;
else{
if(findNode(root,key) != 0)
result = true;
else
result = false;
}
return result;
}
template <class T>
typename BinaryTree<T>::TreeNode * BinaryTree<T>::findNode(TreeNode * node, T input){
TreeNode * result = 0; //Returns 0 if none found
if(node->key == input)
result = node;
else{
if(node->leftChild != 0)
result = findNode(node->leftChild, input);
if(result == 0 && node->rightChild != 0)
result = findNode(node->rightChild, input);
}
return result;
}
template <class T>
void BinaryTree<T>::removeNode(TreeNode * node){
TreeNode * parent = 0;
if(node != root)
parent = findParent(root,node);
if(node->leftChild && node->rightChild){ //Case: both children (algorithm borrowed from tech-faq.com)
TreeNode * temp = findMin(node->rightChild);
string tkey = temp->key;
removeNode(temp);
node->key = tkey;
} else {
if(parent){
if(!(node->leftChild) && !(node->rightChild)){ //case: no children & not root
if(parent->leftChild == node)
parent->leftChild = 0;
else
parent->rightChild = 0;
}
if(!(node->leftChild) && node->rightChild){ //case: right child only & not root
if(parent->leftChild == node)
parent->leftChild = node->rightChild;
else
parent->rightChild = node->rightChild;
}
if(node->leftChild && !(node->rightChild)){ //case: left child only & not root
if(parent->leftChild == node)
parent->leftChild = node->leftChild;
else
parent->rightChild = node->leftChild;
}
delete node;
size--;
}
else{
if(node->leftChild) //case: left child only & root
root = node->leftChild;
else //case: right child only & root
root = node->rightChild;
delete node; //case: no children & root intrinsically covered
size--;
}
}
}
template <class T>
typename BinaryTree<T>::TreeNode * BinaryTree<T>::findMin(TreeNode * node){
TreeNode * result;
if(node->leftChild == 0)
result = node;
else
result = findMin(node->leftChild);
return result;
}
template <class T>
typename BinaryTree<T>::TreeNode * BinaryTree<T>::findParent(TreeNode * start, TreeNode * child){
TreeNode * result = 0;
if(start->leftChild){
if(start->leftChild->key == child->key)
result = start;
else
result = findParent(start->leftChild, child);
}
if(start->rightChild && result == 0){
if(start->rightChild->key == child->key)
result = start;
else
result = findParent(start->rightChild, child);
}
return result;
}
template <class T>
void BinaryTree<T>::destroySubTree(TreeNode * node){
TreeNode * parent = 0;
if(node != root)
parent = findParent(root,node);
if(node->leftChild)
destroySubTree(node->leftChild);
if(node->rightChild)
destroySubTree(node->rightChild);
if(parent){
if(parent->leftChild == node)
parent->leftChild = 0;
else
parent->rightChild = 0;
}
size--;
delete node;
}
template <class T>
BinaryTree<T>::~BinaryTree<T>(){
if(!isEmpty())
destroySubTree(root);
}
#endif
When T is std::string, you will end up having to functions with identical signature, that's why your compiler is complaining. To overcome this, just make compareVals a template of its own. I would also suggest you make them static, so that you can call them without an object.
static int compareVals(std::string const& v1, std::string const& v2)
{
//compare std::string
}
template<typename U>
static int compareVals(U v1, U v2)
{
//compare everything else
}
In fact, std::string does have built in relational operators, so for your specific use case it might not be necessary to define a compare function like the above. At any rate, this approach might still be useful to avoid making the assumption operators are defined for every data type your BinaryTree might end up supporting in the future.