Implementing a heap: becomes inaccurate after one sift - java

I am currently trying to write a program that takes an array and makes it into a heap.
I am trying to implement a siftDown method that will take the elements of the array and make them into a heap but i am just not getting the correct output i want and im not sure why:
public void makeHeap(int[] arr)
{
for(int i = 0; i <= arr.length; i++)//for each element in the array, we we check its children and sift it down
{
siftDown(arr, i);
}
}
//insert a new root in the correct position. Byu comparing the top element and swapping it with its largest child.
public void siftDown(int[]heap, int i)
{
int c = i * 2; //grab the children of the current index we are at.
if(c == 0) // 0*2 is 0 so we make it 1 so it will register the first nodes parents
{
c+=1;
}
if(c >= heap.length || c+1 >= heap.length) // so we dont go off the end of the array
{
return;
}
if(heap[c] < heap[c + 1]) //Is child 1 less than child 2?
{
c += 1; //if it is we want c to be the greater child to eventually move upwards
}
if(heap[i] < heap[c])//If the parent we have just gotten is smaller than the child defined last loop, then we swap the two. We then call sift down again to compare child and parent.
{
heap = swap(heap,i,c);//swap the values
siftDown(heap, c);//call again to compare the new root with its children.
}
}
Here is my swap method:
public int[] swap(int[]heap, int i, int c)
{
//capture the two values in variables
int ele1 = heap[i];
int ele2 = heap[c];
heap[i] = ele2;//change heap i to heap c
heap[c] = ele1;//change heap c to heap i
return heap;
}
The starting numbers are: 4,7,9,6,3,1,5
. The output i want to get is 9,7,5,6,3,1,4 but i seem to only be able to get 9,7,4,6,3,1,5. It seems once 4 gets sifted down once after being replaced by 9, the algorithm goes out of wack and it believes that 3 and 1 are its children when 1,5 should be.
Thank you or your help!

int c = i * 2; //grab the children of the current index we are at.
if(c == 0) // 0*2 is 0 so we make it 1 so it will register the first nodes parents
{
c+=1;
}
This looks wrong to me.
The heap indices for children should be a general formula that works for all cases.
Given parentIdx in 0-based array,
leftChildIdx = parentIdx * 2 + 1
rightChildIdx = parentIdx * 2 + 2
This means children of 0 are 1 and 2, children of 1 are 3 and 4, children of 2 are 5 and 6, etc. It works.
Your code places children of 1 at 2 and 3, which is clearly wrong.

Related

How to add and restore a heap?

In a problem, we were supposed to remove four (4) elements from this maxHeap (see image below), and every time an element was removed, the heap property had to be restored. The list with the remaining heap elements had to be in level-order.
public class HeapSort {
public static void heapify(int node[], int n, int i) {
int largest = i, // Initialize largest as root
l = 2 * i + 1, // Left = 2*i + 1
r = 2 * i + 2; // Right = 2*i + 2
if (l < n && node[l] > node[largest]) {
largest = l; // If left child is larger than root (n = size of heap)
}
if (r < n && node[r] > node[largest]) {
largest = r; // If right child is larger than largest
}
if (largest != i) {
int swap = node[i];
node[i] = node[largest]; // If largest is not root
node[largest] = swap;
heapify(node, n, largest); // Recursively heapify the affected sub-tree
}
}
/**
* Deletes the root from the Heap.
*/
public static int deleteRoot(int node[], int n) {
int lastElement = node[n - 1]; // Get the last element
node[0] = lastElement; // Replace root with first element
n -= 1; // Decrease size of heap by 1
heapify(node, n, 0); // Heapify the root node
return n; // Return new size of Heap
}
/**
* A utility function to print array of size N
*/
public static void printArray(int array[], int n) {
System.out.print("_ ");
for (int i = 0; i < n; ++i) {
System.out.print(array[i] + " ");
}
}
public static void main(String args[]) {
// Insert values representing the Heap.
int node[] = {65, 55, 60, 45, 25, 40, 50, 10, 35, 15, 20, 30};
int n = node.length,
removes = 4; // Insert the number of elements you want to delete (e.g.: 4).
for(int i = 0; i < removes; i++) {
n = deleteRoot(node, n);
}
printArray(node, n);
}}
This code gave me this answer, which is correct according to my quiz:
_ 45 35 40 20 25 15 30 10
My problem is when adding to the heap, with the following challenge: Build a minHeap by adding the following seven elements in the order in which they are listed to the heap above. Every time an element is added, the heap property needs to be restored.
Numbers to be added to the heap:
30 75 35 15 70 20 10
When you are done, list the elements in level-order. Include a leading underscore to indicate that the element on index 0 is not used.
Disclaimer: this, as mention, WAS a quiz and therefore you wouldn't be doing my assignment. I am just curious. Maybe I should use PriorityQueue... I've been trying, but I am not getting anywhere.
As you have already implemented, a deletion works as follows:
Delete the last node and put its value in the root node
Sift down the root's value until the heap property is restored (implemented in heapify)
Insertion works in the other direction:
Append the node with the new value at the end
Sift up that value until the heap property is restored.

