ArrayIndexOutofBoundsException in QuickSort Implementation - java

I'm trying out an implementation of QuickSort but getting an
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at com.JavaReference.QuickSort.swap(QuickSort.java:50)
at com.JavaReference.QuickSort.randPartition(QuickSort.java:20)
at com.JavaReference.QuickSort.randSort(QuickSort.java:12)
at com.JavaReference.QuickSort.randSort(QuickSort.java:13)
at com.JavaReference.QuickSort.randSort(QuickSort.java:13)
at com.JavaReference.QuickSort.randSort(QuickSort.java:13)
at com.JavaReference.QuickSort.randSort(QuickSort.java:13)
at com.JavaReference.QuickSort.randSort(QuickSort.java:8)
at com.JavaReference.QuickSort.main(QuickSort.java:59)
Here's my source code[here.]
Im a newbie to programming so any advice on where Im going wrong would be appreciated.
EDIT:Added entire stacktrace

My suspect is line 30:
int i =left-1;
Since left is initially 0, i will become -1. Then on line 35 you call
swap(a,i,j);
and bang.
OK, from the stack trace it seems my first guess was wrong.
Second guess: from the stack trace it shows that the array is partitioned 4 times, and then at the 5th attempt the exception comes. It is thrown on line 50:
int temp= array[a];
a is the first parameter to swap. The call to swap on line 20 was
swap(a,right,randPivot);
thus right is -1 at that point. This value comes from here (line 13):
randSort(a,left,pivot-1);
If pivot is 0 at this point, shit happens. And it can become 0 since it is taken as a random value between left and right, inclusive. (And actually, that is a mistake, as for effective partitioning, pivot should fall between left and right, noninclusive.) Currently, the probability of pivot becoming 0 increases as the leftmost partition becomes smaller. You need to introduce a check for this (or, more generally, to detect array partitions of size 1, which can't be partitioned further), to stop the recursion in time.

java.lang.ArrayIndexOutOfBoundsException: -1 does always tell you you're trying to call an array at an index which doesn't exist in this array.
Here the value of a ( Try to do System.out.println(a) which will show you the value of a) becomes at one time of the excecution -1.
So you try to call array[-1] which causes the exception because the array begins at an index of 0.
you need to change your algorithm so your method swap will only be called with values int[] array, value between 0 and array.length-1, value between 0 and array.length

You are trying to access to the element of the array with the index -1. This always throws an Exception. Check that the index (a >= 0).

Just a hint. This function:
public static void randSort(int a[],int left,int right)
leads to infinite recursion (it will call itself forever). At some point you will call swap with arguments left=0 and right=-1 (because randPartition returns 0 at some point).

I think it does not make sense to allow the pivot to be either left or right. This is because pivot should be used to separate two parts of the arry to be sorted (divide and conquer). To be most efficient, both parts should be equal in size.
So if left and right differ only by one, you should end recursion anyway.

Well folks,
It was my bad earlier, Id missed a critical
\\\Other code
if(left<right){
int pivot=randPartition(a,left,right);// testing purposes
randSort(a,left,pivot-1);........
...
in the randSort() function, I guess this was making right go negative .Sorry for all the noise.

Related

Understanding a particular solution to 'Minimum Swaps to Group All 1's Together 2nd' problem

I am looking at the LeetCode problem 2134. Minimum Swaps to Group All 1's Together II:
A swap is defined as taking two distinct positions in an array and swapping the values in them.
A circular array is defined as an array where we consider the first element and the last element to be adjacent.
Given a binary circular array nums, return the minimum number of swaps required to group all 1's present in the array together at any location.
I am trying to study how other people came up with solutions of their own. I came across this particular one, but I don't understand the logic:
class Solution {
public int minSwaps(int[] nums) {
// number of ones
int cntones=Arrays.stream(nums).sum();
// worst case answer
int rslt=nums.length;
// position lft and figure better value for min/rslt
int holes = 0;
for(int i=0;i<cntones;i++) {
if(nums[i]==0)
holes++;
}
// better value for rslt from lft to rgt
// up to index of cntones.
rslt = Math.min(rslt, holes);
// they have a test case with one element
// and that trips up if you dont do modulo
int rgt=cntones % nums.length;
for(int lft=0;lft<nums.length;lft++) {
rslt=Math.min(rslt,holes);
if(nums[lft]!=nums[rgt])
if(nums[rgt]==1)
holes--;
else
holes++;
rgt=(rgt+1)%nums.length;
}
return rslt;
}
}
Why is the worst case, the length of the input array?
I'm thinking wait, wouldn't the worst case be something like [0,1,0,1,0,1...] where 0's and 1's are alternating? Can you give me an example?
I suppose #of holes can potentially be a possible solution in some cases, from counting 0's in a fixed length (the number of total 1's) of a window but because I do not understand the worst case, rslt from question #1, below line stumps me as well.
// better value for rslt from lft to rgt
// up to index of cntones.
rslt = Math.min(rslt, holes);
About the modulo below, I don't think cntones can ever be bigger than nums.length, in turn which will result in 0 all the time? I'm thinking for the case with one element, you'd have to check whether that one element is 0 or 1. How does below line cover that edge case?
// they have a test case with one element
// and that trips up if you dont do modulo
int rgt=cntones % nums.length;
Due to #1~#3 the last for loop makes no sense to me...
Why is the worst case, the length of the input array?
First note that a swap is only useful when it swaps a 0 with 1. Secondly, it makes no sense to swap the same digit a second time, as the result of such double swap could have been achieved with a single swap. So we can say that an upper limit for the number of swaps is the number of 0-digits or number of 1-digits (which ever is the least). In fact, this is an overestimation, because at least one 1-digit should be able to stay unmoved. But let's ignore that for now. To reach that worst case, there should be as many 1 as 0 digits, so then we have half of the length as worst case. Of course, by initialising with a value that is greater than that (like the length) we do no harm.
The example of alternating digits would be resolved by keeping half of those 1-digits unmoved, and moving the remaining 1-digits in the holes between them. So that means we have a number of swaps that is equal to about one fourth of the length of the array.
below line stumps me as well.
rslt = Math.min(rslt, holes);
As you said, there is a window moving over the circular array, which represents the final situation where all 1-digits should end up. So it sets the target to work towards. Obviously, the 1-digits that are already within that window don't need to be swapped. Each 0-digit inside that window has to be swapped with a 1-digit that is currently outside that window. Doing that will reach the target, and so the number of swaps for reaching that particular target window is equal to the number of holes (0-digits) inside that window.
As that exercise is done for each possible window, we are interested to find the best position of the window, i.e. the one where the number of holes (swaps) is minimised. That is what this line of code is doing. rslt is the minimum "so far" and holes is the fresh value we have for the current window. If that is less, then rslt should be updated to it. That's what happens in this statement.
About the modulo below, I don't think cntones can ever be bigger than nums.length, in turn which will result in 0 all the time? I'm thinking for the case with one element, you'd have to check whether that one element is 0 or 1. How does below line cover that edge case?
int rgt=cntones % nums.length;
That modulo only serves for the case that cntones is equal to nums.length. You are right that it will never exceed it. But the case where it is equal is possible (when the input only has 1-digits). And as rgt is going to be used as an index, it should not be equal to nums.length as that is an undefined slot in the array.
Due to #1~#3 the last for loop makes no sense to me...
It should be clear from the above details. That loop moves the window with one step at a time, and keeps the variable holes updated incrementally. Of course, we could have decided to count the number of holes from scratch in each window, but that would be a waste of time. As we go from one window to the next, we only lose one digit on the left and gain one on the right, so we can just update holes with that information and know how many holes there are in the current window -- the one that starts at lft and runs (circular) to rgt. In case the digit that we lose at the left is the same as the one we gain at the right, we obviously didn't change the number of holes. Where they are different, we either win or lose one hole in comparison with the previous window.

How to try all possible way of traversing Array of integer

I'm new in programming and I'd like some help for an assignment, I only need a little clue to help me getting started (no answer, I only want to get a direction of how to do it then work my way).
The rules of the game : on the initial square is a marker that can move to other squares along the row. At each step in the game, you may move the marker the number of squares indicated by the integer in the square it currently occupies. The marker may move either left or right along the row but may not move past either end.
The goal of the game is to move the marker to the cave, the “0” at the far end of the row. In this configuration, you can solve the game by making the following set of moves:
eg: 2 3 1 2 4 0
first: move of 2 (to the right since it's impossible to go to the left) then: either move 1 to the right or 1 to the left then: if we moved left before: move 3 to the right (cannot go 3 to the left) if we moved right before then it's either 2 to the left or 2 to the right. 2 to the right is the right answer since then the next value is 0.
I must write the program that will try all the possibilities (so using a loop or a recursive I guess?) and return TRUE if there's a solution or FALSE if there are no solution. I had to choose the data structure from a few given by the prof for this assignment and decided to use an Array Based List since the get() is O(1) and it's mainly the only method used once the arraylist is created.
My program is only missing the (static?) method that will evaluate if it's possible or not, I dont need help for the rest of the assignment.
Assume that the ArrayBasedList is already given.
Thanks for your help!
I think your idea about using a recursive method makes a lot of sense. I appreciate you don't want the full answer, so this should just give you an idea:
Make a method (that passes in an integer x of the current position and your list) that returns a boolean.
In the method, check the value of list.get(x).
If it's 0, return true.
If it's -1, return false (more on that later).
Otherwise, store the value in a variable n, replace it with a -1, and return method(x+n) || method(x-n).
What the -1 does is it eventually fills everything in the array with a value that will terminate the program. Otherwise, you could end up with an infinite loop (like if you passed in [1, 2, 4, 2, 3]) with the value going back and forth.
A couple of things to keep in mind:
You'd need to make a new copy of the array every time, so you don't keep overwriting the original array.
You'd need to incorporate a try-catch (or equivalent logic) to make sure you are not trying to measure out of bounds.
If you have any further questions, feel free to ask!

how to sort an array without a new array?

I'm working on my homework and there's a question that ask us to sort a struct array
The structcitizen consist of an int id and a boolean gender, where id is randomly generated between 1 to 100,
and gender is determined by if id is odd or even, odd=true(male) and even=false(female)
for example a = {33, true}
The question requires me to sort the citizen[] array by gender, it seems very easy but it has the following requirements:
run in linear times O(N)
no new array
only constant extra space can be used
I am thinking about using counting sort but it seems a little bit hard to do it without a new array, is there any suggestion?
Since this is a homework question I'm not going to provide code. The following should be sufficient to get you started.
"Sorting" by gender here really means partitioning into two groups. A general purpose sort cannot be better than O(n*log(n)), but partitioning can be done in O(n) with constant space.
Consider iterating from both ends simultaneously (while loop, two index pointers initialized to first and last elements) looking for elements that are in the "wrong" section. When you find one such element at each end, swap them. Note that the pointers move independently of each other, only when skipping over elements that are already in the right section, and of course immediately after a swap, which is a subcase of "elements already in the right section".
Quit when the index pointers meet somewhere in the middle.
This is not a general purpose sort. You cannot do this for the case where the number of keys is unknown.
Since you only have two values to sort, you could use a kind of swap-counting-sort (I couldn't find any relevant paper on that one).
There is room for optimisation on that sort, but that will be your job.
Here is a pseudo-code of that special sort according to your issue :
integer maleIndex = 0 // Current position of males in the array
for i=0 until array.size do
if array.at(i) is a male then
// after a while, all female will end up at the end
// while all male will end up at the beginning
swap(array.at(maleIndex), array.at(i))
maleIndex = maleIndex + 1
end
end
One approach is similar to the partition stage in QuickSort, or to the median/rank finding algorithm QuickSelect.
I'm going to describe the outline of the algorithms, but not provide any code. Hopefully, it will be good enough that it is easy to make the translation.
You basically want to reorganize the array so that one gender is at the start, and the other is at the end of the array. You'll have the array partitioned in three:
From 0 to i-1 you have the first gender (male or female, up to you)
From i to j-1 you have both male/female. This is the unknown area.
From j to n-1 you have the second gender.
At the start of the algorithm i is set to 0, so the first area is empty, and j is set to n-1, so the second area is empty. Basically the whole array is in the unknown state.
Then, you iterate over the array in a particular way. At each step, you look at citizen[i].gender. If it is the first gender, you leave it alone and increment i. If it is the second gender, you swap A[i] with A[j] and decrement j. You stop when i is equal to j.
Why is this correct? Well, at each step we can see that the constraint of having the three areas is maintained, assuming it held to begin with (which it does), and either the first or the second one increases. At the end, the second area has no elements, so we're only left with the first gender at the start, and the second at the end.
Why is it linear? Well, at each step we make a constant-time decision for one element in the array about where it should belong. There's n such elements, so the time is linear in that. Alternatively, the iteration test can be expressed as while (j - i > 0), and the expression j - i starts at n-1 and drops by 1 for each iteration.

Double Recursion in one method Java

I am pretty sure that I thoroughly understand how the methods with only one recursion work.
Ex) calculating factorial
public int factorial(int n){ //factorial recursion
if(n==0){
return 1;
}
else{
return n*factorial(n-1);
}
}
For these methods, I can even picture what's going on in the stacks and what values are being returned at each stack level.
But Whenever, I encounter methods with Double Recursions, the nightmare begins.
Below is a recursion problem with double recursions from coding bat.
Ex) Given an array of ints, is it possible to choose a group of some of the ints, such that the group sums to the given target? If yes, true. If no, false.
You use 3 parameters; starting index start, An int Array nums, target int value target.
Below is the solution for this problem.
public boolean groupSum(int start, int[] nums, int target) {
if (start >= nums.length) return (target == 0);
if (groupSum(start + 1, nums, target - nums[start])) return true;
if (groupSum(start + 1, nums, target)) return true;
return false;
}
My take to understand this solution is this. Say I was given an array {2,4,8} with starting index = 0, and target value 10. So (0,{2,4,8},10) goes in through the method, the function gets re-called at
if (groupSum(start + 1, nums, target - nums[start])) return true;
so it becomes (1,{2,4,8},8) and it does over and over until start index hits
3. when it hits 3. The stack at the last level(?) goes to the second recursive call. And this is where I start losing track of what's happening.
Can anybody break this down for me? And when people use double recursion,(I know it's very inefficient and in practice, almost no one uses it for its inefficiency. But just in an attempt to understand it.)can they actually visualize what's going to happen? or do they just use it hoping that the base case and recursion would work properly? I think this applies generally to all the ppl who wrote merge sort, tower of hanoi alogrithm etc..
Any help is greatly appreciated..
The idea of a double recursion is to break the problem into two smaller problems. Once you solve the smaller problems, you can either join their solutions (as is done in merge sort) or choose one of them - which is done in your example, which only requires the second smaller problem to be solved if solving the first smaller problem didn't solve the full problem.
Your example tries to determine if there is a subset of the input nums array whose sum is the target sum. start determines which part of the array is considered by the current recursive call (when it's 0, the entire array is considered).
The problem is broken to two, since if such a subset exists, it either contains the first element of the array (in which case the problem is reduced to finding if there's a sub-set of the last n-1 elements of the array whose sum is target minus the value of the first element) or doesn't contain it (in which case the problem is reduced to finding if there's a sub-set of the last n-1 elements of the array whose sum is target).
The first recursion handles the case where the subset contains the first element, which is why it makes a recursive call that would look for the target sum minus the first element in the remaining n-1 elements of the array. If the first recursion returns true, it means that the required subset exists, so the second recursion is never called.
The second recursion handles the case where the subset doesn't contain the first element, which is why it makes a recursive call that would look for the target sum in the remaining n-1 elements of the array (this time the first element is not subtracted from the target sum, since the first element is not included in the sum). Again, if the second recursive call returns true, if means that the required subset exists.
Well if you want to visualize it, usually it's kind of like a tree. You first follow one path through the tree until the end, then step one back and pick a different path (if possible). If there is none or you are happy with your result you just take another step back and so on.
I don't know if this helps you but when I learned recursion, it helped to just think of my method as already working.
So I thought: Great, so basically my method is already working, but I can't call it with the same parameters and have to make sure I return the right value for these exact parameters by using different ones.
If we take that example:
At first we know that if we have no numbers to look at left, then the answer depends on if the target is 0. (first line)
Now what do we do with the rest? Well... we'd need to think about it for a moment.
Just think about the very first number. Under what circumstances is it part of the solution? Well that would be if you could create target-firstnumber with the rest of the numbers. Because then when you add firstnumber, you reach target.
So you try to see if that's possible. If so, it's solvable. (second line)
But if not, it's still possible that the first number just isn't important for the solution. So you have to try again to build the target without that number. (third line)
And that's basically all there is to this.
Of course to think like this you need two things:
1. You need to believe that your method already works for other parameters
2. You need to make sure your recursion terminates. That's the first line in this example but you should always think about if there is any combination of parameters that will just create an endless recursion.
Try to understand it like this: Recursion can be rewritten as a while-loop. where the condition of the while is the negation of the stop-condition of the recursion.
As already said, there is nothing called double recursion.

Given an array of length N, where each element in the array has X possibilities, return all possible arrays

I'm trying to solve the above problem using Java. Thought about using for loops but I can't see how this would work without knowing X and N in advance. I'm trying to solve it with recursion but not sure how it looks. Been trying for a couple hours now. Any help is greatly appreciated.
Example, if N = 4 and x = 3, possible arrays are:
[0,0,0,1]
[2,1,0,0]
[1,2,1,1]
[0,2,2,2]
My algorithem works like counting, you start counting until X (basiclly like counting in Base X) and when you get to X you add 1 to the next position in the Array and reset the last position.
so, as far as i know you can't return few arrays in a normal way so i'll assume you want to print them.
now, this is a "nice" code:
http://pastebin.com/Uqv3fMxg
few notes:
you should not make the function static, i did it from laziness.
this is not perfect, it print twice [1,0], [2,0] and so on. couln't find the problem and it is way too late for me, i'll try to check it again tommorow.
i'm not a guy that comments his code, i did a little but i'll explain everything i can here.
The program starts in the main method where i defined the Array and started the recurtion method.
The stop statement is when i got into the N position (that doesn't exist in the array, only N-1)
The parameters: the array, the position in the array that i am corrently counting and a "mode", is it a run to go to the next position or just to print all of the number in this position.
The alreadyHas variable is ment to not print number 2 times.
if i won't use it, it would print every number atleast 2 times, it will redo any work he has done until he move to this position and every position.
it is hard to explain, you can write 0 instead of it and see what happens.
so, i count until X, every time i print the new Array and to count every number and not skiping any i have to recount the last position with a different number in the last position.
after i have count all of the possible numbers in this possition, i am giving it a value of 0 and going to the next position.
so,to sum it up, you count the number in the first position of the array, when you reach the maximum you add a carry in the next position and reset the corrent position.

Categories