Is this implementation of insertion considered correct? This is a little different from some other examples I have seen.
public static int[] insertionSort(int[] numbers) {
for (int i = 1; i < numbers.length; i++) {
int index = i;
for (int j = i-1; j >= 0 ; j--) {
if (numbers[index] < numbers[j]) {
int temp = numbers[index];
numbers[index] = numbers[j];
numbers[j] = temp;
index--;
}
}
}
return numbers;
}
Your logic is right, it should work and basically it is insertion sort, you are right. However, your algorithm will make unnecessary iterations with current implementation.
The inner loop will go through all the values which lie left to the i even if we already found the place to insert. As a result, your index value will point to the correct place, but the loop will go further, but the if condition won't be satisfied until the next i value.
To fix this you can just add the next:
else {
break;
}
It should finish the inner loop and go to the next value of the outer loop. However, it would be even better to replace inner loop with while to make the code more readable.
As for the complexity, your current code will work with O(n^2) complexity even for the sorted array. With such enhancement it still will be working on O(n^2) in average, but for the best case it will be improved to O(n).
Related
people of the internet,
I am studying algorithms and their complexity and I wrote a "naive" code for finding the number of inversions in an Array. First, it seemed easy and then I started wondering if that j=i+i changes the second loop's complexity from O(n) in a worst-case scenario to something lower ?
Here is my code written in java :
public static void naiveInversionCount(int[] T){
int count = 0;
for(int i = 0; i < T.length -1; i++){ // O(n)
for(int j = i+1; j < T.length; j++){ // O(n) ???
if(T[i]> T[j]) count++; // O(1)
}
}
System.out.println("Naive method returns : " + count);
}
Thank you very much
The outer loop runs exactly n times.
The inner loop runs n−1, n−2, …, 0 times per outer loop. That is, on average, n/2 times.
And count++ runs exactly once per loop.
Thus the nested loop runs 1·n(n/2) times, which is in 𝑂(n²).
I'm studying sorting algorithms, including selection sort, so i decided to write a method and it works fine, but when i checked the book it had 2 variables so i checked it and found that it's using a variable to store the current index and the other as temporary to swap
while mine had only the temporary variable that also stored the initial value in the index as the lowest, then compared it to the other values in the array and swapped if a larger value was found.
Here's my code:
public static void selectionSort(int[] arr){
int lowest;
for(int i = 0; i < arr.length - 1; i++){
lowest = arr[i];
for(int j = i+1; j<arr.length; j++){
if(arr[j]<lowest){
lowest = arr[j];
arr[j] = arr[i];
arr[i] = lowest;
}
}
}
}
and Here's the book's
public static void selectionSort(int[] list){
int min;
int temp;
for(int i = 0; i < list.length - 1; i++) {
min = i;
for(int j = i + 1; j < list.length; j++)
if( list[j] < list[min] )
min = j;
temp = list[i];
list[i] = list[min];
list[min] = temp;
}
}
so I looked on the web and all of them follow the same way as the book, so is my code bad or slower, or it is not considered Selection sort ?
sorry for any english mistakes :P
So, the original code works like this:
Start with the first element of the array
Find the smallest number in the array
Swap the two numbers
Repeat the process Until You reach the end of the list
While Yours does this:
Start with the first element of the array
For each element smaller than the current Swap the two numbers
Replace the lowest number with the swapped
Repeat the process
The result should be the same, but probably You are swapping more numbers than the first one. This probably will make it a little bit slower than the original.
Actually it kinda looks like the insertion sort now, so basically You are swapping the elements with all that are bigger than the one You have.
It looks like you're doing a lot more swaps in the nested for loop.
What happens if you do a sort of [4,3,2,1]? I think you'll have more swap operations than the actual selectionSort.
I'm not sure if your code is bad or slower.
SelectionSort is known to be correct, but it isn't fast either.
Here's the algorithm:
boolean findTripleA(int[] anArray) {
if (anArray.length <= 2) {
return false;
}
for (int i=0; i < anArray.length; i++) {
// check if anArray[i] occurs at least three times
// by counting how often it occurs in anArray
int count = 0;
for (int j = 0; j < anArray.length; j++) {
if (anArray[i] == anArray[j]) {
count++;
}
}
if (count >= 3) {
return true;
}
}
return false;
}
The algorithm is designed to determine whether an array contains at least one number that
occurs three times or more in the array. My job is to figure out what would be the worst-case for this array, and its time complexity.
My thinking is that the worst case would be if the algorithm had two occurrences of every entry (with the extra entry being unique if the array has an odd number of elements). In this case, the if statement within for (int j = 0; j < anArray.length; j++) is always violated twice for each pass through the array, forcing the computation to be performed twice, but the algorithm doesn't actually terminate until it has checked every element. I was thinking that this would have a time complexity of O(n^2).
Can anyone provide any insight into this one? Because I have a nagging suspicion that I'm incorrect, and if I am I'd like to figure out the correct answer and why it's correct.
The worst case is O(N^2), and it happens when you don't find a triplet.
If we're talking about pure running time, then when the if-statement condition is true comes into play (and then you'd also have to worry about things like branch prediction), but
if (anArray[i] == anArray[j]) {
count++;
}
takes O(1) time, whether the if-statement condition is true or not. So, for running time complexity, the whole function would take O(n2). This would happen in any case where either there aren't 3 occurrences, or the first occurrence of an element appearing 3 or more times is near the end ('near the end' may not actually be so near, but let's leave that for another day).
// A strange variation on a bubblesort I created inadvertently. I omitted the usual if a[j] >a[j+1] by mistake yet the code was still able to function perfectly. Would there be any advantage to using a bubblesort of this kind over a normal bubblesort.
public int[] bubbleSort(int[] a)
{
for (int i = 0; i < a.length - 1; i++)
{
for (int j = i + 1; j < a.length - 1; j++)
{
if (a[i] > a[j])
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
return a;
}
Notice that at the end of the first iteration of the outer loop, the first value in the array will necessarily be the minimum value in the array (do you see why?) After the second iteration, the second value will be the second-smallest value, and after the third iteration the third value will be the third-smallest value, etc.
(That said, I think there's a bug in your logic. The upper bound on j should be a.length rather than a.length - 1, since otherwise the last value in the array is never compared to anything else or moved.)
You might want to look into selection sort, which works by moving the smallest value in the array to the front, then the second-smallest, etc. The algorithm you've come up with is (essentially) a modified version of selection sort rather than a modified bubble sort.
Hope this helps!
here's my code that uses selection. i need to use a insertion and do not use temporary arrays or arraylist. i need help of how to do a insertion sort.
public static void sortStudents(ArrayList<Student> list)
{//selection sort
Student tempStudent;
int count1;
int count2;
int largest;
for (count1=0; count1<list.size()-1; count1++)
{
largest = 0;
for (count2=largest+1; count2<list.size()-count1; count2++)
{
if ((list.get(largest)).compareTo(list.get(count2)) < 0)
{
largest = count2;
}
}
tempStudent = list.get(list.size()-1-count1);
list.set(list.size()-1-count1, list.get(largest));
list.set(largest, tempStudent);
}
}
}
Both selection sort and insertion sort work quite similarly, by having a "not yet sorted" part of the list, and an "already sorted" part. In the beginning, the first one is the whole list, and the second part an empty list at the start or end. While sorting the "not yet sorted" part shrinks, while the "already sorted" part grows, by one element per iteration.
The difference between selection sort and insertion sort is this:
For selection sort, you search the minimum (or maximum) element of the "not yet sorted" part, remove it there and then add it to the end (or beginning) of the already sorted part.
For insertion sort, you take the next element of the "not yet sorted" part of the list, find it's insertion point in the "already sorted" part and insert it there.
This should be enough to change your selection sort to insertion sort.
You don't define variables outside the loop if it is only used in the loop. Restricting the lifetime of your variables makes it more easy to reason about the code.
public static void sortStudents (ArrayList<Student> list)
{
int largest;
for (int i=0; i < list.size () - 1; i++)
{
largest = 0;
for (int j=largest + 1; j < list.size () - i; j++)
{
if ((list.get (largest)).compareTo (list.get (j)) < 0)
{
largest = j;
}
}
Student tempStudent = list.get (list.size () - 1 - i);
list.set (list.size () - 1 - i, list.get (largest));
list.set (largest, tempStudent);
}
}
A bit more indentation makes your code more readable. Now what's your concrete error - doesn't it compile, throws it an exception or does it produce the wrong result?
Here is something suspicious in the inner loop:
largest = 0;
for (int j=largest + 1; j < list.size () - i; j++)
If you set largest to 0, then j will be initialized to 0 + 1 => 1. I guess you had another intention. Did you mean j = i + 1;?