Level order traversal of a B-tree - c++

I am writing a symulator of a B-tree.
I read here stackoverflow that the best way is use a queue to make a level order traversal. But i have no idea how to do it.
I work on implementation in c++ from geeksforgeeks.
Perhaps someone knows how to rebuild inorder traversal(code below) to level order traversal.
Classes and constuctors :
class BTreeNode
{
int *keys; // An array of keys
int t; // Minimum degree (defines the range for number of keys)
BTreeNode **C; // An array of child pointers
int n; // Current number of keys
int j;
bool leaf; // Is true when node is leaf. Otherwise false
public:
BTreeNode(int _t, bool _leaf); // Constructor
// A utility function to insert a new key in the subtree rooted with
// this node. The assumption is, the node must be non-full when this
// function is called
void insertNonFull(int k);
// A utility function to split the child y of this node. i is index of y in
// child array C[]. The Child y must be full when this function is called
void splitChild(int i, BTreeNode *y);
// A function to traverse all nodes in a subtree rooted with this node
void traverse();
// A function to search a key in subtree rooted with this node.
BTreeNode *search(int k); // returns NULL if k is not present.
// Make BTree friend of this so that we can access private members of this
// class in BTree functions
friend class BTree;
};
// A BTree
class BTree
{
BTreeNode *root; // Pointer to root node
int t; // Minimum degree
public:
// Constructor (Initializes tree as empty)
BTree(int _t)
{ root = NULL; t = _t; }
// function to traverse the tree
void traverse()
{ if (root != NULL)
cout << "root";
root->traverse(); }
// function to search a key in this tree
BTreeNode* search(int k)
{ return (root == NULL)? NULL : root->search(k); }
// The main function that inserts a new key in this B-Tree
void insert(int k);
};
Inorder traversal :
void BTreeNode::traverse()
{
// There are n keys and n+1 children, travers through n keys
// and first n children
int i;
for (i = 0; i < n; i++)
{
// If this is not leaf, then before printing key[i],
// traverse the subtree rooted with child C[i].
if (leaf == false)
C[i]->traverse();
cout << " " << keys[i];
}
// Print the subtree rooted with last child
if (leaf == false)
C[i]->traverse();
}

Here you can see the Depth-First-Search algorithm (wiki) recursive implementation.
For level-by-level traversal you probably need the Breadth-First-Search (wiki).
To achieve this, we will perform 2 steps.
First step: write recursion-free DFS:
void BTreeNode::traverse()
{
std::stack<BTreeNode*> stack;
stack.push(this);
while (!stack.empty())
{
BTreeNode* current = stack.top();
stack.pop();
int i;
for (i = 0; i < n; i++)
{
if (leaf == false)
stack.push(current->C[i]);
cout << " " << current->keys[i];
}
if (leaf == false)
stack.push(current->C[i]);
}
}
Second step: use queue instead of stack:
void BTreeNode::traverse()
{
std::queue<BTreeNode*> queue;
queue.push(this);
while (!stack.empty())
{
BTreeNode* current = queue.front();
queue.pop();
int i;
for (i = 0; i < n; i++)
{
if (leaf == false)
stack.push(current->C[i]);
cout << " " << current->keys[i];
}
if (leaf == false)
stack.push(current->C[i]);
}
}
So, it's done!

Related

Comparing nodes of two BSTs in C++

I need to compare each node of one BST with all the nodes of another BST.
Similar to how you'd do comparison in an array:
string arr[10];
string arr2[10];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
compare(arr[j], arr2[i]);
}
}
but instead of the outer for loop you're traversing in bst1, and instead of the inner for loop, you're traversing in bst2. then comparing node of bst1 with all nodes of bst2, then moving on to the next node of bst1 and comparing that with all of bst2 and so on
Can't seem to wrap my head around how to implement the traversals. Any help would be appreciated
The idea is to call traverse on the root node of Tree1 and for each node in it, pass it to another function compare which is called on root node of Tree2 and compares the passed node with every node in it.
#include <iostream>
struct Node
{
int val;
Node *left, *right;
};
void compare(Node *curr2, Node *curr1)
{
if (curr2 == nullptr)
return;
compare(curr2->left, curr1);
if (curr2->val == curr1->val) // replace with your comparison function
cout << "Match found for " << curr1->val << endl;
compare(curr2->right, curr1);
}
void traverse(Node *curr1, Node *root2)
{
if (curr1 == nullptr)
return;
traverse(curr1->left, root2);
compare(root2, curr1);
traverse(curr1->right, root2);
}
int main()
{
Node *root1, *root2;
traverse(root1, root2);
}

