selection sort loop questions in Java - java

I have a basic question about the inner loop length in Java selection sort. Here is the commonly used code for selection sort:
package com.java2novice.algos;
public class MySelectionSort {
public static int[] doSelectionSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int index = i;
for (int j = i + 1; j < arr.length; j++)
/* why not the length is not arr.length-1? I think the length is
exactly the same as what it is, the array's length is a
static number as array.length-1, but when it comes to the inner
loop why it plus 1 to the array length? */
if (arr[j] < arr[index])
index = j;
int smallerNumber = arr[index];
arr[index] = arr[i];
arr[i] = smallerNumber;
}
return arr;
}
}

Imagine you're trying to sort five items. The array length is 5, which means the indexes are 0 through 4.
In the first iteration of the inner loop, you have i=0 and j=1. You need j to index to the end of the array. That's why the expression in the inner loop is j < array.Length.
i, of course, only goes from 0 to 3, which is why the outer loop has i < array.Length - 1.
If you lay five playing cards on a table and walk through the steps of the selection sort, you'll get a better idea of what's happening here.

the first loop does not need to check the last index, therefore, it goes to arr.length - 1. on the second loop, of course, the last index of the array must be checked so the loop goes to the last index (arr.length).
imagine if the first loop goes to the last index. then this line for (int j = i + 1; j < arr.length; j++) will never execute.
check out this Pseudo code of selection sort for a better understanding of the algorithm

Related

Manual array copy in a nested for loop

I trying to find all 2s, move them to the back of the array, and turn them into 0s without loosing the order of the array. For example, [1,2,3,2,2,4,5] would become [1,3,4,5,0,0,0]. My code works fine but the IDE is telling me that the nested for loop is copying the array manually and wants me to replace it with System.arraycopy(). How would I go about that?
Code looks like this:
int[] numbers = {1,2,3,2,2,4,5};
for (int i = 0; i < numbers.length; i++){
if (numbers[i] == 2){
for (int j = i; j < numbers.length - 1; j++){
numbers[j] = numbers[j + 1];
}
numbers[numbers.length-1] = 0;
i --;
}
}
The following statement:
for (int j = i; j < numbers.length - 1; j++){
numbers[j] = numbers[j + 1];
}
Can be replaced by:
System.arraycopy(numbers, i + 1, numbers, i, numbers.length - 1 - i);
IDEs like IntelliJ should suggest that automatically when you press alt + enter (default key combination).
Now about arraycopy()
From the documentation, java.lang.System.arraycopy() will copy n elements (last argument) from the source array (1st argument) to the destination array (3rd argument) with the corresponding indexes to start from (2nd and 4th arguments).
More specifically, when calling arraycopy(numbers, i + 1, numbers, i, numbers.length - 1 - i) the arguments are:
numbers: The source array.
i + 1: The starting position in the source array.
numbers: The destination array.
i: The starting position in the destination data.
numbers.length - 1 - i: The number of array elements to be copied.
In your case, elements will be copied from your array, to itself, but the fact that source starting position is shifted from the destination starting position will induce the global shifting you're after (moving elements to the left).
About the number of elements to be moved, it should move i elements minus the first one that doesn't move and only gets overwritten. Hence the length - 1 - i.
The inner loop could be replaced with an arraycopy, however, you don't need an inner loop:
int[] numbers = {1,2,3,2,2,4,5};
int j = 0;
for (int i = 0; i < numbers.length; i++){
if (numbers[i] != 2){
numbers[j++] = numbers[i];
}
}
while (j < numbers.length) {
numbers[j++] = 0;
}
UPDATE
Or even:
int[] numbers = {1,2,3,2,2,4,5};
int j = 0;
for (int n: numbers){
if (n != 2){
numbers[j++] = n;
}
}
Arrays.fill(numbers,j,numbers.length,0);
The key thing is pretty simple: if you can reduce the lines of code you are responsible for (for example by using utility methods such as Arrays.arraycopy()) - then do that.
Keep in mind: each line that you write today, you have to read and understand tomorrow, and to probably modify in 5 weeks or months from now.
But then: I think you are over-complicating things here. I would use a temporary list, like this:
List<Integer> notTwos = new ArrayList<>();
int numberOfTwos = 0;
for (int i=0; i<source.length; i++) {
if (source[i] == 2) {
numberOfTwos++;
} else {
notTwo.append(source[i]);
}
}
... simply append `numberOfTwo` 0s to the list, and then turn it into an array
You see: you are nesting two for-loops, and you are repeatedly copying around elements. That is inefficient, hard to understand, and no matter how you do it: way too complicated. As shown: using a second list/array it is possible to "solve" this problem in a single pass.
After replacing your inner loop with System.arrayCopy the code should look like:
int[] numbers = { 1, 2, 3, 2, 2, 4, 5 };
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] == 2) {
System.arraycopy(numbers, i + 1, numbers, i, numbers.length - 1 - i);
numbers[numbers.length - 1] = 0;
i--;
}
}

How to traverse an array like a sine-wave?

