Simple heap program- what does this variable do - c++

void ReheapDown( int* heap, int top, int swpIndx, int numElements ) {
int leftChild = 2 * top + 1;
int rightChild = 2 * top + 2;
int minChild;
if (leftChild < numElements) {
// find subscript of smallest child
if (rightChild >= swpIndx || heap[leftChild] < heap[rightChild])
minChild = leftChild;
else
minChild = rightChild;
// if data at top is greater than smallest
// child then swap and continue
if (heap[top] > heap[minChild]) {
swap( heap[top], heap[minChild] );
ReheapDown( heap, minChild, swpIndx, numElements );
}
}
This is for a simple heap. ReheapDown is used partly for removing items in the heap. What does swpIndx do though? (I need to know to do a homework assignment, where I'm supposed to write the function that removes a certain key in the heap.)

To remove a key from a heap, we might want to swap it with the last key in the heap before deleting it, otherwise there would be a gaping hole in the heap.
However, swapping the last node with the node we want to remove can upset the ordering of the heap, which is where that ReheapDown method that you provided comes in.
I believe the swpIndex parameter is the index into which we have placed the element that we wish to remove. So that part of the code basically says:
if (there exists a left child) {
if (there is no right child || left child < right child)
minChild <- left child
else
minChild <- right child
}
I think that parameter is unnecessary though, since it seems that it's only purpose is to check for the existence of the left and right child; this can also be accomplished by comparing the leftChild and rightChild indices to numElements.
Hope this helps :)

Related

where is the faulty logic in this re-heap function?

I'm currently working with a heap structure which is suppose to be used to sort numbers in an array. I have done something like this in the code when I want to sort the structure when I pop(dequeue) a element from the heap.
template<typename T>
inline void dHeap<T>::reHeapDown(int root, int bottom)
{
int minChild;
int rightChild;
int leftChild;
int temp;
// Get index of root's right/left child
leftChild = root * 2 + 1;
rightChild = root * 2 + 2;
//Then we are not done with re-heaping
if (leftChild <= bottom)
{
if (leftChild == bottom)
{
minChild = leftChild;
}
else
{
if (arr[leftChild] <= arr[rightChild])
minChild = leftChild;
else
minChild = rightChild;
}
if (arr[root] > arr[minChild])
{
// Swap these two elements
temp = arr[root];
arr[root] = arr[minChild];
arr[minChild] = temp;
// Make recursive call till reheaping completed
reHeapDown(minChild, bottom);
}
}
}
My thought here is that the lowest value in the heap always will be in the root and that's the value that I will be poped(dequeued) in my pop function.
But I'm having some problem that it wont sort the heap correctly.
is there something wrong with my logic in this function and if so, where is it?
Building a heap only enforces the property:
in case of min heap every parent is lesser than it children
in case of max heap every parent is greater than its children.
in case of min-max heap even depth levels (0,2,4..) are lesserr and odd levels (1,3,5...) are greater than their respective children.
However the heap will not necessarily be sorted. It will be balanced, because it is filled in order, level by level, from left to right.
Heapsort will sort an array by using heap functions. The final array will also work as a balanced and sorted heap.

Maintaining a Min heap on deletion c++

Test case:
8,7,5,2,3,6,9 (NOT min heap) (this is element A* for buildHeap function)
2,3,5,7,8,6,9 (min heap after calling build heap)
3,5,6,7,8,9 (after calling deleteMin) THIS IS INCORRECT
it should be this 3,7,5,9,8,6
I can't seem to find the problem with deleteMin i know my heapify is working but idk maybe im not seeing something.
Element Heap::deleteMin(Heap& heap){
Element deleted = heap.H[0];
heap.H[0] = heap.H[heap.size-1];
heap.size--;
cout<<deleted.getKey()<<" has been deleted from heap"<<endl;
for(int i=heap.capacity/2-1;i>=0;--i)
heapify(heap,i);
return deleted;
}
void Heap::heapify(Heap& heap,int index){
int smallest = 0;
int left = 2*index;
int right = 2*index+1;
if(left < heap.size && heap.H[left].getKey() < heap.H[index].getKey())
smallest=left;
else
smallest=index;
if(right < heap.size && heap.H[right].getKey() < heap.H[smallest].getKey())
smallest=right;
if(smallest != index){
int swapKey = heap.H[index].getKey();
heap.H[index].setKey(heap.H[smallest].getKey());
heap.H[smallest].setKey(swapKey);
heapify(heap,smallest);
}
}
void Heap::buildHeap(Heap& heap, Element* A){
for(int j=0;j<heap.capacity;++j){
heap.insert(heap,A[j]);
for(int i=heap.capacity/2-1;i>=0;--i)
heapify(heap,i);
}
}
The first problem is that your calculations for child indexes are wrong. If you're using H[0] as the root of the heap, then
left = (2*index)+1
right = (2*index)+2
The calculations you have assume that the root is at H[1].
The other problem is that you're doing too much work in your deleteMin function:
Element Heap::deleteMin(Heap& heap){
Element deleted = heap.H[0];
heap.H[0] = heap.H[heap.size-1];
heap.size--;
cout<<deleted.getKey()<<" has been deleted from heap"<<endl;
for(int i=heap.capacity/2-1;i>=0;--i)
heapify(heap,i);
return deleted;
}
After you delete the minimum item and put the last item in the heap at the root, you just need to call heapify(heap, 0); There's no reason to re-build the entire heap in that loop.
So your function becomes:
Element Heap::deleteMin(Heap& heap){
Element deleted = heap.H[0];
heap.H[0] = heap.H[heap.size-1];
heap.size--;
cout<<deleted.getKey()<<" has been deleted from heap"<<endl;
heapify(heap, 0);
return deleted;
}
Your buildHeap method is similarly doing too much work.
You might be interested in a refresher on heaps. My blog article at http://blog.mischel.com/2013/09/29/a-better-way-to-do-it-the-heap/ explains their operation in very simple terms, and my simple heap of integers shows a bare-bones implementation. It's in C# rather than C++, but the code is very similar. You should be able to understand it without trouble.

Is it possible to make efficient pointer-based binary heap implementations?

Is it even possible to implement a binary heap using pointers rather than an array? I have searched around the internet (including SO) and no answer can be found.
The main problem here is that, how do you keep track of the last pointer? When you insert X into the heap, you place X at the last pointer and then bubble it up. Now, where does the last pointer point to?
And also, what happens when you want to remove the root? You exchange the root with the last element, and then bubble the new root down. Now, how do you know what's the new "last element" that you need when you remove root again?
Solution 1: Maintain a pointer to the last node
In this approach a pointer to the last node is maintained, and parent pointers are required.
When inserting, starting at the last node navigate to the node below which a new last node will be inserted. Insert the new node and remember it as the last node. Move it up the heap as needed.
When removing, starting at the last node navigate to the second-to-last node. Remove the original last node and remember the the new last node just found. Move the original last node into the place of the deleted node and then move it up or down the heap as needed.
It is possible to navigate to the mentioned nodes in O(log(n)) time and O(1) space. Here is a description of the algorithms but the code is available below:
For insert: If the last node is a left child, proceed with inserting the new node as the right child of the parent. Otherwise... Start at the last node. Move up as long as the current node is a right child. If the root was not reached, move to the sibling node at the right (which necessarily exists). Then (whether or not the root was reached), move down to the left as long as possible. Proceed by inserting the new node as the left child of the current node.
For remove: If the last node is the root, proceed by removing the root. Otherwise... Start at the last node. Move up as long as the current node is a left child. If the root was not reached, move to the sibling left node (which necessarily exists). Then (whether or not the root was reached), move down to the right as long as possible. We have arrived at the second-to-last node.
However, there are some things to be careful about:
When removing, there are two special cases: when the last node is being removed (unlink the node and change the last node pointer), and when the second-to-last node is being removed (not really special but the possibility must be considered when replacing the deleted node with the last node).
When moving nodes up or down the heap, if the move affects the last node, the last-node pointer must be corrected.
Long ago I have made an implementation of this. In case it helps someone, here is the code. Algorithmically it should be correct (has also been subjected to stress testing with verification), but there is no warranty of course.
Solution 2: Reach the last node from the root
This solution requires maintaining the node count (but not parent pointers or the last node). The last (or second-to-last) node is found by navigating from the root towards it.
Assume the nodes are numbered starting from 1, as per the typical notation for binary heaps. Pick any valid node number and represent it in binary. Ignore the first (most significant) 1 bit. The remaining bits define the path from the root to that node; zero means left and one means right.
For example, to reach node 11 (=1011b), start at the root then go left (0), right (1), right (1).
This algorithm can be used in insert to find where to place the new node (follow the path for node node_count+1), and in remove to find the second-to-last-node (follow the path for node node_count-1).
This approach is used in libuv for timer management; see their implementation of the binary heap.
Usefulness of Pointer-based Binary Heaps
Many answers here and even literature say that an array-based implementation of a binary heap is strictly superior. However I contest that because there are situations where the use of an array is undesirable, typically because the upper size of the array is not known in advance and on-demand reallocations of an array are not deemed acceptable, for example due to latency or possibility of allocation failure.
The fact that libuv (a widely used event loop library) uses a binary heap with pointers only further speaks for this.
It is worth noting that the Linux kernel uses (pointer-based) red-black trees as a priority queue in a few cases, for example for CPU scheduling and timer management (for the same purpose as in libuv). I find it likely that changing these to use a pointer-based binary heap will improve performance.
Hybrid Approach
It is possible to combine Solution 1 and Solution 2 into a hybrid approach which dynamically picks either of the algorithms (for finding the last or second-to-last node), the one with a lower cost, measured in the number of edges that need to be traversed. Assume we want to navigate to node number N, and highest_bit(X) means the 0-based index of the highest-order bit in N (0 means the LSB).
The cost of navigating from the root (Solution 2) is highest_bit(N).
The cost of navigating from the previous node which is on the same level (Solution 1) is: 2 * (1 + highest_bit((N-1) xor N)).
Note that in the case of a level change the second equation will yield a wrong (too large) result, but in that case traversal from the root is more efficient anyway (for which the estimate is correct) and will be chosen, so there is no need for special handling.
Some CPUs have an instruction for highest_bit allowing very efficient implementation of these estimates. An alternative approach is to maintain the highest bit as a bit mask and do these calculation with bit masks instead of bit indices. Consider for example that 1 followed by N zeroes squared is equal to 1 followed by 2N zeroes).
In my testing it has turned out that Solution 1 is on average faster than Solution 2, and the hybrid approach appeared to have about the same average performance as Solution 2. Therefore the hybrid approach is only useful if one needs to minimize the worst-case time, which is (twice) better in Solution 2; since Solution 1 will in the worst case traverse the entire height of the tree up and then down.
Code for Solution 1
Note that the traversal code in insert is slightly different from the algorithm described above but still correct.
struct Node {
Node *parent;
Node *link[2];
};
struct Heap {
Node *root;
Node *last;
};
void init (Heap *h)
{
h->root = NULL;
h->last = NULL;
}
void insert (Heap *h, Node *node)
{
// If the heap is empty, insert root node.
if (h->root == NULL) {
h->root = node;
h->last = node;
node->parent = NULL;
node->link[0] = NULL;
node->link[1] = NULL;
return;
}
// We will be finding the node to insert below.
// Start with the current last node and move up as long as the
// parent exists and the current node is its right child.
Node *cur = h->last;
while (cur->parent != NULL && cur == cur->parent->link[1]) {
cur = cur->parent;
}
if (cur->parent != NULL) {
if (cur->parent->link[1] != NULL) {
// The parent has a right child. Attach the new node to
// the leftmost node of the parent's right subtree.
cur = cur->parent->link[1];
while (cur->link[0] != NULL) {
cur = cur->link[0];
}
} else {
// The parent has no right child. This can only happen when
// the last node is a right child. The new node can become
// the right child.
cur = cur->parent;
}
} else {
// We have reached the root. The new node will be at a new level,
// the left child of the current leftmost node.
while (cur->link[0] != NULL) {
cur = cur->link[0];
}
}
// This is the node below which we will insert. It has either no
// children or only a left child.
assert(cur->link[1] == NULL);
// Insert the new node, which becomes the new last node.
h->last = node;
cur->link[cur->link[0] != NULL] = node;
node->parent = cur;
node->link[0] = NULL;
node->link[1] = NULL;
// Restore the heap property.
while (node->parent != NULL && value(node->parent) > value(node)) {
move_one_up(h, node);
}
}
void remove (Heap *h, Node *node)
{
// If this is the only node left, remove it.
if (node->parent == NULL && node->link[0] == NULL && node->link[1] == NULL) {
h->root = NULL;
h->last = NULL;
return;
}
// Locate the node before the last node.
Node *cur = h->last;
while (cur->parent != NULL && cur == cur->parent->link[0]) {
cur = cur->parent;
}
if (cur->parent != NULL) {
assert(cur->parent->link[0] != NULL);
cur = cur->parent->link[0];
}
while (cur->link[1] != NULL) {
cur = cur->link[1];
}
// Disconnect the last node.
assert(h->last->parent != NULL);
h->last->parent->link[h->last == h->last->parent->link[1]] = NULL;
if (node == h->last) {
// Deleting last, set new last.
h->last = cur;
} else {
// Not deleting last, move last to node's place.
Node *srcnode = h->last;
replace_node(h, node, srcnode);
// Set new last unless node=cur; in this case it stays the same.
if (node != cur) {
h->last = cur;
}
// Restore the heap property.
if (srcnode->parent != NULL && value(srcnode) < value(srcnode->parent)) {
do {
move_one_up(h, srcnode);
} while (srcnode->parent != NULL && value(srcnode) < value(srcnode->parent));
} else {
while (srcnode->link[0] != NULL || srcnode->link[1] != NULL) {
bool side = srcnode->link[1] != NULL && value(srcnode->link[0]) >= value(srcnode->link[1]);
if (value(srcnode) > value(srcnode->link[side])) {
move_one_up(h, srcnode->link[side]);
} else {
break;
}
}
}
}
}
Two other functions are used: move_one_up moves a node one step up in the heap, and replace_node replaces moves an existing node (srcnode) into the place held by the node being deleted. Both work only by adjusting the links to and from the other nodes, there is no actual moving of data involved. These functions should not be hard to implement, and the mentioned link includes my implementations.
The pointer based implementation of the binary heap is incredibly difficult when compared to the array based implementation. But it is fun to code it. The basic idea is that of a binary tree. But the biggest challenge you will have is to keep it left-filled. You will have difficulty in finding the exact location as to where you must insert a node.
For that, you must know binary traversal. What we do is. Suppose our heap size is 6. We will take the number + 1, and convert it to bits. The binary representation of 7 is, "111". Now, remember to always omit the first bit. So, now we are left with "11". Read from left-to-right. The bit is '1', so, go to the right child of the root node. Then the string left is "1", the first bit is '1'. As you have only 1 bit left, this single bit tells you where to insert the new node. As it is '1' the new node must be the right child of the current node. So, the raw working of the process is that, convert the size of the heap into bits. Omit the first bit. According to the leftmost bit, go to the right child of the current node if it is '1', and to the left child of the current node if it is '0'.
After inserting the new node, you will bubble it up the heap. This tells you that you will be needing the parent pointer. So, you go once down the tree and once up the tree. So, your insertion operation will take O(log N).
As for the deletion, it is still a challenge to find the last node. I hope you are familiar with deletion in a heap where we swap it with the last node and do a heapify. But for that you need the last node, for that too, we use the same technique as we did for finding the location to insert the new node, but with a little twist. If you want to find the location of the last node, you must use the binary representation of the value HeapSize itself, not HeapSize + 1. This will take you to the last node. So, the deletion will also cost you O(log N).
I'm having trouble in posting the source code here, but you can refer to my blog for the source code. In the code, there is Heap Sort too. It is very simple. We just keep deleting the root node. Refer to my blog for explanation with figures. But I guess this explanation would do.
I hope my answer has helped you. If it did, let me know...! ☺
For those saying this is a useless exercise, there are a couple of (admittedly rare) use cases where a pointer-based solution is better. If the max size of the heap is unknown, then an array implementation will need to stop-and-copy into fresh storage when the array fills. In a system (e.g. embedded) where there are fixed response time constraints and/or where free memory exists, but not a big enough contiguous block, this may be not be acceptable. The pointer tree lets you allocate incrementally in small, fixed-size chunks, so it doesn't have these problems.
To answer the OP's question, parent pointers and/or elaborate tracking aren't necessary to determine where to insert the next node or find the current last one. You only need the bits in the binary rep of the heap's size to determine the left and right child pointers to follow.
Edit Just saw Vamsi Sangam#'s explanation of this algorithm. Nonetheless, here's a demo in code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node_s {
struct node_s *lft, *rgt;
int data;
} NODE;
typedef struct heap_s {
NODE *root;
size_t size;
} HEAP;
// Add a new node at the last position of a complete binary tree.
void add(HEAP *heap, NODE *node) {
size_t mask = 0;
size_t size = ++heap->size;
// Initialize the mask to the high-order 1 of the size.
for (size_t x = size; x; x &= x - 1) mask = x;
NODE **pp = &heap->root;
// Advance pp right or left depending on size bits.
while (mask >>= 1) pp = (size & mask) ? &(*pp)->rgt : &(*pp)->lft;
*pp = node;
}
void print(NODE *p, int indent) {
if (!p) return;
for (int i = 0; i < indent; i++) printf(" ");
printf("%d\n", p->data);
print(p->lft, indent + 1);
print(p->rgt, indent + 1);
}
int main(void) {
HEAP h[1] = { NULL, 0 };
for (int i = 0; i < 16; i++) {
NODE *p = malloc(sizeof *p);
p->lft = p->rgt = NULL;
p->data = i;
add(h, p);
}
print(h->root, 0);
}
As you'd hope, it prints:
0
1
3
7
15
8
4
9
10
2
5
11
12
6
13
14
Sift-down can use the same kind of iteration. It's also possible to implement the sift-up without parent pointers using either recursion or an explicit stack to "save" the nodes in the path from root to the node to be sifted.
A binary heap is a complete binary tree obeying the heap property. That's all. The fact that it can be stored using an array, is just nice and convenient. But sure, you can implement it using a linked structure. It's a fun exercise! As such, it is mostly useful as an exercise or in more advanced datastructures( meldable, addressable priority queues for example ), as it is quite a bit more involved than doing the array version. For example, think about siftup/siftdown procedures, and all the edge cutting/sewing you'll need to get right. Anyways, it's not too hard, and once again, good fun!
There are a number of comments pointing out that by a strict definition it is possible to implement a binary heap as a tree and still call it a binary heap.
Here is the problem -- there is never a reason to do so since using an array is better in every way.
If you do searches to try to find information on how to work with a heap using pointers you are not going to find any -- no one bothers since there is no reason to implement a binary heap in this way.
If you do searches on trees you will find lots of helpful materials. This was the point of my original answer. There is nothing that stops people from doing it this way but there is never a reason to do so.
You say -- I have to do so, I've got an legacy system and I have pointers to nodes I need to put them in a heap.
Make an array of those pointers and work with them in this array as you would a standard array based heap, when you need the contents dereference them. This will work better than any other way of implementing your system.
I can think of no other reason to implement a heap using pointers.
Original Answer:
If you implement it with pointers then it is a tree. A heap is a heap because of how you can calculate the location of the children as a location in the array (2 * node index +1 and 2 * node index + 2).
So no, you can't implement it with pointers, if you do you've implemented a tree.
Implementing trees is well documented if you search you will find your answers.
I have searched around the internet (including SO) and no answer can be found.
Funny, because I found an answer on SO within moments of googling it. (Same Google search led me here.)
Basically:
The node should have pointers to its parent, left child, and right child.
You need to keep pointers to:
the root of the tree (root) (duh)
the last node inserted (lastNode)
the leftmost node of the lowest level (leftmostNode)
the rightmost node of the next-to-lowest level (rightmostNode)
Now, let the node to be inserted be nodeToInsert. Insertion algorithm in pseudocode:
void insertNode(Data data) {
Node* parentNode, nodeToInsert = new Node(data);
if(root == NULL) { // empty tree
parent = NULL;
root = nodeToInsert;
leftmostNode = root;
rightmostNode = NULL;
} else if(lastNode.parent == rightmostNode && lastNode.isRightChild()) {
// level full
parentNode = leftmostNode;
leftmostNode = nodeToInsert;
parentNode->leftChild = nodeToInsert;
rightmostNode = lastNode;
} else if (lastNode.isLeftChild()) {
parentNode = lastNode->parent;
parentNode->rightChild = nodeToInsert;
} else if(lastNode.isRightChild()) {
parentNode = lastNode->parent->parent->rightChild;
parentNode->leftChild = nodeToInsert;
}
nodeToInsert->parent = parentNode;
lastNode = nodeToInsert;
heapifyUp(nodeToInsert);
}
Pseudocode for deletion:
Data deleteNode() {
Data result = root->data;
if(root == NULL) throw new EmptyHeapException();
if(lastNode == root) { // the root is the only node
free(root);
root = NULL;
} else {
Node* newRoot = lastNode;
if(lastNode == leftmostNode) {
newRoot->parent->leftChild = NULL;
lastNode = rightmostNode;
rightmostNode = rightmostNode->parent;
} else if(lastNode.isRightChild()) {
newRoot->parent->rightChild = NULL;
lastNode = newRoot->parent->leftChild;
} else if(lastNode.isLeftChild()) {
newRoot->parent->leftChild = NULL;
lastNode = newRoot->parent->parent->leftChild->rightChild;
}
newRoot->leftChild = root->leftChild;
newRoot->rightChild = root->rightChild;
newRoot->parent = NULL;
free(root);
root = newRoot;
heapifyDown(root);
}
return result;
}
heapifyUp() and heapifyDown() shouldn’t be too hard, though of course you’ll have to make sure those functions don’t make leftmostNode, rightmostNode, or lastNode point at the wrong place.
TL;DR Just use a goddamn array.