binary tree c++ insert and update?

I want to make a binary tree in c++ that perform insert operation the inserted values are 4 on a node that is
name, type , order, and color
The use will enter these 4 as INSERT corn oil 3 yellow. It create a new node with name as corn and 3 child node as type ,order and color.
If again user enter same thing but change any other except name that exists like
INSERT corn oil 4 red as corn name exist this will update node
preorder and postorder traversal with remove and find any node
Here is how i am going ?
struct TreeNode {
string itemname; // The data in this node.
TreeNode *left; // Pointer to the left subtree.
TreeNode *right; // Pointer to the right subtree.
};
1- Name node will have 2 values left right where 4th will be place
2- The hierarchy of tree is like root have only names that have 2 left right node so root have many nodes with names that have only 2 further node but no more node will be added to child node of names is it really a tree
Since you are using binary tree, I am not sure you can use string as a key for TreeNode (well I have always used intigers). So what I suggest is that you have structure like this:
// I am not sure about types, but I assumed them by name
struct Element {
char* name;
int type;
int order;
char* color;
};
struct TreeNode {
int key;
Element *element;
TreeNode *left, *right;
};
Then you would somehow calculate hash of Element::name to get a numeric value, which a is key. Now you would just traverse tree from root to the left or right depending on key. You would check on each node if key you are inserting is same as one in current node and if answer is yes, then you would swap values in that node, otherwise continue traversing the tree to the left or right. If you get to the bottom it means you haven't find a node with that key, so you create a new one and attach it as a leaf.
You can look this link to generate hash. However, keep in mind that for some string you can get same hash value, so you may need to keep more than one element at the current tree node.
UPDATE
Here is the code, however you can optimize it more by using pointers. But as mentioned in comments, if you are not strictly bound to use binary tree, you should use HashTable or std::map.
std::map<std::string, struct Element*> elements
and for retrieving element:
Element *e = elements["corn"]
Binary Tree implementation:
#include <iostream>
#include <vector>
#define A 54059 /* a prime */
#define B 76963 /* another prime */
#define C 86969 /* yet another prime */
#define FIRSTH 37 /* also prime */
struct Element {
std::string name;
std::string type;
int order;
std::string color;
};
struct TreeNode {
int key;
std::vector<Element> values;
struct TreeNode *left;
struct TreeNode *right;
};
/**
* see: https://stackoverflow.com/questions/8317508/hash-function-for-a-string
*/
int calculateHash(const char *s)
{
int h = FIRSTH;
while (*s) {
h = (h * A) ^ (s[0] * B);
s++;
}
return h; // or return h % C;
}
void printElement(Element element)
{
std::cout
<< element.name
<< " "
<< element.type
<< " "
<< element.order
<< " "
<< element.color
<< std::endl;
}
void preOrder(TreeNode* node)
{
if( node == NULL )
return;
for(size_t i=0; i<node->values.size(); i++) {
printElement(node->values[i]);
}
preOrder(node->left);
preOrder(node->right);
}
void insert(TreeNode** root, Element element, int key)
{
if( *root == NULL ) {
TreeNode* node = new TreeNode();
node->key = key;
node->values.push_back(element);
*root = node;
return;
};
if( key == (*root)->key ) {
for(size_t i=0; i<(*root)->values.size(); i++) {
if( (*root)->values[i].name == element.name ) {
(*root)->values[i].type = element.type;
(*root)->values[i].order = element.order;
(*root)->values[i].color = element.color;
break;
}
}
}
else if( key < (*root)->key ) {
insert( &((*root)->left), element, key );
}
else {
insert( &((*root)->right), element, key );
}
}
int main()
{
TreeNode *node = NULL;
insert(&node, {"corn1", "oil", 3, "yellow"}, calculateHash("corn1"));
insert(&node, {"corn2", "oil", 3, "yellow"}, calculateHash("corn2"));
insert(&node, {"corn3", "oil", 3, "yellow"}, calculateHash("corn3"));
insert(&node, {"corn2", "aaa", 32, "blue"}, calculateHash("corn2"));
preOrder(node);
return 0;
}

