I am reading about algorithms by Robert Sedgewick book.
public static void sort(Comparable[] a)
{ // Sort a[] into increasing order.
int N = a.length;
for (int i = 1; i < N; i++)
{ // Insert a[i] among a[i-1], a[i-2], a[i-3]... ..
for (int j = i; j > 0 && less(a[j], a[j-1]); j--)
exch(a, j, j-1);
}
}
Above is insertion sort implementation in java. Here author mentiones as improvment as below.
It is not difficult to speed up insertion sort substantially, by shortening its inner loop to move the larger entries to the right one position rather than doing full exchanges (thus cutting the number of array accesses in half)
I am having difficutly in understanding above improvement. What does author mean by
Move large entries to the right one postion rather than full exchanges and how this will reduce array access to half.
Request to example with simple example for better understanding.
I think that he is referring to the fact that you don't need to keep on actually swapping elements, because you will end up repeatedly moving the same element.
For instance, you can cache the value of the i-th element initially, and refer just to this in the inner loop:
public static <C extends Comparable<C>> void insertionSort(C[] a) {
for (int i = 1; i < a.length; i++) {
C ithElement = a[i];
int j = i;
for (j = i; j > 0 && ithElement.compareTo(a[j - 1]) < 0; --j) {
// This is "moving the larger entry to the right 1 position"
a[j] = a[j - 1];
}
a[j] = ithElement;
}
}
Demo
Related
I'm trying to implement quicksort in Java to learn basic algorithms. I understand how the algo works (and can do it on paper) but am finding it hard to write it in code. I've managed to do step where we put all elements smaller than the pivot to the left, and larger ones to the right (see my code below). However, I can't figure out how to implement the recursion part of the algo, so sort the left and right sides recursively. Any help please?
public void int(A, p, q){
if(A.length == 0){ return; }
int pivot = A[q];
j = 0; k = 0;
for(int i = 0; i < A.length; i++){
if(A[i] <= pivot){
A[j] = A[i]; j++;
}
else{
A[k] = A[i]; k++;
}
}
A[j] = pivot;
}
Big Disclaimer: I did not write this piece of code, so upvotes is not needed. But I link to a tutorial which explains quicksort in detail. Gave me a much needed refreshment on the algorithm as well! The example given has very good comments that might just help you to wrap your head around it.
I suggest you adapt it to your code and write som tests for it to verify it works
Quicksort is a fast, recursive, non-stable sort algorithm which works by the divide and conquer principle. Quicksort will in the best case divide the array into almost two identical parts. It the array contains n elements then the first run will need O(n). Sorting the remaining two sub-arrays takes 2 O(n/2). This ends up in a performance of O(n log n).
In the worst case quicksort selects only one element in each iteration. So it is O(n) + O(n-1) + (On-2).. O(1) which is equal to O(n^2).*
public class Quicksort {
private int[] numbers;
private int number;
public void sort(int[] values) {
// check for empty or null array
if (values ==null || values.length==0){
return;
}
this.numbers = values;
number = values.length;
quicksort(0, number - 1);
}
private void quicksort(int low, int high) {
int i = low, j = high;
// Get the pivot element from the middle of the list
int pivot = numbers[low + (high-low)/2];
// Divide into two lists
while (i <= j) {
// If the current value from the left list is smaller than the pivot
// element then get the next element from the left list
while (numbers[i] < pivot) {
i++;
}
// If the current value from the right list is larger than the pivot
// element then get the next element from the right list
while (numbers[j] > pivot) {
j--;
}
// If we have found a value in the left list which is larger than
// the pivot element and if we have found a value in the right list
// which is smaller than the pivot element then we exchange the
// values.
// As we are done we can increase i and j
if (i <= j) {
exchange(i, j);
i++;
j--;
}
}
// This is the recursion part you had trouble with i guess?
// Recursion
if (low < j)
quicksort(low, j);
if (i < high)
quicksort(i, high);
}
private void exchange(int i, int j) {
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}
}
Link to tutorial
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
// gives next index in array which wraps around in a ring; moves clockwise through indices
private int nextSlot(int k) {
return ((k + 1) % A.length);
}
// Insert method
public void insert(int k) {
if( size == A.length)
resize();
A[next] = k;
for(int i = 0; i < next; i = nextSlot(i)) {
if(k < A[i]) {
for( int j = next - 1; j >= i; j--){
A[nextSlot(j)] = A[j];
}
A[i] = k;
break;
}
}
next = nextSlot(next);
size++;
}
I am trying to create an insert/sort method that inserts values into a circular priority queue in ascending order. The problem I'm having is when the next pointer cycles back to the beginning of the array, the items at the front of the queue aren't being sorted. I've been struggling with this for hours now, any help would be greatly appreciated.
Specifically, when next cycles back to the beginning, it's going to be 0, and therefore this for loop:
for(int i = 0; i < next; i = nextSlot(i)) {
will not do anything.
In general, however, I see several problems with your program. First of all, why are you implementing this as a circular array? Circular arrays are useful when you want to be able to quickly add/remove from both the beginning and end of an array. You seem to be inserting into the middle, so there is no reason to complicate your code when you're doing a linear search through the entire list at each insert anyway.
Finally, be aware that when operating on a circular array, you need to take into account that your indices will wrap around and become 0. Therefore, this line:
for( int j = next - 1; j >= i; j--)
is wrong for at least two reasons:
j>=i is not the correct way to find out if j has reached i
j-- is also wrong as j-1 needs to be wrapped
// 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!
As a homework I was assigned to write algorithm that finds k-th ordered number from unordered set of numbers. As an approach, algorithm median of medians has been presented.
Unfortunately, my attemp has failed. If anyone spots a mistake - please correct me.
private int find(int[] A, int size, int k) {
if (size <= 10) {
sort(A, 0, size);
return A[k];
} else {
int[] M = new int[size/5];
for (int i = 0; i < size / 5; i++) {
sort(A, i*5, (i+1) * 5);
M[i] = A[i*5 + 2];
}
int m = find(M, M.length, M.length / 2);
int[] aMinus = new int[size];
int aMinusIndex = 0;
int[] aEqual = new int[size];
int aEqualIndex = 0;
int[] aPlus = new int[size];
int aPlusIndex = 0;
for (int j = 0; j < size; j++) {
if (A[j] < m) {
aMinus[aMinusIndex++] = A[j];
} else if (A[j] == m) {
aEqual[aEqualIndex++] = A[j];
} else {
aPlus[aPlusIndex++] = A[j];
}
}
if (aMinusIndex <= k) {
return find(aMinus, aMinusIndex, k);
} else if (aMinusIndex + aEqualIndex <= k) {
return m;
} else {
return find(aPlus, aPlusIndex, k - aMinusIndex - aEqualIndex);
}
}
}
private void sort(int[] t, int begin, int end) { //simple insertion sort
for (int i = begin; i < end; i++) {
int j = i;
int element = t[i];
while ((j > begin) && (t[j - 1] > element)) {
t[j] = t[j - 1];
j--;
}
t[j] = element;
}
}
The test I'm running is to put numbers {200, 199, 198, ..., 1) and get 1st number from ordered array. I'm getting:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -13
Which is thrown at return A[k] line, because of recursive call:
return find(aPlus, aPlusIndex, k - aMinusIndex - aEqualIndex);
Your branching logic for the recursion step is backwards. You're trying to find the kth smallest number, and you've found that there are aMinusIndex numbers smaller than m, aEqualIndex equal to m, and aPlusIndex larger than m.
You should be searching in aMinus if aMinusIndex >= k, not if aMinusIndex <= k -- and so on.
(See this easily by looking at the extreme case: say there are zero numbers smaller than m. Then clearly you should not be searching for anything in an empty array, but because 0 <= k, you will be.)
I don't know exactly what your problem is, but you definitely should not be doing this:
sort(A, i*5, (i+1) * 5);
Also, you shouldn't do so much copying, you don't gain any performance when you do that. The algorithm is supposed to be done in place.
Check this wikipedia: Selection algorithm
I understand that this is homework, so your options might be constrained, but I don't see how the Median of Medians is all that useful here. Just sort the entire array using a standard algorithm, and pick the kth element. Median of medians helps find a very good pivot for the sort. For data of 200 length, you aren't going to save much time.
So far as I know, you can't accurately obtain a median, or a percentile, or the kth element, without ultimately sorting the entire input array. Using subsets yields an estimate. If this is wrong, I'd really like to know, as I recently worked on code to find percentiles in arrays of millions of numbers!
p.s. it could be that I don't completely understand your code...