Binary tree stack overflow

I have made a binary tree based on Alex Allain's example found here. It throws a stack overflow exception after adding about 5000-6000 elements to it. Any idea of how to prevent a stack overflow? The cause is that Insert() calls itself recursivly.
Update 3/6/2013
Here is how I refactored the code to avoid stack overflow:
void Insert(Key_T key, Value_T val, QuickMapNode<Key_T, Value_T> *leaf)
{
while (true)
if(key < leaf->key)
{
if(leaf->left) leaf = leaf->left;
else
{
leaf->left = new QuickMapNode<Key_T, Value_T>;
leaf->left->key = key;
leaf->left->val = val;
leaf->left->parent = leaf;
leaf->left->left = NULL; // Sets the left child of the child node to null
leaf->left->right = NULL; // Sets the right child of the child node to null
break;
}
}
else if (key >= leaf->key)
{
if(leaf->right) leaf = leaf->right;
else
{
leaf->right = new QuickMapNode<Key_T, Value_T>;
leaf->right->key = key;
leaf->right->val = val;
leaf->right->parent = leaf;
leaf->right->left = NULL; // Sets the left child of the child node to null
leaf->right->right = NULL; // Sets the right child of the child node to null
break;
}
}
}
Like Öö Tiib said, you should change insert to be not recursive. Every recursive function can be turned into a non-recursive one by storing the data that would go on the stack in some other data structure. This way you can use the heap for those data and don't have the overhead of function calls on the stack (return address etc.) You can often use a vector or list that you use like a stack: take (and pop) the back() of the vector to get the current argument, and in places your current code would recursively call itself, you push_back() what you would have passed to the recursive function call.
Here's the insert() method from your link as an iterative version:
void btree::insert(int key, node *leaf)
{
std::list<node*> leafs;
leafs.push_back(leaf);
while (leafs.size() > 0)
{
leaf = leafs.back();
leafs.pop_back();
if(key < leaf->key_value)
{
if(leaf->left!=NULL)
leafs.push_back(leaf->left);
else
{
leaf->left=new node;
leaf->left->key_value=key;
leaf->left->left=NULL; //Sets the left child of the child node to null
leaf->left->right=NULL; //Sets the right child of the child node to null
}
}
else if(key>=leaf->key_value)
{
if(leaf->right!=NULL)
leafs.push_back(leaf->right);
else
{
leaf->right=new node;
leaf->right->key_value=key;
leaf->right->left=NULL; //Sets the left child of the child node to null
leaf->right->right=NULL; //Sets the right child of the child node to null
}
}
}
}
I ran the code and it seems to work. It's much slower than the recursive version though, not sure why that is ... Both versions work fine with 10000 and more elements, so there's perhaps something else wrong in your implementation ...
Actually, when traversing a binary tree like we do here, there's no need to store any previous information, as we don't do any backtracking. Once the location for the new element is found, we're finished. So we can get rid of the list/vector altogether:
void btree::insert(int key, node *leaf)
{
while (leaf != NULL)
{
if(key < leaf->key_value)
{
if(leaf->left!=NULL)
leaf = leaf->left;
else
{
leaf->left=new node;
leaf->left->key_value=key;
leaf->left->left=NULL; //Sets the left child of the child node to null
leaf->left->right=NULL; //Sets the right child of the child node to null
return;
}
}
else if(key>=leaf->key_value)
{
if(leaf->right!=NULL)
leaf = leaf->right;
else
{
leaf->right=new node;
leaf->right->key_value=key;
leaf->right->left=NULL; //Sets the left child of the child node to null
leaf->right->right=NULL; //Sets the right child of the child node to null
return;
}
}
}
}
Make algorithm of insert that is not recursive. You do need only to search place where to insert so you do not need stack of calls for that.
Taking guesses due to lack of provided details: assume worst case, that after 6000 inserts the stack depth is all 6000 recursive calls. Assume a reasonable stack frame size of maybe 20 bytes - then stack size is 6000 * 20 = 120,000 bytes. If the stack frame is actually 160 bytes (8x larger) then the stak size is 6000 * 160, slightly less than 1MB. I wonder ... is there a limit on your number of elements? What is the allocated stack size?
The comments above tell you how to actually solve the problem (balanced tree). I might add, just about any recursive algorithm can be converted to an iterative algorithm - it isn't as elegant and it will take effort to get it right, but then you won't fill up the stack. But if there really is (not just you think there is) a limit on the number of input elements, then it seems to me you could determine the size of the stack frame for insert and make the stack size large enough to fit #elements * stack frame size, the worst case, plus a little more for whatever extra is on the stack.
As mentioned above the most likely cause is the stack overflow due to too many recursive insert calls
The following are the different options
Use a self balancing tree http://en.wikipedia.org/wiki/Self-balancing_binary_search_tree
Use a non recursive tree decent algorithmn.Lookk at this example Non-recursive add function in a binary tree using c++