Binary Tree Destructor Issue

I have recently been implementing a binary tree in my free-time and I do believe I have it working correctly. However, I have ran into a mysterious segmentation fault when running a simple test. Here is my implementation of the binary search tree:
//the binary search tree class
template <class M>
class BS_Tree {
private:
//node structure
struct Node {
M data; //the key of the node
Node* left,* right,* parent; //node pointers to left right and parent
Node(M key, Node* p) //parameterized node constructor
: data(key), left(nullptr), right(nullptr), parent(p) {}
};
Node* root; //the root node of the binary search tree
bool is_left(Node* n) {return n->parent->left == n;} //utility function
void destroy(Node* n); //used for tree destruction
void duplicate(Node* const &, Node* &); //used for copy construction
public:
BS_Tree() {root = nullptr;} //constructor
~BS_Tree() {destroy(root);} //destructor
BS_Tree(const BS_Tree &); //copy constructor
BS_Tree &operator=(const BS_Tree &); //copy assignment operator
Node* find(M key); //find function
void insert(M); //insert function
void erase(Node*); //erase function
Node* get_root() {return root;}
};
//destroy function used for tree destruction
template <class M>
void BS_Tree<M>::destroy(Node* n) {
if(n) { //recursively erase the tree
if(n->left) destroy(n->left);
if(n->right) destroy(n->right);
delete n;
}
}
//duplicate function used for copy construction
template <class M>
void BS_Tree<M>::duplicate(Node* const &one, Node* &two) {
if(!one) two = nullptr;
else { //recursively duplicate the tree
two = new Node(one->data);
duplicate(one->left, two->left);
duplicate(one->right, two->right);
}
}
//copy constructor
template <class M>
BS_Tree<M>::BS_Tree(const BS_Tree &b) {
if(!b.root) root = nullptr; //update root
else duplicate(b.root, this->root); //call duplicate function
}
//copy assignment operator
template <class M>
BS_Tree<M> &BS_Tree<M>::operator=(const BS_Tree &b) {
if(!b.root) root = nullptr; //update root
else { //destroy current tree and duplicate source tree
this->~BS_Tree();
duplicate(b.root, this->root);
}
}
//function to find a key and return a pointer
template <class M>
typename BS_Tree<M>::Node* BS_Tree<M>::find(M key) {
Node* i = root; //create an index
while(i) {
//try to find the key
if (i->data == key) return i;
if(i->data > key) i = i->left;
else i = i->right;
}
//return a pointer to the key, nullptr if not found
return i;
}
//function to insert a new node
template <class M>
void BS_Tree<M>::insert(M key) {
if(!root) { //if no tree, make new node the root
root = new Node(key, nullptr);
return;
}
Node* i = root; //create an index
while(true) { //find insertion point and insert new node
if(i->data > key) {
if(!i->left) {
i->left = new Node(key, i);
return;
}
else i = i->left;
}
if(i->data <= key) {
if(!i->right) {
i->right = new Node(key, i);
return;
}
else i = i->right;
}
}
}
//Function to erase a node
template <class M>
void BS_Tree<M>::erase(Node* n) {
if(n) {
//no children case
if(!n->left && !n->right) {
if(root == n) root = nullptr; //if node is root, make root null
else { //if node is a child, update parent's children
if(is_left(n)) n->parent->left = nullptr;
else n->parent->right = nullptr;
}
delete n; //erase the node
return;
}
//one child cases
if(!n->left) {
if(n == root){ //if node is root, update root
root = n->right;
n->right->parent = nullptr;
} else { //if node is a child, update parent's children and nodes parent
if(is_left(n)) n->parent->left = n->right;
else n->parent->right = n->right;
n->right->parent = n->parent;
}
delete n; //erase the node
return;
}
if(!n->right) {
if(n == root){ //if node is root, update root
root = n->left;
n->left->parent = nullptr;
} else { //if node is a child, update parent's children and nodes parent
if(is_left(n)) n->parent->left = n->left;
else n->parent->right = n->left;
n->left->parent = n->parent;
}
delete n; //erase the node
return;
}
//two children case
else {
Node* i = n; //create an index
i = i->right; //find successor
while(i->left) i = i->left;
n->data = i->data; //set nodes data to successor's data
if(is_left(i)) i->parent->left = i->right; //update successor's parent and its child
else i->parent->right = i->right;
if(i->right) i->right->parent = i->parent;
delete i; //erase successor node
return;
}
}
}
As for the test, it is a simple linear vector element insert vs time performance check. It takes a max number of elements and an increment of elements for each test. It then runs the test for each increment and times the insertions. It works fine for the first few iterations (i.e n = 10000, 20000, 30000, 40000), but then I reach a segmentation fault after insertion when the 50000 element tree destructor is called. It is hinting at the line:
if(n->right) destroy(n->right);
I understand that I am doing an incremental insertion so all of my elements are on the right side of the tree, but I am having a hard time figuring out where I went wrong and why it only messes up on this iteration.
My test implematation:
int main(){
//number of elements, max test elements, and test increment
int n, t = 100000, i = 10000;
//run the test a number of times
for(n = i; n <= t; n += i) {
//get an incremental vector of size n
std::vector<int> test(n);
std::iota(std::begin(test), std::end(test), 0);
//run the insert test print the time interval
BS_Tree<int> m;
auto ibs_start = clock();
for(auto i : test){
m.insert(i);
}
auto ibs_stop = clock();
std::cout << n << ' ' << (ibs_stop - ibs_start)/double(CLOCKS_PER_SEC)*1000 << "\n";
}
return 0;
}
If someone could help I would greatly appreciate it!
Edit: Could it simply be my stack overflowing due to the destroy function having to store all of the elements before reaching the bottom and actually deleting anything?
If it works for some number of items (40000), but not for a larger, it might be a stackoverflow. Looking at the code also confirms this: destroying is recursive, and in the case of extremely unbalanced tree, it means as many stack frames as many nodes.
The question is how this could be solved without recursion? This is not so obvious, as there are two recursive calls. My solution is to traverse the binary tree, post-order, and delete leaf nodes.
Here is a solution -- an iterative version of the destroy method:
//destroy function used for tree destruction
template <class M>
void BS_Tree<M>::destroy(Node* n) {
if (n) { // iteratively erase the tree
Node* c = n; // current node
while (true) {
if (c->right) {
// it has right child, descend to it
c = c->right;
continue;
}
if (c->left) {
// it has left child, descend to it
c = c->left;
continue;
}
// this node has no (more) children, destroy it
Node* p = c->parent;
if (p) {
// update its parent to no longer point to it
if (p->right == c) p->right = NULL; // we came from left
else if (p->left == c) p->left = NULL; // we came from left
}
// destroy the node
delete c;
// go back to its parent
c = p;
if (c == n) {
// where at back at start node, stop
delete n;
break;
}
}
}
}
Update: I have tested my solution, and made some small changes.

