Why heap is printing in incorrect order? - java

I am not sure why my heap method is not printing the heap in the correct order. Can someone tell me what am I doing wrong here?
Here is my getHeap method:
public static String getHeap(ArrayBasedList<Edge> edgeList)
{
// Build the heap
insert(new Edge(-1,-1,-1));
for(int i = 1; i < edgeList.size(); i++)
{
// Insert into the heap
insert(edgeList.get(i));
}
// Print the heap
String output="";
for(int i = 1; i < edgeList.size(); i++)
{
//System.out.printf("%4d%5d\n", heap[i].getVertex1(), heap[i].getVertex2());
output+=String.format("%4d%5d\n", heap[i].getVertex1(), heap[i].getVertex2());
}
return output;
}
and here are my insert and upHeap methods:
public static void insert(Edge e)
{
heap[edgeCount] = e;
edgeCount++;
upHeap(edgeCount - 1);
}
public static void upHeap(int pos){
if(pos > 0){
if(heap[(pos-1)/2].getWeight() > heap[pos].getWeight()){
/** Temporary edge for swapping */
Edge temp = heap[pos];
heap[pos] = heap[(pos-1)/2];
heap[(pos-1)/2] = temp;
upHeap((pos-1)/2);
}
}
}
and here is the print out of the edges of my heap :
0 1
1 2
2 3
1 3
0 3
but it is incorrect. the correct result is as follows:
0 1
0 2
1 2
2 3
1 3
0 3
what am I doing wrong here? would greatly appreciate any thoughts.. i am at a loss here.

One problem is that your upHeap method is apparently treating your heap as if the root node is at index 0, but your output code starts at index 1. So you never output the heap's root node.
Second, the array representation of a heap doesn't necessarily store things in sequential order. For example, inserting the items 1, 2, and 3 into a min-heap can create the array representation [1, 3, 2] or [1, 2, 3]. Both are valid heaps. Which one is created by inserting depends on insertion order.
If you want to remove items from the heap in order, you have to create an extractMin method, which takes the item at index 0 in the heap, and then re-adjusts the heap to move the next smallest item to index 0 and arranges the rest of the items. Typically that's done by moving the last item in the heap (i.e. the item at heap[heap.size-1] to heap[0], and then sifting it down to its proper place.

This is probably not the whole answer, but you're increasing edgeCount twice
heap[++edgeCount] = e;
edgeCount++;

You do not add edgeList.get(0) to your heap, so that edge (most probably the one printed out as 0 2) is missing from your output.
To add all edges to your heap your first loop should be:
for(int i = 0; i < edgeList.size(); i++)
{
// Insert into the heap
insert(edgeList.get(i));
}
To print out all edges your second loop needs to be:
StringBuilder output=new StringBuilder();
for(int i = 1; i <= edgeList.size(); i++)
{
//System.out.printf("%4d%5d\n", heap[i].getVertex1(), heap[i].getVertex2());
output.append(String.format("%4d%5d\n", heap[i].getVertex1(), heap[i].getVertex2()));
}
return output.toString();
This loop goes from 1 to edgeList.size() since your heap seems to contain a root element that should not be printed.
I've also changed to code from string concatenation to using a StringBuilder - string concatenation in a loop is slow, since strings are immutable. That might not make a big difference for small amounts of data, but it is better to always do it right.

Related

Sorting A Two-Dimensional (2D) Array as a whole without Row/Column Order

