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 :).
Related
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;
}
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;
}
}
I need to sort an array. I write code, i use insertion sort, but for big n this code work so slow. How optimize my code. May be there is another algorithm.
public void insertionSort(ArrayList<Integer> arrayList) {
int n = arrayList.size();
int in, out;
for(out = 1; out < n; out++)
{
int temp = arrayList.get(out);
in = out;
while (in > 0 && arrayList.get(in-1) > temp)
{
arrayList.set(in, arrayList.get(in-1));
in--;
}
arrayList.set(in,temp);
}
print(arrayList);
}
You can use counting sort instead of insertion sort. Because counting sort takes a linear time, but insertion sort at worst takes О(n^2)
Here is example of using counting sort:
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void print(int []a){
System.out.println(Arrays.toString(a));
}
public static void countingSort(int []a, int []b, int n, int k){
int []c = new int [k];
for(int i=0; i<k; i++)
c[i] = 0;
for(int j=0; j<n; j++){
c[a[j]] = c[a[j]]+1;
}
for(int i=1; i<k; i++){
c[i] = c[i]+c[i-1];
}
for(int j=n-1; j>=0; j--){
c[a[j]] = c[a[j]]-1;
b[c[a[j]]] = a[j];
}
for(int i=0; i<n; i++)
a[i] = b[i];
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Random ran = new Random();
int n = Integer.parseInt(in.nextLine());
int []a = new int[n];
int []b = new int[n];
int k = 5; // max value on the array
for(int i=0; i<n; i++)
a[i] = ran.nextInt(k);
print(a);
countingSort(a,b,n,k);
print(a);
}
}
You should look into QuickSort or MergeSort if you want faster sorting algorithms. Unlike InsertionSort (and SelectionSort), they are recursive, but still fairly easy to implement. You can find many examples if you look around on the internet.
As Anna stated above, counting sort can be a really good algorithm, considering you don't have a really large data set and the data is not sparse.
For example, an array of size 10k with 100 elements duplicated will have much better space efficiency than an array of size 10k with all unique elements and spread in a sparse fashion.
For example, the following array -> [5,5,4,...,2,2,1,1,5,6,7,8] will need a space of an array of size 8 (1 being the minimum and 8 being the maximum) while,
This array -> [5,100,6004,3248,45890,2384,128,8659,...,3892,128] will need a space of an array at least of size 45886 (5 being the minimum and 45890 being the maximum).
So, I'll suggest you use this algorithm when you know that the data set you have is evenly distributed within an acceptable range which won't make your program run out of memory. Otherwise you can go with something like quicksort or mergesort. That gets the work done just fine.
That being said, Anna's implementation of counting sort seemed a little over coded to me personally, so here's me sharing my implementation.
public int[] countSort(int[] nums) {
int min = nums[0], max = nums[0], counterLength, start = 0;
int[] counter;
// To dynamically allocate size to the counter.
// Also an essential step if there are negative elements in the input array.
// You can actively avoid this step if you know:
// 1. That the elements are not going to be negative.
// 2. The upper bound of the elements in the array.
for (int i : nums) {
if (i > max)
max = i;
else if (i < min)
min = i;
}
counterLength = max - min + 1;
counter = new int[counterLength];
for (int i : nums)
counter[i - min]++;
for (int i = 0; i < counterLength; i++) {
if (counter[i] > 0) {
int end = start + counter[i];
Arrays.fill(nums, start, end, i + min);
start = end;
}
}
return nums;
}
I have the methods to find the smallest and largest value, and also to place them where they need to be. I also have a method to call those methods, and shrink to a subarray. The problem is, even though it is sorting, I can't print the array once I've moved into the subarray. Please help, there has to be a better way and I've banged my head against the wall for a while now.
package mySort;
import java.util.Arrays;
public class MyAlg {
public static int findSmall(int[] input){
int sm = input[0];
for(int i = 0; i <= input.length - 1; i++){
if(sm < input[i])
sm = input[i];
}
input[0] = sm;
return sm;
}
public static int findLarge(int[] input){
int lg = input[input.length -1];
for(int i = 0; i <= input.length - 1; i++){
if(input[i] > lg)
lg = input[i];
}
input[input.length -1] = lg;
return lg;
}
public static int[] sort(int[] input){
findSmall(input);
findLarge(input);
for(int i = 0; i<= (input.length - 1) / 2; i++){
int[] tmp = Arrays.copyOfRange(input, i + 1, input.length - 2 );
findSmall(tmp);
findLarge(tmp);
}
}
}
I am not sure if you are required to use an array or not, but if you are free to use whatever data structure you like I would recommend a TreeSet. This data structure implements SortedSet which means as the objects are added they are sorted already for you. Then you can use methods such as
first() - to return the lowest value
last() - to return the highest value
Then you could remove those highest and lowest elements or use these methods after that
ceiling(int) - highest number lower than given int
floor(int) - smallest number higher than given int
Lmk if you need more help or just need an implementation for an array.
Unfortunately your code is quite flawed, so I just rewrote everything. The below code will sort any int[] by placing the smallest int in the input array in the left most unfilled position of a new array and placing the biggest in the right most unfilled position of a new array, until the new array is a sorted version of the input array. Enjoy
private static int[] sort(int[] input) {
//create an empty array the same size as input
int[] sorted = new int[input.length];
//create another empty array the same size as input
int[] temp = new int[input.length];
// copy input into temp
for (int i = 0; i <= (input.length - 1); i++) {
temp[i] = input[i];
}
//create variables to tell where to put big and small
//in the sorted array
int leftIndex = 0;
int rightIndex = sorted.length - 1;
//create variables to hold the biggest and smallest values in
//input. For now we'll give them the values of the first element
//in input, they'll change
int big = input[0];
int small = input[0];
// sort
//sort the array as you described
while (temp.length != 0) {
//find the biggest and smallest value in temp
big = findBig(temp);
small = findSmall(temp);
//place the biggest at the end of the sorted array
//and place the smallest at the beginning of the sorted array
sorted[leftIndex] = small;
sorted[rightIndex] = big;
//move the left index of the sorted array up, so we don't over write
//the element we put in on the next iteration, same for the right index to,
//but down
leftIndex++;
rightIndex--;
if(temp.length != 1){
//remove the biggest and smallest values from the temp array
temp = removeElement(temp, big);
temp = removeElement(temp, small);
}else{
//only remove one element in the event the array size is odd
//also not at this point leftIndex == rightIndex as it will be the last
//element
temp = removeElement(temp, big);
}
//repeat, until the temp array is empty
}
// print out the content of the sorted array
for (int i = 0; i <= (sorted.length - 1); i++) {
System.out.println("Index " + i + ": " + sorted[i]);
}
//return the sorted array
return sorted;
}
//find the smallest number in an int array and return it's value
private static int findSmall(int[] input) {
int smallest = input[0];
for (int i = 0; i <= (input.length - 1); i++) {
if (smallest > input[i]) {
smallest = input[i];
}
}
return smallest;
}
//find the biggest value in an int array and return it's value
private static int findBig(int[] input) {
int biggest = input[0];
for (int i = 0; i <= (input.length - 1); i++) {
if (biggest < input[i]) {
biggest = input[i];
}
}
return biggest;
}
//remove an element from an int array, based on it's value
private static int[] removeElement(int[] input, int elementValue) {
//create a temp array of size input - 1, because there will be one less element
int[] temp = new int[input.length - 1];
//create variable to tell which index to remove, set to 0 to start
//will change unless it is right
int indexToRemove = 0;
//find out what the index of the element you want to remove is
for (int i = 0; i <= (input.length - 1); i++) {
if (input[i] == elementValue) {
//assign the value to
indexToRemove = i;
break;
}
}
//variable that says if we've hit the index we want to remove
boolean removeFound = false;
for (int i = 0; i <= (input.length - 1); i++) {
//check if we are at the index we want to remove
if (indexToRemove == i) {
//if we are say so
removeFound = true;
}
//done if we aren't at the index we want to remove
if (i != indexToRemove && removeFound == false) {
//copy input to temp as normal
temp[i] = input[i];
}
//done if we've hit the index we want to remove
if (i != indexToRemove && removeFound == true) {
//note the -1, as we've skipped one and need the to decrement
//note input isn't decremented, as we need the value as normal
//note we skipped the element we wanted to delete
temp[i - 1] = input[i];
}
}
//return the modified array that doesn't contain the element we removed
//and it is 1 index smaller than the input array
return temp;
}
}
Also, I'd place all of these methods into a class Sort, but I wrote it in this way to mimic the way you wrote your code to a certain extent. This would require you to create a getSorted method, and I'd also change the sort method to a constructor if it was placed in a class Sort.
I have written an algorithm to solve your this problem. Using divide and conquer we can solve this problem effectively. Comparing each value to every one the smallest and the largest value can be found. After cutting off 2 values the first one(smallest) and the last one (largest) the new unsorted array will be processed with the same algorithm to find the smallest and largest value.
You can see my algorithm in [GitHub] (https://github.com/jabedhossain/SortingProblem/)
Although its written in C++, the comments should be enough to lead you through.
I tried to find the smallest element in an integer array using what i understood about divide and conquor algorithm.
I am getting correct results.
But i am not sure if it is a conventional way of using divide and conquor algorithm.
If there is any other smarter way of implementing divide and conquor algorithm than what i have tried then please let me know it.
public static int smallest(int[] array){
int i = 0;
int array1[] = new int[array.length/2];
int array2[] = new int[array.length - (array.length/2)];
for(int index = 0; index < array.length/2 ; index++){
array1[index] = array[index];
}
for(int index = array.length/2; index < array.length; index++){
array2[i] = array[index];
i++;
}
if(array.length > 1){
if(smallest(array1) < smallest(array2)){
return smallest(array1);
}else{
return smallest(array2);
}
}
return array[0];
}
Your code is correct, but You can write less code using existing functions like Arrays.copyOfRange and Math.min
public static int smallest(int[] array) {
if (array.length == 1) {
return array[0];
}
int array1[] = Arrays.copyOfRange(array, 0, array.length / 2);
int array2[] = Arrays.copyOfRange(array, array.length / 2, array.length);
return Math.min(smallest(array1), smallest(array2));
}
Another point. Testing for the length == 1 at the beginning is more readable version. Functionally it is identical. From a performance point of view it creates less arrays, exiting as soon as possible from the smallest function.
It is also possible to use a different form of recursion where it is not necessary to create new arrays.
private static int smallest(int[] array, int from, int to) {
if (from == to) {
return array[from];
}
int middle = from + (to - from) / 2;
return Math.min(smallest(array, from, middle), smallest(array, middle + 1, to));
}
public static int smallest(int[] array){
return smallest(array, 0, array.length - 1);
}
This second version is more efficient because it doesn't creates new arrays.
I don't find any use in using a divide and conquer in this paticular program.
Anyhow you search for the whole array from 1 to N, but in two steps
1. 1 to N / 2
2. N / 2 + 1 to N
This is equivalent to 1 to N.
Also you program check for few additional checks after the loops which aren't actually required when you do it directly.
int min = a[0];
for(int i = 1; i < arr.length; i++)
if(min < a[i])
a[i] = min;
This is considered most efficient in finding out the minimum value.
When do I use divide and conquer
A divide and conquer algorithm works by recursively breaking down a problem into two or more sub-problems, until these become simple enough to be solved directly.
Consider the Merge Sort Algorithm.
Here, we divide the problem step by step untill we get smaller problem and then we combine them to sort them. In this case this is considered optimal. The normal runs in a O(n * n) and this runs in O(n log n).
But in finding the minimum the original has O(n). So this is good.
Divide And Conquer
The book
Data Structures and Algorithm Analysis in Java, 2nd edtition, Mark Allen Weiss
Says that a D&C algorithm should have two disjoint recursive calls. I.e like QuickSort. The above algorithm does not have this, even if it can be implemented recursively.
What you did here with code is correct. But there are more efficient ways of solving this code, of which i'm sure you're aware of.
Although divide and conquer algorithm can be applied to this problem, but it is more suited for complex data problem or to understand a difficult data problem by dividing it into smaller fragments. One prime example would be 'Tower of Hanoi'.
As far as your code is concerned, it is correct. Here's another copy of same code-
public class SmallestInteger {
public static void main(String[] args) {
int small ;
int array[] = {4,-2,8,3,56,34,67,84} ;
small = smallest(array) ;
System.out.println("The smallest integers is = " + small) ;
}
public static int smallest(int[] array) {
int array1[] = new int[array.length/2];
int array2[] = new int[array.length - (array.length/2)];
for (int index = 0; index < array.length/2 ; index++) {
array1[index] = array[index];
}
for (int index = array.length/2; index < array.length; index++) {
array2[index - array.length/2] = array[index] ;
}
if (array.length > 1) {
if(smallest(array1) < smallest(array2)) {
return smallest(array1) ;
}
else {
return smallest(array2) ;
}
}
return array[0] ;
}
}
Result came out to be-
The smallest integers is = -2