Why doesn't my search algorithm work for Project Euler 31?

Problem 31
In England the currency is made up of pound, £, and pence, p, and
there are eight coins in general circulation: 1p, 2p, 5p, 10p, 20p,
50p, £1 (100p) and £2 (200p). It is possible to make £2 in the
following way: 1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p How many
different ways can £2 be made using any number of coins?
static int[] nums = {200,100,50,20,10,5,2,1};
static int size = nums.length;
static HashMap<Integer,Integer> pivots = new HashMap<>();
public static int checkSum(HashMap<Integer,Integer> pivots){
int target = 200;
int sum = 0;
for(Integer key: pivots.keySet()){
int pivot = pivots.get(key);
sum += nums[pivot];
if(sum > target) return 1;
}
if(sum < target) return -1;
return 0;
}
public static void shift(HashMap<Integer,Integer> pivots, int pivot_node){
if(pivots.size() + nums[pivots.get(1)] == 201 && pivots.get(1) != 0){
int p_1_value = pivots.get(1); //this part checks whether the current node(which is the first node)
//has reached children of all 1.
//Which means it's time to shift the root node.
pivots.clear();
pivots.put(1 , p_1_value);
shift(pivots, 1);
return;
}
if(pivots.get(pivot_node) != size - 1) {
pivots.put(pivot_node, pivots.get(pivot_node) + 1);
}
else{
shift(pivots , pivot_node - 1);
}
}
public static void branch(HashMap<Integer,Integer> pivots){
pivots.put(pivots.size() + 1, pivots.get(pivots.size()));
}
public static int search(){
int bool = checkSum(pivots);
int n = 0;
int count = 0;
while(n < 25) {
count++;
if (bool == 0) {
n++; // if the sum is equal to 200, we shift the last
//pivot to the next lower number.
shift(pivots, pivots.size());
}else if (bool == -1) {
branch(pivots); //if the sum is less than 200, we make a new pivot with value of the last pivot.
}else if (bool == 1) {
shift(pivots, pivots.size()); //if the sum is greater than 200,
//we shift to the last pivot to the next lower number.
}
bool = checkSum(pivots);
}
return n;
}
public static void main(String[] args){
pivots.put(1,0);
int n = search();
System.out.print("\n\n------------\n\n"+ "n: " + n);
}
This is an algorithm that searches for combinations of a set that add up to a target. It's kind of like a depth first tree search without using a tree. Each pivot represents node on the "tree". The shift() method changes the value of the node to the next lower value. The branch() method creates a new node with the same value of the last node. The checkSum() method checks whether the sum of the pivots are <,= or > the target, 200.
The correct answer for the number of ways is supposed to be around 73000. But my algorithm only returns about 300 ways.
I have no idea why this happens because my algorithm should reach every single possible combination that equals 200.
This is a visualization of how my algorithm works:
Your search algorithm doesn't find all possible combinations of coins that make up £2 because you are only shifting the "last pivot" to the next lower number, when you should be considering the items before that last one too.
Your algorithm will find this combination:
100, 50, 20, 20, 5, 2, 2, 1
but not this:
100, 20, 20, 20, 10, 5, 2, 2, 1
The second combination does not have the value 50 in it, but your algorithm breaks down the coin values backwards to forwards only -i.e. it will never break down 50 until all the following "pivots" are 1. You can easily see that if you print your HashMap<Integer,Integer> pivots every time the counter n is incremented.
You could try to fix your code by amending it to shift() using not only the last pivot but all the distinct previous pivots too. However, doing so you will create a lot of duplicates, so you'll need to keep a list of the distinct found combinations.
Another way to solve problem 31 is by using Dynamic Programming. Dynamic programming is best when it comes to problems that can be broken down in smaller bits. For example the solution of the same problem but where
target = 2 can be used to solve the problem where target = 5, which can be used to solve the problem where target = 10 and so on.
Good luck!