simple binary search tree. Segmentation Fault

Just a simple BST to print numbers inorder. Couldn't figure out what I did wrong.
#include <iostream>
using namespace std;
class bst {
private:
bst* root;
bst* left;
bst* right;
int value;
public:
bst(const int& numb) : root(NULL), left(NULL), right(NULL) {
value = numb;
}
void insert(const int& numb) {
if (numb < value) {
if (left == NULL) {
left = new bst(numb);
left->root = left;
} else {
left->insert(numb);
}
} else if (numb > value) {
if (right == NULL) {
right = new bst(numb);
right->root = right;
} else {
left->insert(numb);
}
} else if (numb == value) {
cout << "duplicated value" << endl;
}
}
void inorder() {
if (left == NULL) cout << value << endl;
else left->inorder();
right->inorder();
}
};
int main() {
bst tree(5);
tree.insert(7);
tree.insert(1);
tree.insert(3);
tree.insert(2);
tree.insert(9);
tree.insert(10);
return 0;
}
Line 29 should read:
right->insert(numb);
where it currently reads:
left->insert(numb);
I highly recommend looking into gdb for solving situations like this.
inorder() should be:
if (left != NULL) left->inorder();
cout << value << endl;
if (right != NULL) right->inorder();
I assume the rest are correct.
Logic errors throughout.
Crash is here:
if (right == NULL) {
right = new bst(numb);
right->root = right;
} else {
left->insert(numb);
}
The else case shold use right, not left.
At least as I see it, your fundamental design is flawed. Although I realize many text books (and such) describe a tree as a recursive structure where each node has two sub-trees, I've never found that a very good way to design the code.
At least in my experience, in actual code, you're (much) better off separating the notion of a node in the tree from the notion of an entire tree. Only the tree should be visible to the outside world; node should be hidden away inside the tree, invisible to the outside world.
class bst {
class node {
int value;
node *left;
node *right;
// ...
};
// ...
node *root;
};
I'd then split insert into two pieces: a public function that takes a value, and just forwards to the second function with the root as the starting point. The second actually traverses the three and inserts the new item:
// public interface:
void insert(int v) {
insert(new node(v), root);
}
// private workhorse:
void insert(node *n, node *&pos) {
if (pos == NULL)
pos = n;
else if (n->value < pos->value)
insert(n,pos->left);
else if (n->value > pos->value)
insert(n,pos->right);
else
// duplicate value.
}
Likewise, inorder gets split into a public and private pair, with the public providing only an interface, and the private one doing all the real work:
// public interface:
void inorder() {
inorder(root);
}
// private worker
void inorder(node *n) {
if (n==NULL)
return;
inorder(n->left);
std::cout << n->value << endl;
inorder(n->right);
}
For what it's worth: yes, I have tested this code and it does work at least with the input you used in you main. It does have shortcomings though. For example, both insert and inorder traverse the tree recursively, so a large, badly imbalanced tree could lead to stack overflow. It's fairly easy to do insertion iteratively, but for real use you usually just switch to some sort of balanced tree instead.