I was working on a Two Dimensional Array and I need to sort it in as a whole and not as in One Row/One Column Sort.
Say,
8 7 9 3
-2 0 4 5
1 3 6 -4
It should look like this,
-2 -1 0 1
2 3 4 5
6 7 8 9
I did It.
Took Two-Days to come up with an algorithm. Its not a perfect algorithm and maybe not even well optimized. But It Works.
Explanation
The Idea Is To get The Minimum Value From A Certain Element (say 0,0) To the End Of Array (i.e. a.length, a[0].length) and swapping it with the Certain Element.
Here I have created a Diagram to better understand the logic.
We Do this Till We Reach The Last Element and Voila! We Have a Sorted 2D-Array.
Code [JAVA]
Now, Come's the fun Part from where I lost Two Brain Cells. The Code.
What I have done, Is To Create a function which returns me the minimum value In a Array.
The Function takes two parameter's which is the Starting Element Index i.e.(i,j) from which its supposed to run a loop to end and return the minimum value with its index in a List.
//Helper Method
//row = Row Of Element To Began Loop From
//column = Column Of Element To Began Loop From.
List get_min(int row,int column)
{
List<Integer> l = new ArrayList<Integer>(); // List To Return with the output.
int mn=a[row][column], mni=0,mnj=0;
//mni= The Row Of Minimum Element
// mnj = The Column Of Minimum Element
for(int i=row;i<a.length;i++)
{
for(int j=column;j<a[0].length;j++)
{
if(mn>a[i][j])
{
mni = i;
mnj = j;
mn=a[i][j];
}
}
column=0; // This needs to be zero, just so the next time Row Updates The Loop doesn't began from the 2nd Element But 0.
}
l.add(mn); l.add(mni); l.add(mnj);
return l;
}
Now We Have A List With Three Values, The Minimum Element, The Minimum Element Row, The Minimum Element Column. We Can Now Build A Simple, Swap Function with the Use of Helper Method Above.
void sort_array()
{
for(int i=0; i<a.length;i++)
{
for(int j=0;j<a[0].length;j++)
{
List<Integer> l = get_min(i, j); // List with Minimum Value As In Step 1,Step 2, Step 3
if(a[i][j]>l.get(0)) // Check To Prevent Last Value Replacing The First Element
{
//Simple Swap
int t = a[i][j];
a[i][j] = l.get(0);
a[l.get(1)][l.get(2)] = t;
}
}
}
}
Voila Now You Have An Sorted 2D-Array. Enjoy with the data.

My BogoSort program may have a logic error

