Minimum heap - DecreaseKey function - heap

Here are two different implementations of the function DecreaseKey for a Minimum-Heap structure.
DecreaseKey gets the minimum-heap array, the index of a node in that heap, and the new value to be assigned to that node. It is assumed that the new value is not greater than the node's current value. The heap property is restored if necessary.
DecreaseKey(A, i, val) -
While (i > 1 and A[parent(i)] > val):
A[i] = A[parent(i)]
i = parent(i)
A[i] = val
DecreaseKey(A, i, val) -
A[i] = val
While (i > 1 and A[parent(i)] > A[i]):
Swap(&A[i], &A[parent(i)])
i = parent(i)
My question is - are these algorithms equivalent? Or is one of them logically wrong?
Is the result of both of them the same for every given input and every given minimum-heap?

Both are equivalent, while the first will run faster in general.
While the second version will move val from the child to the parent slot in each iteration, the second version will wait with moving val until it is clear which its final spot is, and will only then store it there.

Related

In C++ is there any way to apply a function 'simultaneously' to all the elements of a vector ?

I have a vector of length 6, with elements either 1 or zero. I want to apply 'XOR' on 2 elements on both sides of every ith element. e.g. for i = 1, I'll apply xor on 0th and 2nd element. the ith element is then replaced by this xor output. I want to apply xor for all such 'i's simultaneously on the original vector. Is there any way I can achieve this without using another vector?
When you say "simultaneously", you mean that one XOR operation should not use the intermediate data from the previous XOR operation but the data from the original vector, right? In that case, since each step obliterates information (the previous state of element i is overwritten with the result), you can not do that without at least some intermediate storage. However, you only obliterate one bit of information and that information is only required in the next step, so you don't need a complete additional vector.
use a temporary variable to store previous item:
bool prev = vec[0];
for(int i = 1; i < vec.size() - 1; i++){
bool result = vec[i + 1] ^ prev;
prev = vec[i];
vec[i] = result;
}

Intuition behind incrementing the iteration variable?