Finding a single path from any node on a graph to a specific node

Some more background on the question.
Line 1 from A, goes to B. Line 2 from A goes to C.
Line 1 from B, goes to A. Line 2 from B goes to C.
Line 1 from C, goes to B. Line 2 from C goes to A.
Suppose you are lost at one of the stations A, B, or C. Independent of
where you are, if you take line 2, and then line 1, you always end up at station
B. Having a path that takes everyone to the same place is called a meeting path.
We are interested in finding a meeting path which consists of a fixed set of
instructions like, 'take line 1, then line 2,' etc. It is possible that you might
visit a station multiple times. It is also possible that such a path might not exist.
I was thinking of using a Depth First Search on the graph to find each node. However because you can repeat nodes I was not sure when I should stop the search and say that there is no path.
Is there a better way to finding paths in a cyclical Directed graph than DFS?
Once I have a given path to test this is my current implementation.
public static int calculate(int[][] n, List<Integer> list){
boolean flag = false;
int list_counter = 0;
mapEven.clear();
mapOdd.clear();
for(int i = 0; i<n.length;i++){
int item = list.get(0);
mapOdd.put(i, 1);
}
for(int x = 0; x < list.size() && !flag;x++){
for(int i = 0; i < n.length ; i++){
int station = path(n,i,list.get(x));
if (station == -1){
continue;
}
int old_station_amount;
if(x%2==1){
old_station_amount = mapEven.getOrDefault(i,0);
mapOdd.put(station, old_station_amount+mapOdd.getOrDefault(station,0));
}else{
old_station_amount = mapOdd.getOrDefault(i,0);
mapEven.put(station, old_station_amount+mapEven.getOrDefault(station,0));
}
}
if(x%2==1){
mapEven.clear();
}else{
mapOdd.clear();
}
if(mapEven.values().contains((Integer) n.length) ||mapOdd.values().contains((Integer) n.length)){
return -1;
}
}
if(mapEven.values().contains((Integer) n.length) ||mapOdd.values().contains((Integer) n.length)){
return -1;
}else{
return -3;
}
}

Heapify function not working

