Valid selection sort algorithm? - java

I've written the following method that uses selection sort to sort an array:
public T[] selection(T[] arr)
{
T temp, min;
for(int i = 0; i < arr.length-1; i++)
{
for(int j = i + 1; j < arr.length; j++)
{
min = arr[i];
if(min.compareTo(arr[j]) > 0)
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
return arr;
}
However, I am having trouble distinguishing my algorithm from a bubble sort. Does my sorting method pass for a selection sort method?

Your algorithm is actually something called exchange sort.
In selection sort, you run a pass over the array to locate the smallest element. Whenever an element is found smaller than the smallest one discovered so far, you make a note of its position, but don’t move or swap it. Only once you’ve finished scanning the array elements do you swap the item you found to an earlier spot in the array. This means you always do a total of at most n - 1 swaps, one per iteration of the outer loop.
That doesn’t correspond with what you have in your code, because you’re performing multiple swaps per iteration of the outer i loop. The algorithm you have is called exchange sort. It’s a legal sorting algorithm, and like selection sort at the end of each iteration of the outer i loop you’ll have correctly placed another element, but it runs slower than a true selection sort because you’re making many more swaps than are needed.

Your implementation is definitely similar to the selection sort, but the swap should happen outside the nested loop. Within the innermost loop you should only save the index of the smallest element among the ones left to sort (I've misread you if placement during my first editing of the answer).
The main difference between selection sort and bubble sort is mainly, but not entirely, in their nested loop. In fact, the selection sort tries in its nested loop to find the smallest element after i and then places it at the i-th position. In this way, at each iteration of the outer loop it is guaranteed that the i-th element corresponds to the smallest among the ones left to sort (from i to n-1).
public void selectionSort(int[] arr){
int temp, min;
// At every iteration, the outer loop checks whether the i-th element is already at the right place,
// i.e. being the smallest value among the ones that follow it
for (int i = 0; i < arr.length-1; i++) {
//Assuming that the element in position i is the smallest among the ones left to sort
min = i;
//At every iteration of the outer loop, the innermost loop checks if there's a smaller value than the one in position i
for (int j = i + 1; j < arr.length; j++) {
//If a smaller value than the min-th element is found then j is stored as the current smallest index
if (arr[min] > arr[j]) {
min = j;
}
}
//Swapping the smallest element found with the one in position i.
//If min is still equal to i then no actual swap happens
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
On the other hand, the bubble sort algorithm achieves the same thing but instead of traversing from left to right, it iterates from right to left carrying with it the new smallest element it encounters.
public void bubbleSort(int[] vet) {
int temp;
//At every iteration, the outermost loop checks if there are any elements after i which are smaller than it
for (int i = 0; i < vet.length - 1; i++) {
// The innermost loop starts from the right bound 'till the i index.
// Every time this loop finds in [j-1] a bigger element than the one in [j],
// then these two are swapped to carry along the smaller element in position j during the traverse.
// Instead if the element in [j-1] is smaller than the one in [j],
// then it leaves them like that and keeps carrying [j-1] along instead of [j].
for (int j = vet.length - 1; j >= i + 1; j--) {
if (vet[j] < (vet[j - 1])) {
temp = vet[j];
vet[j] = vet[j - 1];
vet[j - 1] = temp;
}
}
}
}

public final class SelectionSort {
public static void sortAsc(int[] arr) {
for (int i = 0; i < arr.length - 1; i++)
swap(arr, i, getMinIndex(arr, i));
}
private static int getMinIndex(int[] arr, int i) {
int minIndex = i;
for (; i < arr.length; i++)
if (arr[i] < arr[minIndex])
minIndex = i;
return minIndex;
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}

Related

Swapping lowest value in the array to order from least to greatest

I have this code
public static int[] swapLowest(int[] array)
{
int smallestValue = 0;
for(int i = 0; i < array.length; i++)
{
for(int k = i + 1; k < array.length; k++)
{
if(array[i] > array[k])
{
smallestValue = array[i];
array[i] = array[k];
array[k] = smallestValue;
}
}
}
}
and it works how I want it to: swapping values to make it from least to greatest (e.g [5, 1, 2, 1, 6] would turn to [1, 1, 2, 5, 6]).
However, the logic behind this is wrong. Apparently, I did not meet the criteria:
Find the smallest number in the array from the starting point
Swap the lowest value with the current value, if necessary
Move to the next index 
Repeat until it reaches the last index
I'm not too sure why. Did I understand it wrong? Regardless, I need to fix my code, and any pointers to help me understand/what to do instead will be greatly appreciated
Seems like you are trying to write a variation of selection sort (exchange sort) and there is nothing wring with your code. There are couple of ways you could implement selection sort.
swap the elements outside the inner for loop
swap the elements inside the inner for loop
you are following up the second method
inside your inner for loop you are looking for the smallest value compared to your current value and if there is a one you are swapping them.
But regarding the time complexity second method (which you have used) could be bit more expensive. Because rather than finding the lowest element in the array and swapping with it, you swap elements every time there is an lower element compared to your current element inside the inner loop.
What you could do is record the index if it's lower than your element and continue to traverse the array inside the inner for loop checking if there are other elements lower than the current (if there are update the lowest element index)and once you found it and out of inner loop you could swap the elements.
public static int[] swapLowest(int[] array)
{
for(int i = 0; i < array.length; i++)
{
int index = i;
for(int k = i + 1; k < array.length; k++)
{
if(array[index] > array[k])
{
index = k;
}
}
int smallestValue = array[index];
array[index] = array[i];
array[i] = smallestValue;
}
return array;
}

Rearrange elements in an integer array in a fashion where-you first replace and then move the replaced integer to first part of the array

I came across a Hackerearth coding problem where you have to perform the following tasks over an integer array-
Search for a particular number in the array and replace it's occurrences with 1
Move all the 1s to the first part of the array, maintaining the original order of the array
For example- if we have an integer array {22,1,34,22,16,22,35,1}, here we search for the number "22" (let us assume it is present in the array), replace it with 1 and move all those 1s (including the 1s already present) to the first part of the array and the resultant array should look like {1,1,1,1,1,1,34,16,35} -maintaining the original order of the array, preferably in Java.
I actually have coded a solution and it works fine but is not optimal, can anyone help me find an optimal solution (w.r.t. time-space complexity)?
Below is my solution-
public static void main(String[] args) {
int[] n = rearr(new int[] {22,1,34,22,16,22,1,34,1}, 22);
for(int i=0; i<n.length; i++) {
System.out.print(n[i]+" ");
}
}
static int[] rearr(int[] a, int x) {
int[] temp = new int[a.length];
int j=0, c=0, k=0;
//search and replace
for(int i=0; i<a.length; i++) {
if(a[i] == x) {
a[i] = 1;
}
}
//shift all 1s to first part of array or shift all non-1s to last part of the array
for(int i=0; i<a.length; i++) {
if(a[i] != 1) {
temp[j] = a[i];
j++;
}
if(a[i] == 1) {
c++;
}
}
j=0;
for(int i=0; i<a.length && c>0; i++, c--) {
a[i] = 1;
j++;
}
for(int i=j ;i<a.length; i++) {
a[i] = temp[k];
k++;
}
return a;
}
This can be done in linear time and space complexity, by returning a completely new list instead of modifying the original list.
static int[] rearr(int[] a, int x) {
// allocate the array we'll return
int[] b = new int[a.length];
int fillvalue = 1;
// iterate backwards through the list, and transplant every value OTHER than
// (x or 1) to the last open index in b, which we track with b_idx
int b_idx = b.length - 1;
for (int i = a.length - 1; i >= 0; i--) {
if (a[i] != x && a[i] != fillvalue)) {
b[b_idx] = a[i];
b_idx--;
}
}
// once we've gone through and done that, fill what remains of b with ones
// which are either original or are replacements, we don't care
for (int i = b_idx; i >= 0; i--) {
b[i] = fillvalue;
}
return b;
}
This is linear space complexity because it requires additional space equal to the size of the given list. It's linear time complexity because, in the worst case, it iterates over the size of the list exactly twice.
As a bonus, if we decide we want to leave the original 1s where they were, we can do that without any trouble at all, by simply modifying the if condition. Same if we decide we want to change the fill value to something else.
Doing this with constant space complexity would require O(n^2) list complexity, as it would require swapping elements in a to their proper positions. The easiest way to do that would probably be to do replacements on a first run through the list, and then do something like bubblesort to move all the 1s to the front.
This can be done in a single iteration through the array. We can use 2 pointer approach here where we will use on pointer to iterate through the array and other one to point to the index of 1 in the array.
The code is below:
public static void main(String[] args) {
// input array
int[] arr = { 22, 1, 34, 22, 16, 22, 35, 1, 20, 33, 136 };
// element to be replaced
int x = 22;
int j = -1;
for (int i = arr.length - 1; i >= 0; i--) {
if (arr[i] == 1 || arr[i] == x) {
if (j == -1) {
j = i;
}
// incase arr[i]==x
arr[i] = 1;
} else {
if (j != -1) {
arr[j] = arr[i];
arr[i] = 1;
j--;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
Here we initialise j=-1 since we consider there are no 1's present in the array.
Then we start iterating the array from the end towards the starting of the array as we have to push all the 1's to the starting of the array. Now when we reach to 1 or x (particular number in your case), we check if this is first occurrence of the x or 1, if yes then we initialise the j with this index and change arr[i] = 1 because this could be equal to x then we need to make it 1. If the arr[i] is not 1 or x it means its a number which we need to push at back of the array. We check if we have position of 1 or j=-1. If j=-1 it means this number is already pushed back at end of array else we swap the number at i and j, and decrement j by 1.
At the end of the array we will have the array sorted in a fashion which is required.
Time Complexity: Since we are only iterating the array one, hence the time complexity is O(n).
Space Complexity: Since there are no extra space being used or constant space being used hence the space complexity is O(1)

How to implement compareTo in a generic method that takes a generic array as argument?

I'm trying to implement a method, that, given a generic array, and two index values, slice the array, and find the largest element between the two given numbers.
<T extends Comparable<? super T>> T max(T[] array, int firstIndx, int secondIndx) { //requires comparable
T maxElement = array[0]; //8
System.out.println(Arrays.toString(array));
for (int i = firstIndx; i < secondIndx - 1; i++) {
for (int j = firstIndx + 1; j < secondIndx; j++) {
if (array[i].compareTo(array[j]) > 0) {
maxElement = array[i];
array[i] = array[j];
array[j] = maxElement;
}
}
}
System.out.println(Arrays.toString(array));
return maxElement;
}
But for an arrays of ints [8, 4, 6, 20, 1], is swapping correctly just the first two elements, giving me the wrong maximum elements. What's wrong with the code ?
There are two issues with your sort. The first is that you're using firstIndx and secondIndx, but based on how your code is structured, it's treating that second number as if it were the second index minus 1.
The second issue is that your inner loop is starting back at firstIndx every time, which breaks the bubble sort. It needs to start at i.
Try this modification to your for loops:
for (int i = firstIndx; i <= secondIndx - 1; i++) { // Notice the "<=".
for (int j = i + 1; j <= secondIndx; j++) { // j starts at i
// ... existing bubble sort code goes here
}
}
Edit: I failed to mention that your approach won't find the max if the max is already in its sorted position. You should just grab the max from array[secondIndx] after you're done sorting.
As an aside, firstIndx is a pretty bad variable name. It's only one letter more to write it out in full: firstIndex.

Java: Reverse sorting array method

Preface: This isn't for homework, but it is for a "coding challenge", it's not worth any points in my course but i would like a fuller understanding of arrays and loops so i want this to work before i move on in the course.
So here's my problem. I'm trying to design a method that reverse sorts an array and places the numbers from highest to lowest. The code i have now is :
public static void selectionReverseSort (int[] array)
{
int startScan, index, maxIndex, maxValue;
for (startScan = 0; startScan < (array.length - 1); startScan++)
{
maxIndex = startScan;
maxValue = array[startScan];
for(index = startScan + 1; index < array.length; index++)
//index is 1
{
if (array[index] > maxValue)
{
maxValue = array[index];
//maxValue now becomes the second array number
maxIndex = index;
//maxIndex becomes the current index number.
}
array[maxIndex] = array[startScan];
array[startScan] = maxValue;
}
}
}
The problem with this code, is that it seems to only reverse sort the arrays if they were in ascending order to start with, otherwise it just repeats the highest number for the first few array slots. Anyone wanna help me understand what's going on here and what i could do to fix this?
Your algorithm is correct. But you are swapping unnecessarily even if the you have a small number. I updated you logic.
import java.io.*;
public class Hey{
public static void main(String args[])throws IOException{
int []ar = {1,2,5,4,6,8,7,9,10};
selectionReverseSort(ar);
}
public static void selectionReverseSort (int[] array){
int startScan, index, maxIndex, maxValue;
for (startScan = 0; startScan < (array.length - 1); startScan++){
maxIndex = startScan;
maxValue = array[startScan];
for(index = startScan + 1; index < array.length; index++){
//index is 1
if (array[index] > maxValue){
maxValue = array[index];
//maxValue now becomes the second array number
maxIndex = index;
//maxIndex becomes the current index number.
//swap only if the condition is true
array[maxIndex] = array[startScan];
array[startScan] = maxValue;
}
}
}
}
for(int i = 0; i < array.length; i++ )
System.out.println(array[i]+"");
}
}
And I suggest you to use any other better sorting algorithm than Insertion sort.
It appears that the algorithm you've chosen is to find the largest value in the array, then use a swap to move the largest value to the first position in the array. Then you do the same for the subarray starting with the second element, then with the subarray starting with the third, and so on.
This will work, but your code does the swap too early. You need to wait until your inner loop is done finding the largest element before you do the swap. I haven't tested it, but I think all you need to do is move these two statements:
array[maxIndex] = array[startScan];
array[startScan] = maxValue;
outside of the inner loop.
This is just a one-line solution by using java API:
public static void selectionReverseSort (int[] array){
Collections.sort(Arrays.asList(array),Collections.reverseOrder());
}
Keep it for future purpose :).

Shell Sort: won't work with certain combos of intervals

I asked this question before, but my post was cluttered with a whole bunch of other code and wasn't clearly presented, so I'm going to try again. Sorry, I'm new here
Shell sort, how I wrote it, only works sometimes. Array a is an array of 100 integers unsorted, inc is an array of 4 integers whose values are the intervals that shell sort should use (they descend and the final value is always 1), count is an array which stores the counts for different runs of shell sort, cnt represents the count value which should be updated for this run of shell sort.
When I run shell sort multiple times, with different sets of 4 intervals, only sometimes does the sort fully work. Half the time the array is fully sorted, the other half of the time the array is partially sorted.
Can anyone help? Thanks in advance!
public static void shellSort(int[] a, int[] inc, int[] count, int cnt) {
for (int k = 0; k < inc.length; k++) {
for (int i = inc[k], j; i < a.length; i += inc[k]) {
int tmp = a[i];
count[cnt] += 1;
for (j = i - inc[k]; j >= 0; j -= inc[k]) {
if (a[j] <= tmp)
break;
a[j + inc[k]] = a[j];
count[cnt] += 1;
}
a[j + inc[k]] = tmp;
count[cnt] += 1;
}
}
}
One problem is that you're only sorting one inc[k]-step sequence for each k, while you should sort them all (you're only sorting {a[0], a[s], a[2*s], ... , a[m*s]}, leaving out {a[1], a[s+1], ... , a[m*s+1]} etc.). However, that should only influence performance (number of operations), not the outcome, since the last pass is a classical insertion sort (inc[inc.length-1] == 1), so that should sort the array no matter what happened before.
I don't see anything in the code that would cause failure. Maybe the inc array doesn't contain what it should? If you print out inc[k] in each iteration of the outer loop, do you get the expected output?
There is an error in your i loop control:
for (int i = inc[k], j; i < a.length; i += inc[k]) {
Should be:
for (int i = inc[k], j; i < a.length; i++) {
The inner j loop handles the comparison of elements that are inc[k] apart. The outer i loop should simply increment by 1, the same as the outer loop of a standard Insertion sort.
In fact, the final pass of Shellsort with an increment of 1 is identical to a standard Insertion sort.

Categories