I am solving a question on LeetCode.com:
Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue. Here, they use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. [The trivial counting sort cannot be used].
For the input: [2,0,2,1,1,0]; the output expected is: [0,0,1,1,2,2].
One of the highly upvoted solutions goes like this:
public void sortColors(vector<int>& A) {
if(A.empty() || A.size()<2) return;
int low = 0;
int high = A.size()-1;
for(int i = low; i<=high;) {
if(A[i]==0) {
// swap A[i] and A[low] and i,low both ++
int temp = A[i];
A[i] = A[low];
A[low]=temp;
i++;low++;
}else if(A[i]==2) {
//swap A[i] and A[high] and high--;
int temp = A[i];
A[i] = A[high];
A[high]=temp;
high--;
}else {
i++;
}
}
}
My question is, why is i incremented when A[i]==0 and A[i]==1 and not when A[i]==2? Using pen and paper, the algorithm just works to give me the answer; but could you please provide some intuition?
Thanks!
This steps through the array and maintains the constraint that the elements 0..i are sorted, and all either 0 or 1. (The 2's that were there get swapped to the end of the array.)
When A[i]==0, you're swapping the element at i (which we just said was 0) with the element at low, which is the first 1-element (if any) in the range 0..i. Hence, after the swap, A[i]==1 which is OK (the constraint is still valid). We can safely move forward in the array now. The same is true if A[i]==1 originally, in which case no swap is performed.
When A[i]==2, you're essentially moving element i (which we just said was 2) to the end of the array. But you're also moving something from the end of the array into element i's place, and we don't know what that element is (because we haven't processed it before, unlike the A[i]==0 case). Hence, we cannot safely move i forward, because the new element at A[i] might not be in the right place yet. We need another iteration to process the new A[i].
That is, because for 0s and 1s, only items left of the current item are handled and those have already been reviewed / sorted. Only for 2s items from the right end of the array are handled, which haven't been looked at yet.
To be more specific: In this specific example only three different states are handled:
the current item being reviewed equals 0: in this case this sorting algorithm just puts this item at the end of all zeros, which have already been sorted (aka A[low]). Also the item which was at A[low] before can only be a 0 or 1 (since they have already sorted) which means you can just swap with the current item and not break the sequence. Now the interesting part: up until now, every item from A[0] over A[low] to A[i] has been already sorted, so the next item which has to be reviewed will be A[i + 1], hence the i++
the current item equals 1: in this case, no swapping has to be done, since all 0s and 1s has already been put in A[0] to A[i - 1] and all 2s have already been put at the end of the array. That means, the next item to be reviewed is A[i + 1], hence the i++
the current item equals 2: in this case, the current item will be put at the end of the array, next to (i.e., to the left of) all the other already sorted 2s (A[high]). The item, which will be swapped from A[high] to A[i] has not been sorted yet and therefor has to be reviewed in the next step, hence th i = i;

Convert linked list into binary search tree, do stuff and return tree as list

I have the following problem:
I have a line with numbers that I have to read. The first number from the line is the amount of operations I will have to perform on the rest of the sequence.
There are two types of operations I will have to do:
Remove- we remove the number after the current one, then we move forward X steps in the sequence, where X=value of removed element)
Insert- we insert a new number after the current one with a value of (current element's value-1), then we move forward by X steps in the sequence where X = value of the current element (i.e not the new one)
We do "Remove" if the current number's value is even, and "Insert" if the value is odd.
After the amount of operations we have to print the whole sequence, starting from the number we ended the operations.
Properly working example:
Input: 3 1 2 3
Output:0 0 3 1
3 is the first number and it becomes the OperCount value.
First operation:
Sequence: 1 2 3, first element: 1
1 is odd, so we insert 0 (currNum's value-1)
We move forward by 1(currNum's value)
Output sequence: 1 0 2 3, current position: 0
Second operation:
0 is even so we remove the next value (2)
Move forward by the removed element's value(2):
From 0 to 3
From 3 to 1
Output sequence: 1 0 3, current position: 1
Third operation:
1 is even, so once again we insert new element with value of 0
Move by current element's value(1), onto the created 0.
Output sequence: 1 0 0 3, current position: first 0
Now here is the deal, we have reached the final condition and now we have to print whole sequence, but starting from the current position.
Final Output:
0 0 3 1
I have the working version, but its using the linked list, and because of that, it doesn't pass all the tests. Linked list traversal is too long, thats why I need to use the binary tree, but I kinda don't know how to start with it. I would appreciate any help.
First redefine the operations to put most (but not all) the work into a container object: We want 4 operations supported by the container object:
1) Construct from a [first,limit) pair of input random access iterators
2) insert(K) finds the value X at position K, inserts a X-1 after it and returns X
3) remove(K) finds the value X at position K, deletes it and returns X
4) size() reports the size of the contents
The work outside the container would just keep track of incremental changes to K:
K += insert(K); K %= size();
or
K += remove(K); K %= size();
Notice the importance of a sequence point before reading size()
The container data is just a root pointing to a node.
struct node {
unsigned weight;
unsigned value;
node* child[2];
unsigned cweight(unsigned s)
{ return child[s] ? child[s]->weight : 0; }
};
The container member functions insert and remove would be wrappers around recursive static insert and remove functions that each take a node*& in addition to K.
The first thing each of either recursive insert or remove must do is:
if (K<cweight(0)) recurse passing (child[0], K);
else if ((K-=cweight(0))>0) recurse passing (child[1], K-1);
else do the basic operation (read the result, create or destroy a node)
After doing that, you fix the weight at each level up the recursive call stack (starting where you did the work for insert or the level above that for remove).
After incrementing or decrementing the weight at the current level, you may need to re-balance, remembering which side you recursively changed. Insert is simpler: If child[s]->weight*4 >= This->weight*3 you need to re-balance. The re-balance is one of the two basic tree rotations and you select which one based on whether child[s]->cweight(s)<child[s]->cweight(1-s). rebalance for remove is the same idea but different details.
This system does a lot more worst case re-balancing than a red-black or AVL tree. But still is entirely logN. Maybe there is a better algorithm for a weight-semi-balanced tree. But I couldn't find that with a few google searches, nor even the real name of nor other details about what I just arbitrarily called a "weight-semi-balanced tree".
Getting the nearly 2X speed up of strangely mixing the read operation into the insert and remove operations, means you will need yet another recursive version of insert that doesn't mix in the read, and is used for the portion of the path below the point you read from (so it does the same recursive weight changes and re-balancing but with different input and output).
Given random access input iterators, the construction is a more trivial recursive function. Grab the middle item from the range of iterators and make a node of it with the total weight of the whole range, then recursively pass the sub ranges before and after the middle one to the same recursive function to create child subtree.
I haven't tested any of this, but I think the following is all the code you need for remove as well as the rebalance needed for both insert and remove. Functions taking node*& are static member function of tree and those not taking node*& are non static.
unsigned tree::remove(unsigned K)
{
node* removed = remove(root, K);
unsigned result = removed->value;
delete removed;
return result;
}
// static
node* tree::remove( node*& There, unsigned K) // Find, unlink and return the K'th node
{
node* result;
node* This = There;
unsigned s=0; // Guess at child NOT removed from
This->weight -= 1;
if ( K < This->cweight(0) )
{
s = 1;
result = remove( This->child[0], K );
}
else
{
K -= This->cweight(0);
if ( K > 0 )
{
result = remove( This->child[1], K-1 );
}
else if ( ! This->child[1] )
{
// remove This replacing it with child[0]
There = This->child[0];
return This; // Nothing here/below needs a re-balance check
}
else
{
// remove This replacing it with the leftmost descendent of child[1]
result = This;
There = This = remove( This->child[1], 0 );
This->child[0] = Result->child[0];
This->child[1] = Result->child[1];
This->weight = Result->weight;
}
}
rebalance( There, s );
return result;
}
// static
void tree::rebalance( node*& There, unsigned s)
{
node* This = There;
node* c = This->child[s];
if ( c && c->weight*4 >= This->weight*3 )
{
node* b = c->child[s];
node* d = c->child[1-s];
unsigned bweight = b ? b->weight : 0;
if ( d && bweight < d->weight )
{
// inner rotate: d becomes top of subtree
This->child[s] = d->child[1-s];
c->child[1-s] = d->child[s];
There = d;
d->child[s] = c;
d->child[1-s] = This;
d->weight = This->weight;
c->weight = bweight + c->cweight(1-s) + 1;
This->weight -= c->weight + 1;
}
else
{
// outer rotate: c becomes top of subtree
There = c;
c->child[1-s] = This;
c->weight = This->weight;
This->child[s] = d;
This->weight -= bweight+1;
}
}
}
You can use std::set which is implemented as binary tree. It's constructor allows construction from the iterator, thus you shouldn't have problem transforming list to the set.