I have been trying to write a recursive heapify method that turns an array of integers into a min-heap. The Main and Heap classes are shown below. Most of the array shown in Main is already a min-heap, but the subtree [11, 4, 5] is not a min-heap. However, the heapify function doesn't seem to reach that subtree. I can't figure out what the problem is, any help would be greatly appreciated.
public class Heap {
public Heap(int[] array) {
heap = array;
}
public void heapify() {
heapifyHelper(0);
}
public void heapifyHelper(int rootIndex) {
if(isLeafIndex(rootIndex)) {
return;
}
else {
int leftChildIndex = getLeftChildIndex(rootIndex);
int rightChildIndex = getRightChildIndex(rootIndex);
int leftChildValue = heap[leftChildIndex];
int rightChildValue = heap[rightChildIndex];
int rootValue = heap[rootIndex];
if(leftChildValue < rootValue && leftChildValue < rightChildValue) {
swap(rootIndex, leftChildIndex);
heapifyHelper(leftChildIndex);
heapifyHelper(rightChildIndex);
}
else if(rightChildValue < rootValue && rightChildValue < leftChildValue) {
swap(rootIndex, rightChildIndex);
heapifyHelper(leftChildIndex);
heapifyHelper(rightChildIndex);
}
}
}
public int getLeftChildIndex(int parentIndex) {
return 2 * parentIndex + 1;
}
public int getRightChildIndex(int parentIndex) {
return 2 * parentIndex + 2;
}
public int getParentIndex(int childIndex) {
if(childIndex == 0) {
throw new IllegalArgumentException("Cannot get the parent index of the root.");
}
else {
return (childIndex / 2) - 1;
}
}
public boolean isLeafIndex(int index) {
int leftIndex = getLeftChildIndex(index);
int rightIndex = getRightChildIndex(index);
if(leftIndex >= heap.length && rightIndex >= heap.length) {
return true;
}
else {
return false;
}
}
public void swap(int index1, int index2) {
int temp = heap[index1];
heap[index1] = heap[index2];
heap[index2] = temp;
}
public void printHeap() {
System.out.println(Arrays.toString(heap));
}
int[] heap;
}
public class Main {
public static void main(String[] args) {
int[] x = {0, 5, 2, 9, 11, 6, 12, 21, 32, 4, 5};
Heap heap = new Heap(x);
heap.printHeap();
heap.heapify();
heap.printHeap();
}
}
There are several problems in your heapifyHelper:
public void heapifyHelper(int rootIndex) {
if(isLeafIndex(rootIndex)) {
return;
}
else {
int leftChildIndex = getLeftChildIndex(rootIndex);
int rightChildIndex = getRightChildIndex(rootIndex);
int leftChildValue = heap[leftChildIndex];
int rightChildValue = heap[rightChildIndex];
What if leftChildIndex == heap.length - 1? Then rightChildValue will cause an ArrayIndexOutOfBoundsException.
int rootValue = heap[rootIndex];
if(leftChildValue < rootValue && leftChildValue < rightChildValue) {
swap(rootIndex, leftChildIndex);
heapifyHelper(leftChildIndex);
heapifyHelper(rightChildIndex);
}
else if(rightChildValue < rootValue && rightChildValue < leftChildValue) {
What if both children are equal, and smaller than the parent? In that case you don't swap at all.
swap(rootIndex, rightChildIndex);
heapifyHelper(leftChildIndex);
heapifyHelper(rightChildIndex);
}
}
}
And the reason why the subtree [11, 4, 5] isn't reached is because you only call heapifyHelper for the children if one of the children is smaller than the parent, but when you call heapifyHelper(1), the two children of the node 5 are 9 and 11, both larger than the root value. (Actually, you don't even call heapifyHelper(1), since heap[0]is already smaller than both its children.)
But rectifying that alone by unconditionally recurring (on the children that exist) doesn't make your heapify correct. If you recur from the root to the leaves, each value can bubble up at most one level. You must recur from the leaves to the root(1), and you need to sift the values down completely, not just one level.
If you only swap a value with one of its children, each position is considered at most twice. Once when comparing it to its parent, once when comparing it to its children. When you go from the root to the leaves, when you compare a position to its children, no position above it (no position with a smaller index, even) can ever be changed anymore.
So each value can bubble up at most one level. If the smallest element is below the direct children of root, root won't become the smallest element in the tree. If you start from the leaves (or rather the parents of the leaves), the values can bubble up as far as they need. But if you only swap a value with the smaller of its children (if that is smaller than the value), each value can still only bubble down one level, which still need not create a heap.
Let us consider the tree
7
/ \
/ \
2 6
/ \ / \
1 3 4 5
If you go from the root to the leaves, you swap 2 and 7 first, giving
2
/ \
/ \
7 6
/ \ / \
1 3 4 5
The top two levels are now a min-heap.
Then you treat the left subtree, and finally the right subtree, producing
2
/ \
/ \
1 4
/ \ / \
7 3 6 5
altogether. Now the bottom two levels are composed of min-heaps, but the heap property was destroyed in the level above. To make that a heap again, the 1 must be sifted up further (in this case, just one level).
If you go from the leaves to the root, you first treat the right subtree,
6
/ \
4 5
producing
4
/ \
6 5
for that, then the left subtree
2
/ \
1 3
producing
1
/ \
2 3
there. Both subtrees are now min-heaps. Altogether, you have
7
/ \
/ \
1 4
/ \ / \
2 3 6 5
Then you'd swap 7 and 1, producing
1
/ \
/ \
7 4
/ \ / \
2 3 6 5
Now the root is the smallest value, but the last swap destroyed the heap property of the left subtree. To make that a heap again, the 7 must be sifted down further.
So you need a siftDown method (and/or a siftUp method) that sifts a value down (up) as far as needed.
private void siftDown(int index) {
int leftChildIndex = getLeftChildIndex(index);
if (leftChildIndex >= heap.length) {
// a leaf, no further sifting down possible
return;
}
int rightChildIndex = getRightChildIndex(index);
if ((heap[leftChildIndex] < heap[index])
&& (rightChildIndex >= heap.length || heap[rightChildIndex] >= heap[leftChildIndex)) {
// left child is smallest or only, and smaller than parent
swap(index, leftChildIndex);
siftDown(leftChildIndex);
} else
// left child not smaller than parent, or right child exists and is smaller than parent
if (rightChildIndex < heap.length && heap[rightChildIndex] < heap[index]) {
swap(index, rightChildIndex);
siftDown(rightChildIndex);
}
// otherwise, this one has no smaller child, so no more sifting needed
}
Then a correct heapify would be
public void heapify() {
// last index that has a child:
int lastNonLeafIndex = heap.length/2 - 1;
for(int index = lastNonLeafIndex; index >= 0; --index) {
siftDown(index);
}
}
That works because if you have a (binary) tree where both of the subtrees are min-heaps, sifting down the root value constructs a min-heap:
If the root value is smaller than (or equal to) both its children, the entire tree is already a min-heap.
Otherwise, after the root value has been swapped with the smaller of its children (without loss of generality the left), the other subtree is unchanged, hence still a min-heap. And, since the left child was the smallest value in the left subtree before the swap, the value at the root is the smallest value in the entire tree after the swap. Swapping may have destroyed the min-heap property of the left child, though. But the left-left and the left-right subtrees have not been changed, so they are still min-heaps. And the new left subtree is smaller than the original tree, so by the induction hypothesis, sifting down its root value creates a min-heap from that. So after sifting down has finished, we have a tree with the smallest value at the root, both of whose subtrees are min-heaps, that is, a min-heap.
Since each leaf is trivially a min-heap, for each index processed in heapify, the subtree rooted at that index becomes a min-heap.
The alternative, using siftUp:
private void siftUp(int index) {
if (index == 0) return; // root, nothing to do
int parentIndex = getParentIndex(index); // see Note below
if (heap[index] < heap[parentIndex]) {
swap(index, parentIndex);
siftUp(parentIndex);
}
}
public void heapify() {
for(int index = 1; index < heap.length; ++index) {
siftUp(index);
}
}
The code for siftUp is much shorter than for siftDown, since only two nodes are involved here, and there is no need to check whether any child index falls outside the array. But the heapify is less efficient (see footnote (1)).
siftUp is the method used to insert a new value into a heap. So this one builds a heap by inserting all values (except the root value) into an existing min-heap [when siftUp(index) is called, the part of the array before index is already a min-heap].
Note: your getParentIndex is incorrect,
return (childIndex / 2) - 1;
says the parent of index 1 is -1, and the parent of index 3 is 0, correct is
return (childIndex - 1) / 2;
(1) Actually, you can proceed from the root to the leaves, if you sift each value up as far as needed. It's just more efficient to heapify going from the [parents of the] leaves to the root. If you go from the root to the leaves, at level k you have 2^k values that may need to bubble up k levels, which gives an O(n*log n) complexity for building the heap. If you proceed from the [parents of the] leaves upward, you have 2^(log n - 1 - k) values that may need to bubble down k levels, which gives a complexity of O(n) for building the heap.
So i think I figured out what the problem is.
Your heapify helper stops the minute you find a root where the root is smaller than leftChild and rightChild.
In running your case.. you reach a situation where root (5) is lesser than 11 and 9..But 11 is not heapified..
Many ways to fix this. That i leave to you.
EDIT
So heapify is ideally meant only to put the first element in the rootIndex in a correct place. Not to create a Heap.
If you want to create a correct Heap, you need to insert a new element and call heapify on every such insert.

Genetic algorithms: Uniform crossover in just a part of genotype

I need to implement a "uniform crossover" genetic operator.
Edit: I realized that it is normal to have duplicates (because of random exchange) if a number appears in both individuals.
So I I added this:
if(anyDuplicate(p0_genome,minIndex) || anyDuplicate(p1_genome,minIndex)){
//rollback: swap again
swap(p0_genome,p1_genome,i);
}
but it stills create duplicates (most of time of the gene in position minIndex (which is excluded from the cycle!!!) . Of course I tested the function anyDuplicate,and it works very well
I tried with this code
> Note: Individual 1 and 2 have the same length but a different number
> of valid bits.
>
> Foe example: genotype length (of both individuals) = 10 ,
> representation as numbers from 1 to 10 without anyone repeated,the
> start delimiter is 1 and the end delimiter should be 2. Not used genes
> are = 0
>
> individual 1(p0_genome) = {1,4,5,3,2,0,0,0,0,0}
> individual 2(p1_genome) = {1,4,6,3,8,2,0,0,0,0}
Desideres output:
Individual 1(p0_genome): **1** <some genes ALL DIFFERENTS> **2** 0,0,0,.....
Individual 2(p1_genome): **1** <some genes ALL DIFFERENTS> **2** 0,0,0,.....
Main Code:
int indexOfLastP0 = findLast(p0_genome,gl); // last valid bit (the one = 2) of first individual
int indexOfLastP1 = findLast(p1_genome,gl); // last valid bit (the one = 2) of second individual
int minIndex = Math.min(indexOfLastP0,indexOfLastP1); // last valid bit of the "smaller" of the inviduals
// Building sons
/* exchange bit without considering delimiters bit (1 and 2)
and according to the smaller individual */
int threshold = 0.60;
for (int i=1; i<minIndex; i++) {
if (Math.Random()>threshold) {
swap(p0_genome,p1_genome,i);
}
// when exiting the loop the remaining of genes remain the same
Swap code:
public void swap(int[] array1, int[] array2 ,int i){
int aux=array1[i];
if (array2[i]!=2){
array1[i]=array2[i];
}
if (aux!=2){
array2[i]=aux;
}
anyDuplicate() code:
public boolean anyDuplicate(int[] genoma,int min){
for (int i=0;i<=min;i++){
for (int j=0;j<=min;j++){
if (genoma[i]==genoma[j] && i!=j){
return true;
}
}
}
return false;
}
findLast code:
public int findLast(int[] mgenome,int genotypeLength){
int k=1; // 1 element is not considered
while (k<genotypeLength && mgenome[k]!=0){
k++;
}
return k-1; // **I also tried returning k;**
}
The problem is that I get a lot of duplicates numbers in both individuals
I also tried with a "duplicate"(arraycopy from a parent to a child) of "fathers":
// Creating sons genotypes
int [] s0_genome = new int[gl];
int [] s1_genome = new int[gl];
// Building sons
int threshold = 0.60;
for (int i=0; i<minIndex; i++) {
if (Math.Random()>threshold)) {
s0_genome[i] = p1_genome[i];
s1_genome[i] = p0_genome[i];
}
else {
s0_genome[i] = p0_genome[i];
s1_genome[i] = p1_genome[i];
}
for (int i=minIndex; i<10; i++) {
// copy what's left
s0_genome[i] = p0_genome[i];
s1_genome[i] = p1_genome[i];
}
Am I doing something wrong? Thank you for any hint!
Okay, so you try swapping once, and if either of the resulting genomes contains duplicate values, you try swapping again. If there are still duplicates after the second try, you give up. This is not efficient, and the longer your genomes are, the more unlikely this is to work.
Solution A: You could try only doing a swap if the swapped value is not already in the target genome. That would give a swap function like this:
public void swap(int[] array1, int[] array2 ,int i){
int aux=array1[i];
if (array2[i]!=2 && !Arrays.asList(array1).contains(array2[i]){
array1[i]=array2[i];
}
if (aux!=2 && !Arrays.asList(array2).contains(array1[i]){
array2[i]=aux;
}
The problem with this is that it might completely lock genomes that contain the same values in different positions. For your example, with
g1 = {1, 4, 8, 9, 3, 2, 0, 0}
g2 = { 1, 3, 9, 8, 4, 2, 0, 0}
There would be no valid swaps at all, and the crossover would return the original genomes.
Solution B: If the value to be swapped is already present in the target genome, find the index of that gene in the target genome, and swap that too. This might cascade to require swaps in large parts of the genome, and of course it shouldn't happen when i=j.
Kind of depends on the desired behavior. For the example genomes above, what would a successful crossover look like?

Categories

Resources