Inserting into an Array Based Binary Search Tree? C++

Im trying to insert into an array Based Binary Search tree.
I am not sure how i prevent overwriting data using left and right indexes...
Do i insert leftchild as tree[2 * i + 1] and rightchild as tree[2 * i + 2] ? I think it is for locating the position of a node given its name...
Thats my problem. Not knowing how to insert, recursively or iteratively(ive chosen recursively but it might be totally wrong).
BST::BST(int capacity) : items(new item[capacity]), size(0),
leftChild(0), rightChild(0), root_index(1)
{
items->empty = true;
maxSize = capacity-1;
}
Below is the insertion function. I have seen many that deal with Linked Lists implementations, But nothing array based! Here is my attempt:
void BST::insert(const data& aData)
{
if ( items[root_index].empty )
{
items[root_index].theData = aData;// Get the data.
items[root_index].empty = false;
oldRoot.theData = aData;
}
else
{
if ( aData < items[root_index].theData )
{
leftChild = root_index * 2;
if ( items[leftChild].empty )
{
items[leftChild].theData = aData;
items[leftChild].empty = false;
}//items->empty = true;
else
{
items[root_index].theData = items[leftChild].theData;
this->insert(aData);
}
}
else if ( items[root_index].theData < aData )
{
rightChild = root_index * 2 + 1;
if ( items[rightChild].empty )
{
items[rightChild].theData = aData;
items[rightChild].empty = false;
}
else//items->empty = true;
{
items[root_index].theData = items[rightChild].theData;
this->insert(aData);
}
}
else return;
}
items[1].theData = oldRoot.theData;
}
What is correct?...Does anyone have any array based suggstions for inserting? I appear to be stuck in an infinite recursion
First have a look at what is the
algorithm for inserting into BST
(don't care about how it is
implemented for arrays ...)
Once you understand how to insert, look at how you select left/right child of the current node and replace the algorithm with the way you need to access nodes in array based BST, meaning your (left,right) --> [2*i + 1],[2*i + 2] ... This calculation gives you the location of the node in the array
Have a look at the BST description at wikipedia, and the following example:
/* Inserts the node pointed to by newNode into the subtree rooted at treeNode */
void InsertNode(Node* &treeNode, Node *newNode)
{
if (treeNode == NULL)
treeNode = newNode;
else if (newNode->key < treeNode->key)
InsertNode(treeNode->left, newNode);
else
InsertNode(treeNode->right, newNode);
}
Replace the way nodes and values are accessed in array, meaning replace treeNode->key, treeNode->left,treeNode->right with how you would access children nodes and the value in array (calculating the indexes of where in the array you store the values).
You will probably not need to pass Node* around because you'll be operating on an array, and probably you can pass around index to the current node and then just add to it to get the index for left/right children.
Btw (1), if it is array based it is probably not supposed to grow in memory, you create fixed size array at the beginning that is big enough to hold your elements and then you insert your elements into appropriate indexes of that array.
Btw (2), where did you get that comparison tree that you trying to achieve? How can Z be on left path from R? If you insert according to the same algorithm when you insert Z when R is already in tree you do (Z < R ? go left : go right) so Z would end up on right path from the root R (same as when you inserted the first A after R: (A < R ? go left : go right) you ended up inserting A on the left path ...)
Btw (3), it is correct as others mentioned, the final tree depends here on the order of insertion. The most inefficient way of generating tree would be to order elements and insert one by one because you would end up with linked list so traversal would take O(n) instead of O(logN). So if you have fixed set of elements you either pick random or consistently middle element.
I take it, then, that you want to be able to use elements in the array without having to re-arrange the array when you insert a new element?
Clearly, you would want to put the tree's root node at index zero. After that, you could use the path of descent to construct a number in binary. For instance, going down the tree left-left-right-left would give you the number 0b1011 = 11. (I used 1 for left and 0 for right) Add 1 to that, so this node would go at index 12. To descend further in the tree, use a logical or with the direction of descent.
If you want to lay out a complete binary tree in an array, i_left=i_parent*2 and i_right=i_parent*2+1 works well (with i_root=1). BST are supposed to be efficiently updatable by modifying only the nodes along the path from the root to another node in the tree; location-independent explicit left and right subchild pointers (or indices) allow this, because shifting the location (or reuse of) of a subtree doesn't require a deep copy.
The only way it makes sense to have a packed binary search tree (with fixed locations for left and right subtrees based on parent's index, as above) is if the set is fixed; sort it and recurse, grabbing the middle of the sorted subrange and using it as the root of your BST-subtree.