I am learning the mechanics of Insertion Code. This is the original Insertion Code algorithm as described in several sites:
for (int i = 0; i < a.length; i++) {
int key = a[i];
int j = i;
while (j > 0 && a[j-1] > key) {
swap(a, j, j - 1);
j--;
}
a[j] = key;
}
The issue is while learning how it works, I realized that the next code without using a key, does exactly the same:
for (int i = 0; i < a.length; i++) {
int j = i;
while (j > 0 && a[j-1] > a[j]) {
swap(a, j, j - 1);
j--;
}
}
My question is, why is they key required in the original algorithm? is it needed for some edge cases that the second algorithm doesn't take into consideration? If so, which edge cases would them be?
After some testing the results of both algorithms perform the same amount of swaps, so I can't figure out what is the difference of having to use a key variable.
Related
I'm writing Shellsort in Java and found that adding a criteria in a for loop significantly improves the speed. Can someone explain why?
This is the fast code, 80ms for 10K Doubles.
public static void sort(Comparable[] a) {
if (a.length <= 1) {
return;
}
// Using 3K+1 starting from < N/3 as in the book
int magic = 1;
while (magic < a.length / 3) {
magic = 3 * magic + 1;
}
while (magic >= 1) {
for (int i = magic; i < a.length; i += 1) {
if (less(a[i - magic], a[i])) {
// Already in good order
continue;
}
for (int j = i; j >= magic && less(a[j], a[j - magic]); j -= magic) {
// if (less(a[j], a[j - magic])) {
exch(a, j, j - magic);
// }
}
/*
for (int j = 0; j < i; j += 1) {
if (less(a[i], a[j])) {
// j is the right place
// Use a series of exchanges to avoid creating new arrays
for (int k = i; k > j; k -= 1) {
exch(a, k-1, k);
}
break;
}
}
*/
}
magic /= 3;
}
}
The slow version (I'll just put the inner for loop here) which takes around 43,000ms
for (int j = i; j >= magic; j -= magic) {
if (less(a[j], a[j - magic])) {
exch(a, j, j - magic);
}
}
Please note that the less function simply check whether a[j] is smaller than a[j-magic].
From what I understand, in the fast code, we still check the less criteria for each loop, and if it doesn't satisfy we don't go inside the loop. In the slow version, we do go inside each loop and even less is not satisfied we don't do the exchange. What I don't understand is why the fast code is SO much faster? And is it the same for C++? (I could test the C++ part by myself)
Let's consider the slow version of the loop:
for (int j = i; j >= magic; j -= magic) {
if (less(a[j], a[j - magic])) {
exch(a, j, j - magic);
}
}
In this loop, we call less for each value of j, and for the values for which less return true, we call exch. This happens until j >= magic.
Now, let's look at the faster version:
for (int j = i; j >= magic && less(a[j], a[j - magic]); j -= magic) {
exch(a, j, j - magic);
}
In this version, we also call less for each value of j, but for the first value of j it returns false, the execution exits the loop. So, in this condition after the loop exits, it is not necessary that j < magic. As a result, many calls to exch and less are saved here, which results in optimization.
This will be the same for every language.
The problem is to count how many times my bubble sort algorithm switches the places of numbers. I tried to use a variable which increments by one each time, but I think there may be an error with scopes or something similar. Instead of returning a number such as 6 (which means numbers were swapped 6 times), it returns 0, which is what I initialized my variable as. How would I get my program to work?
public static int sort(int arr[]) {
int length = arr.length;
int temp;
int count = 0;
for (int i = 0; i < (length); i++) {
for (int j = 1; j < (length); j++) {
if (arr[j - 1] > arr[j]) {
temp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = temp;
count++;
}
}
}
return count;
}
Looks like your algorithm is not optimized because of your for loop condition and initialization. As a result you are comparing an element with itself which is redundant.
Proper approach should be like below:
int yourCounter = 0;
for (int i = 0; i < length; i++)
for (int j = 1; j < length-i; j++)
if (arr[j - 1] > arr[j]) {
//swap code
//yourCounter++;
}
your counter should give you proper result then.
I was reading up on sorting algorithms, I finished selection and bubble sort and thought I should try to implement what I understood.It took me while to understand what I wrote intending to be selection sort(code snippet-1) wasn't implementing key features of selection sort at all(which is finding min of unsorted array and building sorted array one element at a time). So I wrote one more for selection sort(code snippet-3). But now, I'm curious about Snippet-1. Can someone tell me if it is bubble sort or not?
Code Snippet-1
public void sort(int[] arr) {
// code snippet-1
int n = arr.length;
for (int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
if(arr[i] > arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
Code Snippet-2
public void sort(int[] arr) {
// code snippet-2
int n = arr.length;
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n-1; j++) {
if(arr[j] > arr[j+1]){
int temp=arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
Code Snippet-3
public void sort(int[] arr) {
// Code snippet-3
int n = arr.length;
for (int i = 0; i < n; i++) {
int min = i;
for(int j = i + 1; j < n; j++){
if(arr[j] < arr[min]) {
min = j;
}
}
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
Also, on a not so related account, can someone explain how the outer for loop condition (i.e i<n and i<n-1) doesn't affect the result in these cases? I only changed snippet-2's condition to j<n-1 as it gave me Arrayoutofbound error because of arr[j+1] term. Yes, I saw the entire thing in debug mode and animations too but still not completely clear how to choose a condition. I know I'm missing something here.
You have different approaches to bubble sort and the Arrayoutofbound exception is because of the comparison of n+1 element which is not there in the array.
In code snippet 2, you could also avoid one more loop by doing:
for (int i = 0; i <= n-2; i++)
I need to count the number of loops and comparisons which occur over four different sorting methods. I am using the Selection, Bubble, Insertion, and Quick sort methods. Ideally, I would just place a int such as loopCounter and ++ it every time it loops/compares. Although, being quite new to all of this, I am having trouble distinguishing when I need to include such counters. As you will be able to see in the following code, I attempted to create multiple counters. Although, I think only the selection counters are correct so far.
Additionally, I am required to count the number of times that a value is shifted. In other words, how many times integers are swapped.
Any help with this would be extremely appreciated!
Thanks
ArrayList<Integer> list = new ArrayList<Integer>();
//Counters for Selection Sort
int loopCounter = 0;
int compCounter = 0;
//Counters for Bubble Sort
int loopCounter2 = 0;
int compCounter2 = 0;
//Counters for Insertion Sort
int loopCounter3 = 0;
int compCounter3 = 0;
//Counters for Quick Sort
int loopCounter4 = 0;
int compCounter4 = 0;
public void selectionSort(Integer[] a) {
for(int i = 0; i < a.length; i++) {
int smallestValue = a[i];
int smallestIndex = i;
if(ascButton.isSelected()){
for(int j = i+1; j < a.length; j++) {
if (smallestValue > a[j]) {
smallestValue = a[j];
smallestIndex = j;
loopCounter++;
compCounter++;
}
}
a[smallestIndex] = a[i];
a[i] = smallestValue;
} else if(desButton.isSelected()){
for(int j = i+1; j < a.length; j++) {
if (smallestValue < a[j]) {
smallestValue = a[j];
smallestIndex = j;
loopCounter++;
compCounter++;
}
}
a[smallestIndex] = a[i];
a[i] = smallestValue;
}
}
}
public void bubbleSort(Integer[] a) {
int temp;
for (int i = a.length - 1; i > 0; i--) {
if(ascButton.isSelected()) {
for(int j = 0; j < i; j++) {
loopCounter2++;
compCounter2++;
if(a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
} else if(desButton.isSelected()) {
for(int j = 0; j < i; j++) {
loopCounter2++;
compCounter2++;
if(a[j] < a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
}
public void insertionSort(Integer[] a) {
for(int i = 1; i < a.length; i++) {
loopCounter3++;
compCounter3++;
int temp = a[i];
int j = i - 1;
if(ascButton.isSelected()) {
while(j >= 0 && a[j] > temp) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = temp;
} else if(desButton.isSelected()) {
while(j >= 0 && a[j] < temp) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = temp;
}
}
}
public void quickSort(Integer[] a, int left, int right) {
int i = left;
int j = right;
int temp;
int pivot = a[(left + right)/2];
while(i <= j) {
if(ascButton.isSelected()) {
while(a[i] < pivot)
i++;
while(a[j] > pivot)
j--;
} else if(desButton.isSelected()) {
while(a[i] > pivot)
i++;
while(a[j] < pivot)
j--;
}
if(i <= j) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
}
if(left < j) {
quickSort(a,left,j);
}
if(i < right) {
quickSort(a, i, right);
}
}
With counters, you simply want to "count" when you want to program to count something. So if you don't understand your own code, then it will be difficult to know when you want to "count" something. I suggest you figure out when a swap is happening, when that is happening in your code, that is when you want to do some sort of:
swapCount++;//Each time a swap happens increment by 1
iterationCount++//A full pass has happened increment by 1
Note: above just because a full pass has happened in many sort, which you probably know, does not mean it is sorted, it is just saying it has done 1 pass.
I'm not sure if this theory will help you any. Give me some feedback on what your still having trouble with and I'll see if I can change my answer to better reflect what your looking for.
As #Andreas suggested, your loop and comparison counters are in place correctly.
As far as the swap counter is concerned, think of it this way - you cannot swap without a temp variable. As a result, whenever a temp variable is involved you want to increase your swap counter.
As an example, for your quicksort, it would look like this:
public void quickSort(Integer[] a, int left, int right) {
int i = left;
int j = right;
int temp;
int pivot = a[(left + right)/2];
while(i <= j) {
if(ascButton.isSelected()) {
while(a[i] < pivot)
i++;
while(a[j] > pivot)
j--;
} else if(desButton.isSelected()) {
while(a[i] > pivot)
i++;
while(a[j] < pivot)
j--;
}
if(i <= j) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
swapCounterForQuickSort++;
}
}
if(left < j) {
quickSort(a,left,j);
}
if(i < right) {
quickSort(a, i, right);
}
}
Follow the same logic for your other sorts.
Also, some general suggestions:
Always name variables so that they tell you what they are used for. Rather than loopCounter1 try using loopCounterForSelectionSort and so on. Don't be afraid of long variable names. Information is power!
Make your functions as short and reusable as possible. For example, you swap integers a lot in your code. Maybe you can just copy the swap code and paste it into a swapIntegers() function. Then everytime you just call this function when you want to swap! Also, notice how this makes your swap counter question easier to answer since you can put a counter in the swap method to do the counting for you. (Although be aware since multiple methods will call the swap counter so you may want to pass it as an argument etc.)
I am doing insertion sort and was wondering if the number of comparisons made and number of moves made were calculated properly. Comparisons are the number of times two values were compared and moves are the number of elements moved, so a swap between numbers will be 2 moves.
public static int[] InsertionSort(int[] a) {
int j;
for(int i = 1; i < a.length; i++) {
int tmp = a[i];
for(j = i; j > 0 && (tmp < a[j-1]); j--) {
numCompares++;
a[j] = a[j-1];
numMoves++;
}
a[j] = tmp;
numMoves++;
}
return a;
}
The only problem here is that in inner loop condition j > 0 && (tmp < a[j-1]), actual comparison tmp < a[j-1] may result false, causing break of for loop, so numCompares++ which is located inside the loop will be skipped. To count comparisons precisely, small reformat is required:
for(j = i; j > 0; j--) {
numCompares++;
if (tmp >= a[j - 1])
break;
a[j] = a[j - 1];
numMoves++;
}