Assume I had a 2D integer array, mxn.
I want to traverse this array like a sine wave.
In specific, traversal would start from the last row, and the first column, move onto the first row and the second column, move onto the last row and the third column.
I have attached an image to elaborate further.
t:
I only know how to traverse in order, but I was thinking of transposing the columns, changing the starting index of the column at every round, but I couldn't create a consisting loop to do so.
My attempt:
boolean startsAtbottom=true;
//cols become rows, startPoint alternates
for(int i = 0;i<n;i++)
{
if(startsAtbottom)
{
for(int j =m-1;j>-1;j--)
{
System.out.print(myArr[j][i]);
}
startsAtbottom=false;
}
else
{
for(int j =0;j<m;j++)
{
System.out.print(myArr[j][i]);
}
startsAtbottom=true;
}
}
The following code will do what you want. All you want is to change the way you traverse in consecutive iterations.
boolean traverseInOrder=true;
for(int i=0;i<columnCount;i++){
for(int j=0;j<rowCount;j++){
index=j;
if(!traverseInOrder){
index=rowCount-j-1;
}
//access the element
int element=array[i][index];
}
traverseInOrder= !traverseInOrder;
}
Your solution works, and there's nothing wrong with it. However you can get rid of the if by doing this:
for (int i = 0; i < n; i++) {
boolean goingUp = i % 2 == 0;
for (int j = 0; j < m; j++) {
int row = goingUp ? m - 1 - j : j;
System.out.println(myArr[row][i]);
}
}
Starting from your input you have that:
the outer loop index just increments from 0
the inner loop index increments for even columns and decrements for odd columns
you can determine if a number is even or odd by just checking if modulo is 0 (or by checking if (i & 0x01) == 0 but that's irrelevant)
Given this it's quite easy to model that pattern:
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
int value = data[i][i % 2 == 0 ? (cols - j - 1) : j]
}
}
The formula cols - j - 1 allows you to start from the end and go backward (see that with j = 0 you have cols - 1 and with j = cols - 1 you have cols - (cols - 1) - 1 == 0).
Mind that Java is nor column major nor row major, since a bidimensional array is just an array of arrays so according to your real layout you may need to swap indices.

Sorting arrays (Bubble Sort)

I have a small doubt while sorting arrays and yeah I am new to programming. Take a look at this code for example:
public void bubbleSort(int[] array) {
boolean swapped = true;
int j = 0;
int tmp;
while (swapped) {
swapped = false;
j++;
for (int i = 0; i < array.length - j; i++) {
if (array[i] > array[i + 1]) {
tmp = array[i];
array[i] = array[i + 1];
array[i + 1] = tmp;
swapped = true;
}
}
}
In the above code, why do we have to use j++ and i < (array.length-j) as the test expression? We could have rather used i < (array.length) as the test expression while omitting the variable j. Any answers?
"Why do we have to use j++ and i < (array.length-j) as the test expression?"
The reason behind is at any time elements array[ array.length -j ] to array[array.length - 1] are already sorted.
Example: Say you have array of length n.
So after the first iteration the biggest element will be placed at array[n - 1].
So because the largest element is already sorted on the next iteration we will only sort array of length n - 1.
After the second iteration the second biggest element will be placed at array[ n - 2].
So because the 1st largest and 2nd largest elements are already sorted on the next iteration we will only sort array of length n - 2, and so on...
The running time of the algorithm will be which is
As you said it we could have used i < (array.length - 1) but we will be just doing a lot of work for nothing. If we do this the running time will be (nn) which is O(nn). But though the running time is still O(n*n) but it is obvious that is smaller than , hence the first one is efficient.

How come I can't count downwards on an array in Java?

I am currently trying to take the elements of an array and reverse its order in Java. How come I cannot print the elements of the array by counting downwards using a for loop without changing the actual ordering of elements in my array?
private void printArray(int[] array) {
for (int i = array.length; i >= 0; i--){
println(array[i]);
}
}
Array indices start at 0 and end at array.length - 1. Here, you get an ArrayIndexOutOfBOundsException since your first read is past the end of the array (int i = array.length;).
Do:
for (int i = array.length - 1; i >= 0; i--)
println(array[i]);
Try
for (int i = array.length - 1; -1 != i; --i){
As indexes start from 0

Random number generator continues to include 0

I'm trying to populuate an array with random numbers to be sorted and used in a binary search. All of my code seems to work fine except the generating part. The numbers need be between 1-32767 and I continue to get 0.
for(int i = 0; i < SIZE-1; i++){
array[i] = (gen.nextInt(32767 - 1) + 1);
}
// Print out five entries
for(int i = 0; i < 5; i++){
System.out.println(array[i]);
}
// Sort array
Arrays.sort(array);
// Print out first five sorted entries
for(int i = 0; i < 5; i++){
System.out.println(array[i]);
}
After they're sorted and printed, the first entry is always 0. Perhaps this has to do with the array sorting, and I'm not realizing it. Any suggestions?
You're never setting the last element of the array -- use i < SIZE, not i < SIZE-1.

Categories

Resources