c++ binarysearchtree insert

I'm working on a project where I have to make a binary search tree that stores strings and takes account of doubles. While i've already tackled the specifics, I can't for the life of me get this damn insert function to work. It seems to only store the root node, leaving it's "children" NULL even though it does actually seem to assign the left and right pointers to new nodes. However when I attempt to output it, only the main parent (root) node exists. I guess the changes do not get saved for whatever reason.
Here's the header file:
#ifndef BST_H
#define BST_H
#include <string>
#include <vector>
#include <iostream>
using namespace std;
typedef string ItemType;
class Node
{
public:
Node(); // constructor
ItemType data; // contains item
Node* left; // points to left child
Node* right;// points to right child
int dataCount; // keeps track of repeats
vector<int> lineNumber; // keeps track of line numbers
};
class Tree
{
public:
Tree(); // constructor
// ~Tree(); // destructor. not working.
bool isEmpty(); // tests for empty tree
Node* find(Node* root, ItemType item); // finds an item
void insert(Node* root, ItemType item, int lineN, Tree tree); // inserts an item
void outputTree(Node* root); // lists all items in tree
void treeStats(Tree tree); // outputs tree stats
void clearTree(); // erases the tree (restart)
Node* getRoot(); // returns the root
void setRoot(Node*& root);
// void getHeight(Tree *root); // gets height of tree
private:
Node* root; // root of tree
int nodeCount; // number of nodes
};
#endif
cpp:
#include "BST.h"
bool setRootQ = true;
/** Node constructor- creates a node, sets children
* to NULL and ups the count. */
Node::Node()
{
left = right = NULL;
dataCount = 1;
}
/** Tree constructor- creates instance of tree
* and sets parameters to NULL */
Tree::Tree()
{
root = NULL;
nodeCount = 0;
}
/** Destructor- deallocates tree/node data;
* avoids heap leaks. SOMETHING WRONG. CAUSES SEGFAULT
Tree::~Tree()
{
if(this->root->left) // if a left child is present
{
delete this->root->left; //recursive call to destructor ("~Tree(->left)")
this->root->left = NULL;
}
if(this->root->right) // if a right child is present
{
delete this->root->right; //recursive call to destructor
this->root->right = NULL;
}
} */
/** Returns true if tree is empty.
* Otherwise returns false (DUH). */
bool Tree::isEmpty()
{
return root == NULL;
}
/** Searches tree for item; returns the node if found
* #param root- tree node.
* item- data to look for. */
Node* Tree::find(Node* root, ItemType item)
{
if(root == NULL) // if empty node
{
return NULL;
}
else if(item == root->data) // if found
{
return root;
}
else if(item < root->data) // if item is less than node
{
find(root->left, item);
}
else if(item > root->data) // if item is more than node
{
find(root->right, item);
}
return NULL;
}
/** Adds a new node to the tree. If duplicate, increases count.
* #param item- data to insert.
* root- tree node/ */
void Tree::insert(Node* root, ItemType item, int lineN, Tree tree)
{
Node* temp = find(tree.getRoot(), item);
if(temp != NULL) // if item already exists
{
temp->dataCount += 1;
temp->lineNumber.push_back(lineN);
return;
}
if(root == NULL) // if there is an empty space
{
root = new Node; // insert new node
root->data = item; // w/ data value
root->lineNumber.push_back(lineN);
nodeCount++;
if(setRootQ)
{
setRoot(root);
setRootQ = false;
}
return;
}
if(item < root->data)
{
insert(root->left, item, lineN, tree);
}
if(item > root->data)
{
insert(root->right, item, lineN, tree);
}
}
/** Outputs tree to console in inorder.
* #param root- tree root. */
void Tree::outputTree(Node* root)
{
if(isEmpty()) // if empty tree
{
cout << "Error: No items in tree" << endl; // error message
}
else
{
if(root->left != NULL)
{
outputTree(root->left);
}
cout << "- " << root->data << " (" << root->dataCount << ") line#s: ";
for(unsigned int i = 0; i < root->lineNumber.size(); i++)
{
cout << root->lineNumber[i] << ", ";
}
cout << endl;
if(root->right != NULL)
{
outputTree(root->right);
}
}
}
/** Displays tree stats including number of nodes,
* tree height, and more frequent item.
* #param tree- tree instance. */
void Tree::treeStats(Tree tree)
{
cout << "Number of entries: " << nodeCount << endl;
// unfinished
}
/** Clears tree.
void Tree::clearTree()
{
this->~Tree();
} */
/** Returns the root of the tree. */
Node* Tree::getRoot()
{
return root;
}
void Tree::setRoot(Node*& rootS)
{
root = rootS;
}
I realize my destructor isn't working but I'll tackle that myself later. I've been pulling my hair out over this trying to figure out what I'm missing, but to no avail. If anyone can give me any help and point me in the direction towards a solution I would greatly appreciate it.
i think it might have something to do with
void Tree::insert(Node* root, ItemType item, int lineN, Tree tree)
and instead should be something like
void Tree::insert(Node* &root, ItemType item, int lineN, Tree tree)
but when i try i get a "no matching function" error. :/
The solution you suggest yourself (with insert() taking Node *& root) will work. You have to make a corresponding change to the .h file, AND also change getRoot() to return Node *& in both .h and .cc files.
This will work. But your code has other problems. For example, setRoot and setRootQ don't do anything useful, as far as I can tell. The fourth argument to insert() only confuses things and does nothing to detect duplicates. It should be removed. To detect a duplicate simply do if (item == root->data) just before you do if (item < root->data) in the insert() method (i.e. it'll be even more similar to find()).
Also, if anyone besides you will ever use your code, you shouldn't require passing in getRoot() to methods like find() and insert(). Instead, create private helper methods, like find_helper(Node*, Item) and insert_helper(Node*&,Item), and have the public methods call them with the root node as the first argument. E.g.:
Node *find(Item item) { return find_helper(root, item); }
This would also make the weird return type of getRoot() unnecessary, and you could change it back to returning the plain Node*, or get rid of that accessor altogether.
Seems like there is a lot of pointer comparison occurring but the pointer member variables are not being initialized. Ensure that the pointer member variables are initialized properly so that they evaluate properly in if statements.
Change from:
class Node
{
public:
Node(); // constructor
...
};
to
class Node
{
public:
Node() : left(0), right(0) {}
...
};