For an assignment, I have to write some Bogosort code, and empirically determine the program's Big O notation.
However, I am unsure of whether the code works, because even though it sorts it for 3 and 4 element arrays of type int, I don't think it should be doing it in 0 ms.
Conversely, it's taking really long for 5 elements (still haven't gotten a successful case within 15 minutes yet), which indicates to me that there may be something wrong with the program. Since there are no errors being thrown, I believe any problem found would be a logic error.
I've tried running the IDE debugger on the program. Each of the methods used for the bogosort seemed to be working as intended, although I was not able to reach the case where it sorted an array properly while using the debugger.
However, by changing the values of the array to have it already sorted, I was able to test the case where the array was sorted, and the code was executed successfully.
This seems to indicate that the problem if there is any, would have to do with a logic error in sorting, where the sort method is somehow never getting to the correct solution.
The file is as shown below, and is commented.
Any suggestions for the program will have to pertain to the current structure (no adding methods, no using ArrayLists) since this is a homework assignment.
public class BogoSort {
public static void main(String[] args) {
int[] myArray = {20, 142, 115, 120, 140};
//sets start time
long start = System.currentTimeMillis();
bogoSort(myArray);
//sets end time
long end = System.currentTimeMillis();
printArray(myArray);
//print time (end time - start time)
System.out.println((end - start) + "ms");
}
// Places the elements of a into sorted order.
public static void bogoSort(int[] a) {
while(!isSorted(a)){
//calls the shuffle method if it's not sorted
shuffle(a);
}
}
// Returns true if a's elements are in sorted order.
public static boolean isSorted(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i+1]) {
//returns false if the number in this index is greater than
//the number in the next index aka not sorted
return false;
}
}
//else return true
return true;
}
// Shuffles an array of ints by randomly swapping each
// element with an element ahead of it in the array.
public static void shuffle(int[] a){
Random r = new Random();
for(int i = a.length - 1;i > 0;i--){
//random number between 0 and i
int j = r.nextInt(i);
//calls swap method
swap(a, i, j);
}
}
// Swaps a[i] with a[j].
public static void swap(int[] a, int i, int j) {
//temp variable to hold value of a[i] for swap
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void printArray(int[] a)
{
for(int i = 0; i < a.length; i++)
{
System.out.println(a[i]);
}
}
}//end of BogoSort class
Results should be as follows:
20
115
120
140
142
???ms
??? is a value for how long the program runs for, maybe about 720 ms, if I understand bogosort's Big O notation correctly.
Currently, I have not gotten a result for an array above a size of 4.
The time it takes for an array of 3 or 4 elements to sort is 0 ms, which is a bit odd to me, I feel like it should be about 24 ms for 3 elements, and 120 ms for 4 elements.
The result of the sorting of a 3 or 4 element array is that the numbers are sorted correctly, as per the expected result.
Your shuffle algorithm is broken due to an off-by-1 error. If you try it with int[] myArray = {2,1,3};, you'll see that it fails to complete for 3 elements as well.
When dealing with randomness, it's better to use statistics than eyeballing, because it's hard to notice this at a glance:
$ java BogoSort | head -n 100000 > file
$ sort file | uniq -c
33325 [1, 3, 2]
33315 [2, 1, 3]
33360 [3, 2, 1]
As you can see, you only ever generate 3 out of 6 possible permutations.
When you shuffle, like your comment indicates, you swap each element with one earlier in the array. You need to additionally allow the element to stay in place. You can do this by adding 1 to the index you choose:
// Shuffles an array of ints by randomly swapping each
// element with an element ahead of it in the array **or leave it in place**.
public static void shuffle(int[] a){
Random r = new Random();
for(int i = a.length - 1;i > 0;i--){
//random number between 0 and i
int j = r.nextInt(i+1); // <-- +1 here to select the current element
//calls swap method
swap(a, i, j);
}
}
The result now looks better (I rigged the program to keep printing even when it's sorted):
$ sort file | uniq -c
16807 [1, 2, 3]
16579 [1, 3, 2]
16745 [2, 1, 3]
16697 [2, 3, 1]
16361 [3, 1, 2]
16811 [3, 2, 1]
and indeed, it now finishes in 0-1ms. Running it on 8 numbers takes ~10ms, and 10 numbers take ~150ms, in line with the expected factorial curve.
The accepted answer correctly identified the fault and a straight forward solution.
I attempted to dig a bit deeper into why there were missing permutations. From that answers suggested starting point, [2,1,3], the incorrect shuffle would result can only produce two outcomes: [1,3,2] and [3,2,1]. This is already a mistake, since you expect a shuffle to be able to produce any of the 6 permutations. However, in addition, under the incorrect shuffle, those outcomes can only produce each other on another iteration of the bad shuffle.
So, to think about it differently, the only way for [2,1,3] to shuffle into [1,2,3] would be if the third element was allowed to stay in place. The only way for [1,3,2] to shuffle into [1,2,3] would be if the first element was allowed to stay in place. Finally, the only way for [3,2,1] to shuffle into [1,2,3] would be if the second element was allowed to stay in place. But the algorithm does not allow elements to stay, and any moved element during the shuffle iteration is not moved again.
The bad shuffle only produces the permutations that cause all the elements to be in a different position. In other words, it can only produce rotations!Only for the 3 element case
So, if the starting point is not a rotation of the sorted array, the algorithm will never terminate.
In comments, I had suggested an alternative shuffle implementation:
public static void shuffle(int[] a){
Random r = new Random();
int x = r.nextInt(a.length);
for(int i = a.length-1;i > 0;i--){
int j = r.nextInt(i);
if (j < x) break;
swap(a, i, j);
}
}
However, the weakness of this shuffle is that itself still lacks the ability to generate any possible permutation. The ability of the bogosort to eventually see all possible permutations using this implementation depends on each successive call to shuffle producing slightly different inputs for the next call.

Replacement selection sorting

So I've been trying to implement this algorithm but I'm not so sure on where to start. Basically from what I understood you can implement it in two ways, by sorting it that the top level is the minimum (minHeap) or that the top level is the max of everything (maxHeap). I googled a lot about any of the two ways and I could not get a grip on how to actually implement it. I do not get the idea in general I would say, can anyone please explain how this works? Like how the minHeap one should work, or the maxHeap one.
Thank you in advance!
I'm assuming that you have a basic understanding of binary heap implementation in an array.
Let's say you have an array of integers that you want to sort into ascending order. One way is to rearrange items in the array so that they form a max-heap.
Then, you swap the top item (the largest item in the array) with the last item in the heap, decrease the heap count by 1, and sift the item from the top down into its new place in the heap. At the end, the first item in the array will be the next largest item. You repeat that for every item and your array is sorted.
Let's take a small example. Given the array [4,7,6,1,3,5,2], you rearrange them into a heap using Floyd's algorithm.
for (int i = array.length/2; i >= 0; i--)
{
siftDown(i);
}
This is an O(n) operation.
When you're done, the array is arranged in a binary heap. In this case, the heap would be [7,4,6,1,3,5,2], or:
7
4 6
1 3 5 2
So, we swap the root item with the last item, giving us: [2,4,6,1,3,5,7]. We decrease the count and sift 2 down to its proper place, giving: [6,4,5,1,3,2,7], or the heap representation:
6
4 5
1 3 2
(I omitted the 7 because we decreased the count. But it's still at the end of the array.)
Again, swap the top item with the last item in the heap: [2,4,5,1,3,6,7], decrease the count, and sift down: [5,4,2,1,3,6,7]:
5
4 2
1 3
If you continue that for the remaining five items in the heap, you'll end up with a sorted array.
The code for this is pretty simple:
int count = array.length-1;
while (count > 0)
{
swap(array[0], array[count]);
--count;
siftDown(0);
}
If you want to do a descending sort, you can either do the above with a max-heap and then reverse the array (an O(1) operation), or you can build a min-heap to start.
The siftDown method just moves the item down to its proper place, following the rules for binary heap construction:
void siftDown(int index)
{
// Left child is at index*2+1. Right child is at index*2+2;
while (true)
{
// first find the largest child
int largestChild = index*2+1;
// if left child is larger than count, then done
if (largestChild >= count)
{
break;
}
// compare with right child
if (largestChild+1 < count && array[largestChild] < array[largestChild+1])
{
++largestChild;
}
// If item is smaller than the largest child, then swap and continue.
if (array[index] < array[largestChild])
{
swap(array[index], array[largestChild]);
index = largestChild;
}
else
{
break;
}
}

Circular Array Loop, detection

I am working on a problem, and have spent some time on it.
Problem statement:
You are given an array of positive and negative integers. If a number n at an index is positive, then move forward n steps. Conversely, if it's negative (-n), move backward n steps. Assume the first element of the array is forward next to the last element, and the last element is backward next to the first element. Determine if there is a loop in this array. A loop starts and ends at a particular index with more than 1 element along the loop. The loop must be "forward" or "backward'.
Example 1: Given the array [2, -1, 1, 2, 2], there is a loop, from index 0 -> 2 -> 3 -> 0.
Example 2: Given the array [-1, 2], there is no loop.
Note: The given array is guaranteed to contain no element "0".
Can you do it in O(n) time complexity and O(1) space complexity?
And this is my solution in progress, however, I am not sure how should I end the do-while condition, when there is no loop detected. I believe my code will run infinitely if there is no loop detected.
public static boolean circularArrayLoop(int[] nums) {
int size = nums.length;
if(size < 2) return false;
int loopStart = nums[0];
int index = 0;
int start = nums[0];
do{
if(nums[index] > 0){
index = moveForward(index, nums[index], size);
}else {
index = moveBackward(index, Math.abs(nums[index]), size);
}
}while (loopStart != nums[index]);
}
This can be seen as a version of cycle detection in a directed (possibly disconnected) graph or more like finding a minimum spanning trees for all the connected subgraphs in the given graph. The numbers in the array are vertices and an edge will be formed between the vertices based on the vertice value. There are no known graph parsing algorithms which can possibly solve it in O(1) space complexity. This might be solved in O(n) time complexity as the best graph parsing algorithms can be solved in O(V+E) time and V=E in this case which makes it possible to solve with O(n) time complexity in some cases. The best-known algorithm is Kruskal's: http://www.geeksforgeeks.org/greedy-algorithms-set-2-kruskals-minimum-spanning-tree-mst/ which solves in O(nlogn) time.
Since there are guaranteed no elements with value 0, there is always going to be a loop. The qualifier is loops must be greater than a single element long.
With this condition, when advancing to the next index as directed by the array element value results in the same index being reached, "no" loop is present.
The fast and slow moving cursors can be used to find the beginning of the loop. Then advancing a single cursor until it returns to the same index would let you iterate over the elements of the loop. If a single advancement returns the cursor to the same index no loop is present.
public static void main(String[] args) {
int[] loop = {2, -1, 1, 2, 2};
int[] noloop = {-1, 2};
System.out.println(circularArrayLoop(loop));
System.out.println(circularArrayLoop(noloop));
}
static int nextIndex(int[] nums, int cur) {
// Get next index based on value taking into account wrapping around
}
static boolean circularArrayLoop(int[] nums) {
int fast = 0;
int slow = 0;
do {
// advance fast cursor twice
// advance slow cursor once
} while (fast != slow);
int next = nextIndex(nums, fast);
// return if the loop has more than a single element
}
Am I wrong to think there is no guarantee that the loop will go on with the first element ? Thus, you can't just do int loopStart = nums[0];
What if your example 1 was rather [2, -1, 1, 4, 2], then the loop would be from index 0 -> 2 -> 3 -> 2. And, your check with loopstart wouldn't work, since it checks sums[0].
A good solution is to use 2 variables and move them at different speed (one twice the speed). If the array/linked list is circular, you'll get to a point where var1 equals var2.
Here's the pseudocode:
if array.length<=1
return false
int i=0;
//loop is when "var1 == var2"
//end is when "var1 == abs(array.length)"
loop (until var1 == var2 or var1 reaches the end)
var1 = moveToNext(var1)
if (i++ % 2 == 0)
var2 = moveToNext(var2)
return var1 == var2;
This is quite similar to a question generally asked using linked list: How to detect a loop in a linked list?

Remove multi-elements from an arraylist error

public class test {
public static void main(String[] args) throws supernova, autowin{
ArrayList<Integer> integer = new ArrayList<Integer>();
integer.add(new Integer(0));
integer.add(new Integer(1));
integer.add(new Integer(2));
integer.add(new Integer(3));
System.out.println(integer.get(0));
System.out.println(integer.get(1));
System.out.println(integer.size());
for(int i = 0;i<2;i++){
if(i == integer.get(i)){integer.remove(i);System.out.println("remove");}
}
System.out.println(integer.get(0));
System.out.println(integer.get(1));
System.out.println(integer.size());
}
The outputs are
0
1
4
remove
1
2
3
.I expect this code to remove two elements(0 and 1),but it eventually only remove the first element. What if I want to remove all elements that have a special feature ,speaking like all elements store a odd number ,from an arraylist.
Could you explain the reason? Thank you a lot.
When you use the remove method, all elements ahead of the index are moved to the left. Therefore, after the first element is removed, i == integer.get(i) will always be false, because the Integer's value was set to be its original index, but now they are all "one ahead", so to speak.
Use a debugger in an IDE to see the process happen.
After the first iteration (i=0) the list is modified and becomes to
[1, 2, 3]
then for the next iteration i=1 adn then you do
if (i == integer.get(i)) {
if 1 == elementAtIndex1--> if 1==2 wich returns false an is not removing anything....
therefore your code is behaving like that...
Lets go step by step:
in for loop, when i = 0, you remove value from arraylist on position 0. Now, your ArrayList will be 1,2,3. Now, you check position i = 1, and in that position you have 2, not 1. because 2 is not equal to 1, if will not be executed.
One solution would be to change the direction of the for loop:
for(int i = 1;i >= 0;i--){
if(i == integer.get(i)) {integer.remove(i);System.out.println("remove");}
}
Now, the output will be:
0
1
4
remove
remove
2
3
2
Update: OP asked new question
If you want to remove odd numbers, just place logic for it in if:
for(int i = integer.size() - 1;i >= 0;i--){
if(integer.get(i) % 2 != 0 {
integer.remove(i);
System.out.println("remove");
}
}

Categories