The code below does quick sort in C.I tried to translate the same code logic into java.But, i am unable to write the equivalent Java code statement for "partition(&arr[left+1],size-left-1);" in the partition function below.Can anyone help?
#include<stdio.h>
int main()
{
int arr[8]={4,8,1,6,3,7,2,5};
partition(arr,8);//Initial Calling of partition function
int i;
for(i=0;i<8;i++)
printf("%d ",arr[i]);
return 0;
}
void partition(int arr[],int size)
{
if(size<2)
return;
int pivot=arr[rand()%size];
int left=0,right=size-1,temp=0;
while(left<right)
{
while(arr[left]<pivot)
left++;
while(arr[right]>pivot)
right--;
temp=arr[left],arr[left]=arr[right],arr[right]=temp;//swapping values
}
//partitioning and recursive calling
partition(arr,left);
partition(&arr[left+1],size-left-1);//The problem is to write an equivalent code for this
//line in Java
}
To get rid of pointers you need to specify start and end by parameters. Define you function like the following:
void partition(int arr[],int start, int end)
and instead of:
int left=0,right=size-1,temp=0;
do
int left=start,right=end,temp=0;
C allows you to use pointers to refer to a different starting point in the same array. Java does not. You can only refer to the entire array.
But you can add the starting index as a parameter.
void partition(int arr[],int offset, int length) {
...
partition(arr[], left+1, size-left-1); // check calculation, might be wrong :)
}
A solution without needing to handle pointers is to change the header like this:
void partition(int array[], int firstElement, int lastElement);
You can also try the function copyOf described here:
copyOf
But you would have to reconstruct it back together since you're working on copies, and I doubt it would be much QUICKsort anymore
public static boolean[] copyOf(boolean[] original,
int newLength)
Copies the specified array, truncating or padding with false (if necessary) so the copy has the specified length. For all indices that are valid in both the original array and the copy, the two arrays will contain identical values. For any indices that are valid in the copy but not the original, the copy will contain false. Such indices will exist if and only if the specified length is greater than that of the original array.
Parameters:
original - the array to be copied
newLength - the length of the copy to be returned
Returns:
a copy of the original array, truncated or padded with false elements to obtain the specified length
Throws:
NegativeArraySizeException - if newLength is negative
NullPointerException - if original is null
Since:
1.6
The x argument refers to the "pivot " value. In any case you need to study how this algorithm works.
public static int partition(
int[] arr, int start, int end, int x)
{
int l = start,r = end;
while (l<r ) {
if (arr[l] < x)
{
l =l +1;
}
else {
int temp = arr[l];
arr[l] = arr[r-1];
arr[r-1] = temp;
r = r-1;
}
}
return l;
}
Below is the equivalent Java code for the above (problem) partition function written in C.The initial call to partition function,say,from inside main, may be somewhat like this:partition(arr,0,arr.length-1);
Thanks for all your support and guidance
static void partition(int arr[],int first,int last)
{
int left=first;
int right=last,temp=0;
if(left>=right)
return;
Random rnd=new Random();
int pivot = arr[left + rnd.nextInt(right - left)];
while(left<right)
{
while(arr[left]<pivot)
left++;
while(arr[right]>pivot)
right--;
temp=arr[left];
arr[left]=arr[right];
arr[right]=temp;
}
partition(arr,first,left);
partition(arr,left+1,last);
}
Related
I'm trying to implement a quickSort algorithm after learning about it.
package qsort;
public class QuickSort {
public static void main(String[] args) {
int arr[] = {10,16,8,12,15,6,3,9,5,100};
quickSort(arr,0,(arr.length-1));
for(int number:arr) {
System.out.println(number);
}
}
public static void quickSort(int[] arr, int l, int h) {
if(l<h) {
int j=partition(arr,l,h); //pivot position as j retrieved as the one sorted element
int[] left = new int[j];
int[] right = new int[(arr.length-j)];
for(int index=0;index<j;index++) {
left[index]=arr[index];
}
for(int index=j;index<arr.length;index++) {
right[index-(j)]=arr[index];
}
quickSort(left,0,j); //Sorts the first half of the array (i.e the elements before pivot
quickSort(right,j+1,arr.length-1); //SOrts the second half after pivot
}
}
public static int partition(int[] arr, int l, int h) {
if(arr[l]>arr[h]) {
swap(arr[l],arr[h]);
}
int pivot = arr[l];
int i=l;
int j=h; //i starts from the first and increments; j starts from last and decrements
while(i<j) {
do {
i++;
}while(arr[i]<=pivot); //i keeps incrementing until i points to a value greater than pivot
do {
j--;
}while(arr[j]>pivot); //j keeps decrementing until it finds a value less than pivot
if(i<j) {
swap(arr[i],arr[j]);
}
}
swap(arr[l],arr[j]); // swapping the first element l with the element in j so that the pivotal element can be ordered
return j; //finally j points to the one sorted index where pivot should be placed
}
public static void swap(int a, int b){
int temp=a;
a=b;
b=temp;
}
}
And I've been clueless about IndexOutOfBoundsException and I'm not able to find out where or how it occurs. Any help would be much appreciated.
There are these issues:
swap doesn't swap. It just swaps the values of two local variables, but has no knowledge about an array. When swap exits, those two local variables are discarded and nothing really changed. You need to pass the array reference to swap and the two indices that are involved, and then swap should change the values in that array at those two given indices.
left gets j values, but then a recursive call is made with h equal to j, which is an index that is out of range. The left array has j elements, so its last index is j-1, not j.
right gets the remaining values, but then the recursive call is made with l equal to j+1, but that has no relation to right, whose relevant values start at index 0, not at index j+1.
The whole idea to copy values into new arrays left and right is wrong. This is not how quicksort is supposed to work. Even if left and right would be successfully sorted, this does not have any impact on arr, which remains unsorted. So you'd have done work for nothing. Quicksort is an inplace sorting algorithm, so you should always be working with arr, not with copies of partitions of it.
Here is the correction of the relevant functions:
public static void quickSort(int[] arr, int l, int h) {
if(l<h) {
int j=partition(arr,l,h);
// Don't create new arrays here, but sort the partition in-place:
quickSort(arr,l,j-1);
quickSort(arr,j+1,h);
}
}
public static int partition(int[] arr, int l, int h) {
if (arr[l]>arr[h]) {
swap(arr, l, h); // swap needs the array reference, and two indices
}
int pivot = arr[l];
int i=l;
int j=h;
while(i<j) {
do {
i++;
}while(arr[i]<=pivot);
do {
j--;
}while(arr[j]>pivot);
if(i<j) {
swap(arr, i, j); // see above
}
}
swap(arr, l, j); // see above
return j;
}
// swap needs the array reference and the indices to perform the swap in the array
public static void swap(int[] arr, int i, int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
I've been clueless about IndexOutOfBoundsException and I'm not able to find out where or how it occurs.
Debugging means you read the stack trace that includes this error message. It will give you the line number where it occurs (it was on the first line in partition). Then when you have identified that line, you can start to really use a debugger, setting breakpoints and inspecting variables. One of the first things you would notice, is that arr never changes: nothing gets moved in it. And so you would continue to debug and resolve one thing after the other. It is what I did with your code.
I am practising with recursion and have been looking at the question:
"Write a recursive program whose input is an array A and a number x. The program should print the number of occurrences of x in A"
This is my working solution:
public int countOccurrencesOfX_Recursive(int[] array, int x, int index, int occurrences) {
if (index == array.length) {
return occurrences;
}
if (array[index] == x) {
return countOccurrencesOfX_Recursive(array, x, index+1, occurrences+1);
} else {
return countOccurrencesOfX_Recursive(array, x, index+1, occurrences);
}
}
I couldn't think of another way to do it without introducing more function args. It doesn't seem great because it depends on the occurrences argument being set to 0, but a user could enter any integer they liked. My question is, is this considered a good way of keeping a counter when using recursion and if not, then how would you do it?
The normal solution to this is to have a non-recursive public function which your users call, which in turn calls a private function which is recursive.
For example:
public static int recursiveCount(int[] array, int value) {
return recursiveCountInternal(array, value, 0, 0);
}
private static int recursiveCountInternal(int[] array, int value, int index, int count) {
if (index == array.length) {
return count;
}
if (array[index] == value) {
count++;
}
return recursiveCountInternal(array, value, index + 1, count);
}
I've seen this style of recursion before and it looks fine.
What you can do is make an overloaded function that just calls this function with an initial occurrences of 0 like so:
public int countOccurrencesOfX_Recursive(int[] array, int x, int index) {
return countOccurrencesOfX_Recursive(array, x, index, 0);
}
and make the recursive function private. This will prevent your concern about users entering any number.
You can return 1+results from the rest of the string.
private static int countOccurencesofIntInarrayRec(Integer[] nums, int target){
if (nums == null || nums.length==0) return 0;
int addNum = nums[0]==target?1:0;
return countOccurencesofIntInarrayRec(Arrays.copyOfRange(nums, 1, nums.length),target) + addNum;
}
Which is better to use for an array of millions of integers(ages)
public static int findMax(int[] x) {
int max = 0;
int curr = 0;
for (int a : x) {
curr = Math.max(curr, a);
max = Math.max(max, curr);
}
return max;
}
public static int findMax(int[] x){
List<Integer> list = new ArrayList<>();
for (int y : x){
list.add(y);
}
return Collections.max(list);
}
The first one will definitely be faster than the second one, as you really don't want to be making an arraylist for no reason just to find the maximum of an array!
Also, there is no reason to use two different variables for the current and the max, just the max will suffice, like so:
public static int findMax(int[] x) {
int max = Integer.MIN_VALUE;
for (int a : x) {
max = Math.max(max, a);
}
return max;
}
Note: I used the minimum integer because the largest value in your array may be negative. Also, you could just use an if-condition instead of Math.max(), but it'll work either way. This also saves you an extra operation. The runtime is O(n) in every case.
They both look like they are O(n). You could always use a logger and see what the time is. The following is a link that talks about logging time executed: How do I time a method's execution in Java?
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5 };
int[] b = new int[5];
rekursiq(a, b, 0, 0, 1);
}
static void rekursiq(int[] a, int[] b, int index, int start, int check) {
if (index == b.length){
System.out.println(java.util.Arrays.toString(b));
} else {
for (int i = start; i < a.length; i++) {
b[index] = a[i];
rekursiq(a, b, index + 1, i + 1, check + 1);
}
}
}
Now my question is: Instead of b.length in the recursion bottom I want to place an int check, and make check go +1 on every going there, and do something.
while (check < b.length) go the if statement, else return; but I can't seem to 1) increase the value properly and 2) make this while correctly. I don't know why.
I think my best try was
static void rekursiq(int[] a, int[] b, int index, int start, int check) {
if (check > b.length) {
return;
} else {
if (index == check) {
System.out.println(java.util.Arrays.toString(b));
} else {
for (int i = start; i < a.length; i++) {
b[index] = a[i];
rekursiq(a, b, index + 1, i + 1, check + 1);
}
}
}
}
But it did not work, and I hope some one of you can tell me why and how to fix it.
The value of check does increase when the method is called recursively. However, the problem you have is independent of check.
The Problem
Let me start by repeating what abhishrp already briefly mentioned: In this particular case, you want to either use a loop to iterate over all elements in the array, or recursion, but not use a loop inside of your recursive method. The reason is the following: At each step in the recursion, you look at exactly one element: the element at position index.
The Solution
So, how would you recursively copy an array? Let us assume you have a source array (in your code a) and an empty destination array (in your code b). Now, we know how to copy a single element of the array, namely destination[index] = source[index], and we can imagine copying the array as copying the first element, and then copying the subarray starting at the second element. Note that knowing how to copy a single element in an array implies knowing how to copy an array containing only one element.
This leads us to the following recursion, which we will turn to code shortly after:
if the given index dereferences the last element in the array, then copy this last element.
otherwise, copy the element at the current index, and copy the subarray starting at the next index.
Or expressed in Java:
static void copyValuesFromSourceToDestinationStartingAtIndex(int[] source, int[] destination, int index) {
if (isIndexOfLastElementInArray(index, destination)) {
destination[index] = source[index];
} else {
destination[index] = source[index];
copyValuesFromSourceToDestinationStartingAtIndex(source, destination, index + 1);
}
}
static boolean isIndexOfLastElementInArray(int index, int[] array){
return index == array.length - 1;
}
Note that you have too many parameters in your code: The parameter check is really just index, as you want to check whether the index is still inside the bounds of the array. I don't really know what you intended to do with the variable start though - seems like somehow you got confused there because of the loop.
Sidenote
Also, a small justification on why the true-branch of the if-statement in the above code does copy the last element instead of returning nothing if the index is out of bounds as in your code. It's perfectly reasonable to do it like you did. The argument "We trivially know how to copy an empty array" just didn't seem as natural as "knowing how to copy a single element implies knowing how to copy an array consisting of a single element". I encourage you however to adjust the code to "copy an empty array" as a base-case, because it removes the duplication, and more importantly, allows you to copy empty arrays (for which the above implementation would fail horribly).
Code
I also tried to give a comparison between the iterative and the recursive approach:
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
int[] copyOfAUsingIteration = copyArrayUsingIteration(a);
int[] copyOfAUsingRecursion = copyArrayUsingRecursion(a);
assert(Arrays.equals(copyOfAUsingIteration, copyOfAUsingRecursion));
assert(copyOfAUsingIteration != a);
assert(copyOfAUsingRecursion != a);
System.out.println(java.util.Arrays.toString(copyOfAUsingIteration));
System.out.println(java.util.Arrays.toString(copyOfAUsingRecursion));
}
static int[] copyArrayUsingIteration(int[] arrayToCopy) {
int[] result = new int[arrayToCopy.length];
for(int index = 0; index < result.length; index++){
result[index] = arrayToCopy[index];
}
return result;
}
static int[] copyArrayUsingRecursion(int[] arrayToCopy){
if (arrayToCopy.length == 0){
return new int[0];
} else {
int[] result = new int[arrayToCopy.length];
copyValuesFromSourceToDestinationStartingAtIndex(arrayToCopy, result, 0);
return result;
}
}
static void copyValuesFromSourceToDestinationStartingAtIndex(int[] source, int[] destination, int index) {
if (isIndexOfLastElementInArray(index, destination)) {
destination[index] = source[index];
} else {
destination[index] = source[index];
copyValuesFromSourceToDestinationStartingAtIndex(source, destination, index + 1);
}
}
static boolean isIndexOfLastElementInArray(int index, int[] array){
return index == array.length - 1;
}
To copy one array to another you can use either iteration or recursion. There is no need to do both. By this I mean there is no need for the for loop inside the rekursiq method.
I created a 2D array of int[]
Now, I want to swap two int[] inside of 2D array
I have this for my code:
swap(values[row][col], values[randomRow][randomCol]);
where values is a 2D array of int[].
so values[int][int] is a int[];
I get an error message like this:
Error: The method swap(int[], int[]) is undefined for the type ShufflePic
How should I fix this?
Thanks a lot!
Java is pass-by-value. You cannot swap values like this.
Instead use this approach :
void swap(int[][] array, int row1, int col1, int row2, int col2) {
int temp = array[row1][col1];
array[row1][col1] = array[row2][col2];
array[row2][col2] = temp;
}
Now you can call swap(...) method to swap the values
swap(values, row, col, randomRow, randomCol);
mybe your method should looks like
swap(int[] arryFirst, int arryFirstRow, int arryFirstCol, int[] arrySec, int arrySecRow, int arrySecCol)
Basically, this finds the indices and swaps according to these indices. Try printing the items in the list after swapping. Of course, this technique could also be implemented for 2D arrays, but I'll leave that as a challenge for you.
public class Test {
static int[] list = {4, 5, 6, 3, 1, 2};
public static void main(String[] args) {
swap(6, 2); // test swap
}
public static void swap(int a, int b) {
int a_index = 0;
int b_index = 0;
for (int i = 0; i < list.length; i++) {
if (list[i] == a) a_index = i;
if (list[i] == b) b_index = i;
}
list[a_index] = b;
list[b_index] = a;
}
}
I created a 2D array of int[]
You did indeed do that, but you probably wanted to create a 2D array of int, not int[].
values[row][col] = 5 //2d int array
values[row][col] = new int[length] //3d int array. Probably not what you intended
Once you fix that, the other answers about passing by value should work for you.
EDIT:
If that's what you want, then this method should work:
public void swapArrays(int[][][] arr, int row1, int col1, int row2, int col2) {
int[] temp = arr[row1][col1];
arr[row1][col1] = arr[row2][col2];
arr[row2][col2] = temp;
}
You would then call this with:
swapArrays(values, row, col, randomRow, randomCol);
The reason you were getting the error is because you hadn't defined a swap function which takes in two arrays. However, even if you had, it wouldn't have functioned properly because of the pass-by-value, pass-by-reference thing. (Google it for more info on that.)
With my proposed method, it will have a reference to the entire array, enabling it to change its values. If you just passed in values[row][col], the method would only see the value stored at that index, but not access to the values array.