I've wrote two different implementations of heapsort today and both have given me the same results:
Object i: 18
Object i: 11
Object i: 10
Object i: 9
Object i: 8
Object i: 3
Object i: 7
Object i: 1
Object i: 4
Now I've checked my code with this page here; and believe one of my implementations is exactly the same as the pseudo-code would suggest, whilst the other is very similar to one of the Java implementations.
I'd like to stress the fact that I've actually wrote two different versions, and checked them against implementations I can find! So I am really stumped at the moment! I've stepped through it with a debugger a few times - but have probably must've something along the way? I even made a debugging function which just looped through the list and outputted the contents using System.out.println() - but this still didn't help a great deal!
The algorithm is working on a List - and I have done nothing to optimise it at this stage; it merely is a bit of an experiment at the moment. I have working implementations of QuickSort, BubbleSort & Insertion Sort - but this one has left me stumped!
My first implementation is below:
public static List<Integer> execSort(List<Integer> s) {
int n = (s.size()-1);
Integer t;
for(int i = n/2; i>0; i--){
s = downheap(s, i, n);
}
while(n >= 1){
t= s.remove(0);
s.add(0, s.remove(n-1));
s.add(n-1, t);
n--;
s = downheap(s, 1, n);
}
return s;
}
public static List<Integer> downheap(List<Integer> s, int i, int n){
Integer t = s.get(i-1);
int j;
while( i <= n/2 ){
j = i*2;
if( (j<n) && (s.get(j-1) < s.get(j)))
j++;
if( t >= s.get(j-1)){
break;
} else {
/* Swap them, without using a third variable
- although with all the get()/set() methods
it would be better to have a third one, doh! */
s.set(i-1, (s.get(i-1) + s.get(j-1)));
s.set(j-1, (s.get(i-1) - s.get(j-1)));
s.set(i-1, (s.get(i-1) - s.get(j-1)));
i=j;
}
}
s.set(i-1, t);
return s;
}
You can also see them on Github as Gists:
- Implementation 1
- Implementation 2
Any ideas as to why some of the elements don't want to sort?! I'm aware that this implementation is going to be sub-optimal, that working on a List<> isn't going to be the best data structure and I should probably look at using primitive data-types as opposed to (ab)using auto-boxing... but that's for another post! I just want a working version before I try and improve it ;)
In the gist (you accidentally linked both to the same), you have a few typos
public static List<Integer> execSort(List<Integer> s) {
int start = (s.size()/2)-1;
int end = s.size()-1;
while( start >= 0){
s = sift(s, start, end);
sift takes the count as last argument, not the last index, so the argument ought to be s.size() (or end+1) instead of end.
public static List<Integer> sift(List<Integer> s, int start, int count){
int root = start;
while( ((root*2)+1) < 2 ){
That must be while(root*2+1 < count), and not < 2.
In the code you have here, you have in part the same problem (caused by an odd indexing strategy, I suspect):
for(int i = n/2; i>0; i--){
s = downheap(s, i, n);
Since you always get(i-1) resp. j-1 in downheap, you need an upper bound of s.size() or n+1 while building the initial heap.
}
while(n >= 1){
This loop should only run while n > 1, or you'll swap the smallest element out of place.
t= s.remove(0);
s.add(0, s.remove(n-1));
s.add(n-1, t);
The old root must go in the last place, that's place n, not n-1, s.add(n,t).
n--;
s = downheap(s, 1, n);
}
In downheap, the final
s.set(i-1, t);
is superfluous, you always swap t, so when that line is reached, the element at i-1 already is t.
Related
class Check {
static void countOddEven(int a[], int n) {
int countEven = 0, countOdd = 0;
for (int item : a) {
if (item % 2 == 0) {
countEven++;
}
}
countOdd = n - countEven;
System.out.println(countOdd + " " + countEven);
}
}
Code is to calculate even and odd numbers in an array. Please help to optimise the code.
You’re code is not correct.
If you were meant to count the even and odd numbers in a, then you are counting the even numbers correctly. If n is not equal to the length of a, then your calculation of the count of odd numbers is incorrect.
If on the other hand — and I’m just guessing — you were meant to count the even and odd numbers among the first n elements, then you are counting the even numbers incorrectly since you are iterating over all of a. Also in this case, if n is much smaller than the length of a, there is an optimization in only iterating over the first n elements as you should.
Finally you may try the following version. I doubt that it buys you anything, but I am leaving the measurements to you.
int countOdd = 0;
for (int ix = 0; ix < n; ix++) {
countOdd += a[ix] & 1;
}
int countEven = n - countOdd;
The trick is: a[ix] & 1 gives you the last bit of a[ix]. This is 1 for odd numbers and 0 for even numbers (positive or negative). So we are really adding a 1 for each odd number.
You should try running code with for loop instead of for each loop
Because ,
When accessing arrays, at least with primitive data for loop is dramatically faster.
however
When accessing collections, a foreach is significantly faster than the basic for loop’s array access.
but if you are getting some another errors , so might have done something wrong while calling the method (make sure n=length of your array)
here is the whole code with main method.
class Check{
static void countOddEven(int a[], int n){
int countEven=0,countOdd=0;
for(int i=0;i<n;i++)
if(a[i]%2==0)
{
countEven++;
}
countOdd=n-countEven;
System.out.println(countOdd+" "+countEven);
}
public static void main(String[] arg){
int a[]={2,3,4,5,6};
int n = 5;
countOddEven(a,n);
}
}
I've been at this for a couple days, reading many pseudocode and watching videos to explain recursion and mergesort. I understand mergesort and somewhat understand recursion -- except for when it applies to arrays as is in my code below. I did some debugging and it appears that my program is not sorting correctly regardless of the out of bounds error. I am very lost and would appreciate any help you can offer!
Questions:
1) what does it mean for a recursion on an array? Does it create a sub array that is held by the original array? -- if that makes sense.
2) why is my code running into a out of bounds error even though I followed a tutorial to the t and also set the k value after every pass. Specifically the issue is being encountered.
Here's the code:
public class Merge {
public static void main(String[] args) {
}
static void mergeSort(int arr[]){
int r = arr.length - 1;
Merge.sort(arr,0,r);
System.out.println(arr);
}
static void sort(int arr[], int p, int r){
if(p<r){
int q = (p+r)/2;
sort(arr,p,q);
sort(arr,q+1,r);
merge(arr,p,q,r);
}
}
static void merge(int arr[], int p, int q, int r){
int n1 = q-p+1;
int n2 = r-q;
int L[] = new int[n1];
int R[] = new int[n2];
for(int i = 0; i< n1; i++){
L[i] = arr[i];
}
for(int j = 0; j< n2; j++){
R[j] = arr[q+1+j];
}
int i = 0, j = 0;
int k = 1;
while(i<n1 && j<n2){
if(L[i]<= R[j]){
arr[k] = L[i];
i++;
}
else{
arr[k] = R[j];
j++;
}
k++;
}
while(i<n1){
arr[k] = L[i];
i++;
k++;
}
Error occurs here --> while(j<n2){
arr[k] = R[j];
k++;
}
}
}
Thank you for the help!
edit: Just wanted to say how greatful I am for the amazing replies on this post, thank you so much for your time.
To be honest I don't think your sentence 'recursion on an array' makes any sense.
Your code has one array arr which gets sorted. Your merge method is supposed to be sorting parts of this array, but every time it is called it has the same whole array object. There are no sub-arrays; it's just up to this method to sort the relevant part of this one array. If this method isn't doing what it's supposed to do, then problems will occur.
Let's take a closer look at the loop where you are getting an error:
while(j<n2){
arr[k] = R[j];
k++;
}
Suppose we get to this loop with j < n2. What happens?
We enter the loop because j < n2, so we copy R[j] to arr[k] and then increment k. We go back to the top of the loop, we find j is still less than n2 because neither variable has changed, so we copy R[j] to arr[k] and increment k again. We got back to the top of the loop, find j is still less than n2 and go round again. And so on, and so on, until eventually k falls off the end of arr and we get an ArrayIndexOutOfBoundsException.
In this part of mergesort we are trying to copy into arr the contents of R that haven't already been merged into arr, but we forgot to increment j. So, to fix this loop, increment j as well as k:
while(j<n2){
arr[k] = R[j];
j++;
k++;
}
Note that the previous loop, the one beginning with while(i<n1), increments i and k. This change now makes the two loops look more similar to one another.
So, we run our code again, and what happens? We still get an ArrayIndexOutOfBoundsException. Clearly we haven't solved the problem yet, but have we made any progress at all if we're just getting the same error?
The intention of the merge method is to merge the subarrays of arr from positions p to q inclusive and from positions q+1 to r inclusive. If the two subarrays are sorted, then after merging the whole subarray of arr from p to r will be sorted.
However, when we write the values back into arr, we start at index 1. Is this correct? Suppose arr has length 2, p = 0, q = 0 and r = 1. We have two elements to sort. Where does the first one get written to, and where does the second?
The answer is the first one gets written to arr[1], and your code throws an exception because it attempts to write the second to arr[2], which does not exist.
You want k to start from the start of the subarray you are sorting. You want k to start from p.
So replace the line
int k = 1;
with
int k = p;
We try again, and now we find the code no longer throws an exception but prints something unintelligible like [I#65fb1cd. Annoyingly, this is how Java prints arrays by default. To fix this, add the line import java.util.Arrays; to your file and replace the line
System.out.println(arr);
with
System.out.println(Arrays.toString(arr));
Your code should now print out a list of numbers when it runs.
However, we now see that our code isn't sorting the array correctly. I asked it to sort the values 8, 1, 4, 9 and it came back with 1, 1, 8, 9. The 1 has been duplicated and the 4 has disappeared.
Recall once again that the intention of the merge method is to sort arr from p to r onwards. Take a careful look at what values are being copied from the array into L and R:
for(int i = 0; i< n1; i++){
L[i] = arr[i];
}
for(int j = 0; j< n2; j++){
R[j] = arr[q+1+j];
}
Notice any difference between these two loops, apart from the fact that one uses j instead of i, n2 instead of n1 and R instead of L?
Note that when you copy into R, you are copying values from position q+1 onwards. These are the values in the second sorted subarray. But when you are copying into L, you are copying values from position 0 onwards. This isn't necessarily where the first sorted subarray begins. That of course starts from p.
Replace the first of these loops with:
for(int i = 0; i< n1; i++){
L[i] = arr[p+i];
}
Finally, we run the code and find that we now have a working mergesort program.
Let's break your question down a bit - specifically, what does recursion mean? You can think of it like a loop - it performs an operation on itself until it reaches a stop condition. Take for example, a for loop
for(int i = 0; i < 2; i++)
will perform the operation until it reaches the case where variable i is no longer less than 2. Likewise, recursively
void methodLoop(int input){
int i = input;
if(i < 2){
methodLoop(i+1);
}
else{
System.out.println("Base case reached! I is no longer less than 2!");
}
}
Performs a similar operation, just with recursion instead!
What does this mean for arrays? It depends. What you've touched upon in your question is a concept called multidimentional arrays - arrays within arrays. These work like normal arrays, it's just an array that contains another array in each one of its indexes - these are instantiated as follows
String[][] multidimensionalarray = new array[4][4]
To visualize such a concept, it might be easier to think of it as a coordinate grid, with the indexes being the coordinate places and the value at that index containing information about that place. For example, assuming the multidimensional array has been filled with data like so, it might look like:
4 a b c d
3 e f g h
2 i j k l
1 m n o p
1 2 3 4
and then the value of multidimensionarray[2][3] would return the string k!
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
I am working on a problem. Out of 17 test cases 10 works fine and gives the result in less than a second but in 7 cases it is taking 2 seconds which are beyond the time limit. Following is the code
import java.util.*;
import java.io.*;
class TestClass
{
static PrintWriter wr = new PrintWriter(System.out);
public static void func1(int arr[], int n)
{
int temp = arr[0];
for (int jj = 0; jj < n; jj++)
{
if (jj == (n - 1))
arr[jj] = temp;
else
arr[jj] = arr[jj + 1];
}
}
public static void func2(int arr[], int n, int rt)
{
int count = 0;
for (int a = 0; a < n; a++)
{
for (int b = a; b < n; b++)
{
if (arr[a] > arr[b])
count++;
}
}
if (rt == (n - 1))
wr.print(count);
else
wr.print(count + " ");
}
public static void main(String args[]) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine().trim();
StringTokenizer st = new StringTokenizer(str);
int t = Integer.parseInt(st.nextToken());
for (int i = 0; i < t; i++) //for test cases
{
str = br.readLine().trim();
st = new StringTokenizer(str);
int n = Integer.parseInt(st.nextToken());
int arr[] = new int[n];
str = br.readLine().trim();
st = new StringTokenizer(str);
for (int j = 0; j < n; j++) //to take input of array for each test case
{
arr[j] = Integer.parseInt(st.nextToken());
}
for (int rt = 0; rt < n; rt++) //for number of times circular shifting of array is done
{
func1(arr, n); //circularly shifts the array by one position
func2(arr, n, rt); //prints the number of inversion counts
}
if (i != (t - 1))
wr.println();
}
wr.close();
br.close();
}
}
Can someone suggest how to optimize the code so that it takes less time in execution.
I know BufferReader and PrintWriter takes less time as compared to Scanner and System.out.print. I was using scanner and System.out.print earlier but changed it later in hope of getting less time but it didn't help. Also I did it earlier without the use of func1 and func2 and did all the operations in main only. The time in both the cases remains the same.
I am getting the currect output in all the cases so code is correct, I just need help in optimizing it.
The website you are using acquires questions from past programming competitions. I recognize this as a familiar problem
Like most optimization questions, the preferred steps are:
Do less.
Do the same in fewer instructions.
Don't use functions.
Use faster instructions.
In your case, you have an array, and you wish to rotate it a number of times, and then to process it from the rotated position.
Rotating an array is an incredibly expensive operation, because you typically need to copy every element in the array into a new location. What is worse for you is that you are doing it the simplest way, you are rotating the array one step for every step needing rotation.
So, if you have a 100 element array that needs rotated 45 steps, you would then have (3 copies per element swap) 100 * 45 * 3 copies to perform your rotation.
In the above example, a better approach would be to figure out a routine that rotates an array 45 elements at a time. There are a number of ways to do this. The easiest is to double the RAM requirements and just have two arrays
b[x] = a[(mod(x+45), a.length)]
An even faster "do less" would be to never rotate the array, but to perform the calculation in reverse. This is conceptually the function of the desired index in the rotated array to the actual index in the pre-rotated array. This avoids all copying, and the index numbers (by virtue of being heavily manipulated in the math processing unit) will already be stored in the CPU registers, which is the fastest RAM a computer has.
Note that once you have the starting index in the original array, you can then calculate the next index without going through the calculation again.
I might have read this problem a bit wrong; because, it is not written to highlight the problem being solved. However, the core principles above apply, and it will be up to you to apply them to the exact specifics of your programming challenge.
An example of a faster rotate that does less
public static void func1(int arr[], int shift) {
int offset = shift % arr.length;
int [] rotated = new int[arr.length];
// (arr.length - 1) is the last index, walk up till we need to copy from the head of arr
for (int index = 0; index < (arr.length - 1) - offset; index++) {
rotated[index] = arr[index+offset];
}
// copy the end of the array back into the beginning
for ( int index = (arr.length - 1) - offset; index < arr.length; index++ ) {
rotated[index] = (offset - ((arr.length - 1) - index) - 1);
}
System.arraycopy(rotated, 0, arr, 0, arr.length);
}
This copies the array into its rotated position in one pass, instead of doing a pass per index to be rotated.
The first rule of optimisation (having decided it is necessary) is to use a profiler. This counts how many times methods are invoked, and measures the accumulated time within each method, and gives you a report.
It doesn't matter if a method is slow if you only run it a few times. If you run it hundreds of thousands of times, you need to either make it faster, or run it fewer times.
If you're using a mainstream IDE, you already have a profiler. Read its documentation and use it.
The other first rule of optimisation is, if there's already literature about the problem you're trying to solve, read it. Most of us might have invented bubble-sort independently. Fewer of us would have come up with QuickSort, but it's a better solution.
It looks as if you're counting inversions in the array. Your implementation is about as efficient as you can get, given that naive approach.
for(int i=0; i< array.length; i++) {
int n1 = array[i];
for(int j=i+1; j< array.length; j++) {
n2 = array[j];
if(n1 > n2) {
count++;
}
}
}
For an array of length l this will take ( l - 1) + ( l - 2 ) ... 1 -- that's a triangular number, and grows proportionally to the square of l.
So for l=1000 you're doing ~500,000 comparisons. Then since you're repeating the count for all 1000 rotations of the array, that would be 500,000,000 comparisons, which is definitely the sort of number where things start taking a noticeable amount of time.
Googling for inversion count reveals a more sophisticated approach, which is to perform a merge sort, counting inversions as they are encountered.
Otherwise, we need to look for opportunities for huge numbers of loop iterations. A loop inside a loop makes for big numbers. A loop inside a loop inside another loop makes for even bigger numbers.
You have:
for (int i = 0; i < t; i++) {
// stuff removed
for (int rt = 0; rt < n; rt++) {
// snip
func2(arr, n, rt); //prints the number of inversion counts
}
// snip
}
public static void func2(int arr[], int n, int rt) {
// snip
for (int a = 0; a < n; a++) {
for (int b = a; b < n; b++) {
// stuff
}
}
// snip
}
That's four levels of looping. Look at the input values for your slow tests, and work out what n * n * n * t is -- that an indicator of how many times it'll do the work in the inner block.
We don't know what your algorithm is supposed to achieve. But think about whether you're doing the same thing twice in any of these loops.
It looks as if func1() is supposed to rotate an array. Have a look at System.arrayCopy() for moving whole chunks of array at a time. Most CPUs will do this in a single operation.
I am trying to create a method to search a 1D array for a minimum value using recursion. It does give me an output but it is always "1" regardless of whether or not the array even contains "1". I am very new to programming and any help is appreciated.
public static int smallest(int[] array)
{
return smallestFrom(array, 0);
}
static int min = 500; //large number
private static int smallestFrom(int[] array, int i)
{
int x = array.length;
if (i < x && array[i] < min)
{
min = array[i];
i++;
smallestFrom(array, i);
}
else if (i < x && array[i] >= min)
{
i++;
smallestFrom(array, i);
}
return min;
}
Output:
2,4,6,1,6,3,8
Smallest: 1
43,76,3,23,95,23
Smallest: 1
Your implementation looks fine to me. Well, that's a bit too much said, but it works. You could improve this quite a bit though:
Large Integer
Why use some arbitrary number as "large number"? This code will break for inputs with larger values than 500. You should just use the constant Integer.MAX_VALUE. There are no larger values possible than this one, it's named in a clear manor and it's defined by the API.
Global variables
This is where the error occurs. Your implementation is designed for singleuse. min will hold 1 after running it with the first array. Since there are no numbers larger than 1 in the second example-array, it will return 1 again. This can be fixed by either resetting min to the original value each time smallest is called, or alternatively completely relinquishing it (see below).
Branching
This problem can be solved with a lot less conditions. Instead of storing the minimum, we could use an alternate definition of the maximum of an array:
max({a, b, c, d, e, f}) = max({a, max({b, c, d, e, f})})
Looks more complicated? Actually it isn't. The idea is that the maximum of an array is the maximum of it's first elements and the maximum of all remaining elements in the array. This could now be translated a lot simpler into code.
Putting it all together
static int min(int[] arr)
{
return minRec(arr, 0);
}
static int minRec(int[] arr, int i)
{
if(i == arr.length)
return Integer.MAX_VALUE;
return Math.min(arr[i], minRec(arr, i + 1));
}
Looks a lot neater, doesn't it? Math.min(int, int) is just the API-implementation of a function that returns the minimum of two parameters.
I am trying to implement Quick Sort algorithm, here's my code:
public class Sort {
int count = 0;
public void Partition(int A[], int l, int h) {
if ((h-l) > 1) {
count += (h-l) - 1;
int pivot = A[l];
int i = l+1;
int temp;
int j;
for (j = l + 1; j < h; j++) {
if (A[j] < pivot) { // SWAP
temp = A[i];
A[i] = A[j];
A[j] = temp;
i++;
}
// else : j++
}
temp = A[i-1];
A[i-1] = A[l];
A[l] = temp;
Partition(A, l, i-1);
Partition(A, i, A.length);
}
}
}
the code does sort the input array, but when i count the number of comparisons, it gives a number, much greater than the original number of the comparisons. I added a break point and moved a step by step into the code, and found that the problem lies in the last two lines:
Partition(A, l, i-1);
Partition(A,i, A,length);
The 'i' sent in the 2nd call, is the i resulting from the 1st call to the function Partition, and not the 'i' from the very first code. for example, the first time the code runs on the following input:
3 8 4 6 10 2 5 7 1
the output is: 1 2 3 4 6 10 9 5 7 8
and i = 3.
then the first call to Partition takes i (where i equals 3) and keeps changing the i's value, when it's finally done, the i's value is different than 3, and another wrong value is sent to the 2nd recursive call.
My question is, is there a way, so that the two calls take the same parameter i, without anyone changing it ?
Try this. Don't try to do the sort in Partition; from there, just return the index i (you have to change the return type to int, of course). Then write a different method to implement your quicksort.
public static void quicksort(int[] n, int left, int right){
if (left<right){
int pivotindex=Partition(n, left, right);
quicksort(n, left, pivotindex-1);
quicksort(n, pivotindex+1, right);}
}
I tested this with the following, and it worked perfectly.
public static void main(String[] args){
int[] n= new int[8];
n[0]=3;
n[6]=2;
n[1]=5;
n[3]=20;
quicksort(n, 0, n.length);
for (int i=0; i<n.length; i++){
System.out.print(n[i]+",");
}
}
Since Java uses pass-by-value, there is no way the first call can change the value of the parameter i, since the called method has no reference to it.
You are probably expecting the second call to Partition to be the next one. However, the first call will in turn call Partition twice more, causing the parameter values of the next execution of Partition to be different than you might expect.
Also, please start your method names with a lower-case letter.