Heap sort, Understanding the basics

As a disclaimer I am new to this site and therefore, do not know very well how to ask questions. Please don't be too harsh because I really am trying to just understand how some of these concepts work. If i am missing understanding near the beginning, please just tell me that so I can start from there and not waste your time with the rest. Here goes nothing. Because I think my understanding might be flawed, I poised some questions about how heaps would act in different areas, and then tried to answer them.
First, I would like help understanding how a random set of numbers added to an empty heap would look. lets say for example, I have 9, 4, 5, 3, 2, 7, 8, 7. After adding it to the heap, what would the heap look like? I can visually understand this (I think) the 9 being the root, 4 being the first left child and so on and so forth, but since this isn't a tree specifically, and is a heap, would it sort the numbers by switching them (see paragraph "if my understanding is correct") so that they are sorted in either min or max order?
Now lets say we removed the 9 from the heap (I believe the 9 would be the root), how would we respond to this change and then what would then be put into the root? I think here if 9 is the root, we would take the next largest number and copy it into the slot of the nine, while if this was a min heap and we where just removing a node at the bottom, it would just be removed no problem.
Along similar lines, what would a formula to get the parent of the heap item in the array?
--I think I understand this, If parent is at i, the left child would be at i*2 and the right child would be at i*2+1. And therefore going to find the parent, we would have to divide i/2 to find the parent. For example if we where at i=7 the parent would be i=3 because 3.5 would be truncated and if we where at point i=6 the parent would also be i=3. From this example the child at i = 7 would be right child of i = 3 while i=6 would be the left child of i = 3.
If my understanding of this is correct, then to reheapify after a new term has been added to the root I would compare the child to parent and if the child is larger, switch the terms. BUT I would need to compare the two children (if there are two) to see which one is bigger to decide which one needs to swap. This would be for a max heap and would go the other direction for a min heap.
Finally, if I where to add the root element, how would it reheapify?
After 9 is deleted, nothing becomes the root. The heapsort algorithm goes to the left child for sorting (you said 4.) Then the right child (or 5), etc. If the number is being checked is the root (we have different implementations) then 4 becomes the root, then 5, etc. If you are confused, look at this definition of heapsort, written in javascript:
var heapSort = function(array) {
var swap = function(array, firstIndex, secondIndex) {
var temp = array[firstIndex];
array[firstIndex] = array[secondIndex];
array[secondIndex] = temp;
};
var maxHeap = function(array, i) {
var l = 2 * i;
var r = l + 1;
var largest;
if (l < array.heapSize && array[l] > array[i]) {
largest = l;
} else {
largest = i;
}
if (r < array.heapSize && array[r] > array[largest]) {
largest = r;
}
if (largest !== i) {
swap(array, i, largest);
maxHeap(array, largest);
}
};
var buildHeap = function(array) {
array.heapSize = array.length;
for (var i = Math.floor(array.length / 2); i >= 0; i--) {
maxHeap(array, i);
}
};
buildHeap(array);
for (var i = array.length-1; i >= 1; i--) {
swap(array, 0, i);
array.heapSize--;
maxHeap(array, 0);
}
array.heapMaximum = function(){
return this[0];
};
array.heapExtractMax = function(){
if(this.heapSize < 1){
throw new RangeError("heap underflow");
}
var max = this[0];
this[0] = this[this.heapSize - 1];
this.heapSize--;
maxHeap(this, 1);
return max;
};
array.heapIncreaseKey = function(i, key){
if(key < this[i]){
throw new SyntaxError("new key is smaller than current key");
}
this[i] = key;
while(i > 1 && this[Math.floor(i / 2)] < this[i]){
swap(this, i, Math.floor(i / 2));
i = Math.floor(i / 2);
}
};
array.maxHeapInsert = function(key){
this.heapSize--;
this[this.heapSize] = -Infinity;
this.heapIncreaseKey(this.heapSize, key);
};
};
var a = [Math.floor(Math.random() * 100), Math.floor(Math.random() * 100), Math.floor(Math.random() * 100), Math.floor(Math.random() * 100), Math.floor(Math.random() * 100)];
heapSort(a);
document.writeln(a);
*{
font-family:monospace;
}
I actually don't know how it would reheapify, but you can see the snippet to find out.
To begin with your first question about how the heap would look. It will take on the structure of a complete binary tree. We could just walk down the list and update the tree as we see it but this will ruin the run time so there is a more clever way to do it. We want to first start by linearly going through the array and adding it to the left most open slot where the first entry in the array is the root. Then once you have an array, we want to fix the heap from the ground up. This involves looking at the highest depth of the heap and fixing it by making a swap so that the minimum is the parent. Then move up one in the depth of the tree and make the swap if either child is less than the new parent. If this is true then make the swap, however we may have broken the min property and so we must recursively move down the heap to fix the property. Once we recursively move towards the top and fix the heap at the top then we will have made the min Heap desired. Note that through some nice algebra, we can show that this will run in O(n) time.
The second question about removing 9 is not correct (as it is not the root anymore) so let's focus on removing the root node. When the root node is removed (from the tree or the first entry of the array) then we need to place something there for the tree structure and we place the left most node of the tree or the last element in the array, but as you might be thinking, this may have ruined the min-property and you are right. So once you move the left most to the root node, we have to check its children and if it is smaller than both, then we are good. Otherwise, we need to swap with the smaller and repeat this for the next set of children until it is smaller than both its children.
In an array, it is correct that we use 2i and 2i+1 as the index so just dividing by 2 will not be sufficient. We note that 2i is even and 2i+1 is odd and so we should focus on whether the index we are looking at is even or odd. However, it is correct that truncating would given the correct answer for the parent and that the decimal would result in the decision for the left and right child.
To address your final concern, we should note that when you add something to a heap that it is a complete binary tree and should be added to the left most slot and not the root. When you add something to the left most (for a min heap), we need to check if it is smaller than its parents and move it towards the root.
Additionally, building your heap with O(n) is efficient when needing to run prim's algorithm or Dijkstra's Shortest Path Algorithm.
Hope this helps - Jason

How to implement a minimum heap sort to find the kth smallest element?

I've been implementing selection sort problems for class and one of the assignments is to find the kth smallest element in the array using a minimum heap. I know the procedure is:
heapify the array
delete the minimum (root) k times
return kth smallest element in the group
I don't have any problems creating a minimum heap. I'm just not sure how to go about properly deleting the minimum k times and successfully return the kth smallest element in the group. Here's what I have so far:
bool Example::min_heap_select(long k, long & kth_smallest) const {
//duplicate test group (thanks, const!)
Example test = Example(*this);
//variable delcaration and initlization
int n = test._total ;
int i;
//Heapifying stage (THIS WORKS CORRECTLY)
for (i = n/2; i >= 0; i--) {
//allows for heap construction
test.percolate_down_protected(i, n);
}//for
//Delete min phase (THIS DOESN'T WORK)
for(i = n-1; i >= (n-k+1); i--) {
//deletes the min by swapping elements
int tmp = test._group[0];
test._group[0] = test._group[i];
test._group[i] = tmp;
//resumes perc down
test.percolate_down_protected(0, i);
}//for
//IDK WHAT TO RETURN
kth_smallest = test._group[0];
void Example::percolate_down_protected(long i, long n) {
//variable declaration and initlization:
int currPos, child, r_child, tmp;
currPos = i;
tmp = _group[i];
child = left_child(i);
//set a sentinel and begin loop (no recursion allowed)
while (child < n) {
//calculates the right child's position
r_child = child + 1;
//we'll set the child to index of greater than right and left children
if ((r_child > n ) && (_group[r_child] >= _group[child])) {
child = r_child;
}
//find the correct spot
if (tmp <= _group [child]) {
break;
}
//make sure the smaller child is beneath the parent
_group[currPos] = _group[child];
//shift the tree down
currPos = child;
child = left_child(currPos);
}
//put tmp where it belongs
_group[currPos] = tmp;
}
As I stated before, the minimum heap part works correctly. I understand what I what to do- it seems easy to delete the root k times but then after that what index in the array do I return... 0? This almost works- it doesn't worth with k = n or k = 1.Would the kth smallest element be in the Any help would be much appreciated!
The only array index which is meaningful to the user is zero, which is the minimum element. So, after removing k elements, the k'th smallest element will be at zero.
Probably you should destroy the heap and return the value rather than asking the user to concern themself with the heap itself… but I don't know the details of the assignment.
Note that the C++ Standard Library has algorithms to help with this: make_heap, pop_heap, and nth_element.
I am not providing a detailed answer, just explaining the key points in getting k smallest elements in a min-heap ordered tree. The approach uses skip lists.
First form a skip list of nodes of the tree with just one element the node corresponding to the root of the heap. the 1st minimum element is just the value stored at this node.
Now delete this node and insert its child nodes in the right position such that to maintain the order of values. This steps takes O(logk) time.
The second minimum value is just then the value at first node in this skip list.
Repeat the above steps until you get all the k minimum elements. The overall time complexity will be log(2)+log(3)+log(4)+... log(k) = O(k.logk). Forming a heap takes time n, so overall time complexity is O(n+klogk).
There is one more approach without making a heap that is Quickselect, which has an average time complexity of O(n) but worst case as O(n^2).
The striking difference between the two approaches is that the first approach gives all the k elements the minimum upto the kth minimum, while quickSelect gives only the kth minimum element.
Memory wise the former approach uses O(n) extra space which quickSelect uses O(1).