I am trying to understand the 3-way radix Quicksort, and i dont understand why the the CUTOFF variable there? and the insertion method?
public class Quick3string {
private static final int CUTOFF = 15; // cutoff to insertion sort
// sort the array a[] of strings
public static void sort(String[] a) {
// StdRandom.shuffle(a);
sort(a, 0, a.length-1, 0);
assert isSorted(a);
}
// return the dth character of s, -1 if d = length of s
private static int charAt(String s, int d) {
assert d >= 0 && d <= s.length();
if (d == s.length()) return -1;
return s.charAt(d);
}
// 3-way string quicksort a[lo..hi] starting at dth character
private static void sort(String[] a, int lo, int hi, int d) {
// cutoff to insertion sort for small subarrays
if (hi <= lo + CUTOFF) {
insertion(a, lo, hi, d);
return;
}
int lt = lo, gt = hi;
int v = charAt(a[lo], d);
int i = lo + 1;
while (i <= gt) {
int t = charAt(a[i], d);
if (t < v) exch(a, lt++, i++);
else if (t > v) exch(a, i, gt--);
else i++;
}
// a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi].
sort(a, lo, lt-1, d);
if (v >= 0) sort(a, lt, gt, d+1);
sort(a, gt+1, hi, d);
}
// sort from a[lo] to a[hi], starting at the dth character
private static void insertion(String[] a, int lo, int hi, int d) {
for (int i = lo; i <= hi; i++)
for (int j = i; j > lo && less(a[j], a[j-1], d); j--)
exch(a, j, j-1);
}
// exchange a[i] and a[j]
private static void exch(String[] a, int i, int j) {
String temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// is v less than w, starting at character d
private static boolean less(String v, String w, int d) {
assert v.substring(0, d).equals(w.substring(0, d));
return v.substring(d).compareTo(w.substring(d)) < 0;
}
// is the array sorted
private static boolean isSorted(String[] a) {
for (int i = 1; i < a.length; i++)
if (a[i].compareTo(a[i-1]) < 0) return false;
return true;
}
public static void main(String[] args) {
// read in the strings from standard input
String[] a = StdIn.readAll().split("\\s+");
int N = a.length;
// sort the strings
sort(a);
// print the results
for (int i = 0; i < N; i++)
StdOut.println(a[i]);
}
}
from http://www.cs.princeton.edu/algs4/51radix/Quick3string.java.html
It would appear to be used in order to invoke insertion sort for sufficiently small (size <= 15) arrays. This is most likely to speed up sorting.
It's a simple optimization of quicksort algorithm. The cost of recursive calls in quicksort are quite high, so for small arrays insertion sort works better. So, the idea is, that if length of subarray to be sorted os below certain threshold, it's better to sort it using insertion sort than quicksort. In your example, CUTOFF variable defines that threshold, i.e. if less than 15 elements are left, they are sorted using insertion sort instead of quicksort.
The sort method above is a recursive method. And every recursive method should have some kind of base case (otherwise it will keep calling itself, eventually leading to a stack overflow).
The insertion part is the base case in that method, because at every recursive step, the hi-lo difference keeps decreasing, & when its less than CUTOFF, the insertion sort will eventually be triggered, forcing the recursion to stop.
if (hi <= lo + CUTOFF) { // base case
insertion(a, lo, hi, d);
return;
}
Now, why insertion ? Because it works well for small arrays.
More on sorting here: http://www.sorting-algorithms.com/
This idea comes from Robert Sedgewick, who knows more about Quicksort than probably any man alive. It is cited in Donald E. Knuth, The Art of Computer Programming, Volume III, where he shows that for small M, insertion sort is faster than Quicksort, so he recommends not sorting small partitions < M at all and leaving it to one final insertion sort over the whole data set at the end. Knuth gives a function for calculating M (which is your CUTOFF), and which is 9 for his MIX pseudo-computer.
Related
I was completing some practice problems today on HackerRank, and on a problem asking me to write an algorithm that left-shifts all elements in an array n-times (i.e. rotLeft({1, 2, 3, 4, 5}, 1) returns {2, 3, 4, 5, 1}), I ran into the classic timeout error due to my algorithm being inefficient. This isn't the first time I have been dinged for inefficient algo writing by an online coding system. Really I have two questions: 1) How can I specifically rewrite my left-shift algorithm to be more time-efficient? 2) In general, how do I improve performance-wise upon an algorithm which runs inefficiently?
public static final int NULL = -2147483648;
static int[] rotLeft(int[] a, int d) {
return rotLeftRec(a, d, 0);
}
static int[] rotLeftRec(int[] a, int d, int numRot) {
if (numRot >= d) {
return a;
} else {
int first = a[0];
int temp1 = NULL;
int temp2 = NULL;
for (int i = a.length - 1; i >= 0; i--) {
if (i == a.length - 1) {
temp1 = a[i];
} else {
if (temp1 == NULL) {
temp1 = a[i];
a[i] = temp2;
temp2 = NULL;
} else {
temp2 = a[i];
a[i] = temp1;
temp1 = NULL;
}
}
}
a[a.length - 1] = first;
}
return rotLeftRec(a, d, numRot + 1);
}
I was curious about the arraycopy approach, looks like this. There's no need to call the method proposed here m times where you shift the array by n each time. You can call it with the product m*n and you're there as well (I think). Would be curious if that one passes.
Btw. ArrayList uses arrayCopy, I got it from there.
static int[] rotLeft(int[] a, int d) {
if (d < 0 || a == null || a.length == 0) {
throw new IllegalArgumentException();
}
int shift = d % a.length;
if (shift == 0) {
return a;
}
int[] result = new int[a.length];
System.arraycopy(a, shift, result, 0, a.length - shift);
System.arraycopy(a, 0, result, a.length - shift, shift);
return result;
}
You recurse for d times shifting once. That is inefficient as you can immediately find the correct value at index i by i+d % a.length.
The point is left-rotating by d would seem to need multiple variables. For this you should use recursion.
static void rotLeft(int[] a, int d) {
rotLeftRec(a, d, 0);
}
static void rotLeftRec(int[] a, int d, int i) {
if (i >= a.length) {
return;
}
int j = (i + d) % a.length;
int aj = a[j];
rotLeftRec(a, d, i + 1);
a[i] = aj;
}
The trick is, that after coming back from the recursion you fill in the data a[i] with the value of a[j] you remembered before the recursive call.
You see, that the recursion enables you to hold a stack of i and aj.
Implementing such recursion is doing the simple step and looking at the time line of variables, what should be remembered beforehand, what future partial result is needed (some return value of a recursive call).
Transformation to iterative version (still further optimizable)
static void rotLeft(int[] a, int d) {
int[] stack = new int[a.length];
for (int i = 0; i < a.length; ++i) {
int j = (i + d) % a.length;
int aj = a[j];
stack[i] = aj;
}
System.arraycopy(stack, 0, a, 0, a.length);
}
I have the following programm calculating the binomial coefficient of two integers. But I want to change the programm, that it calculates and saves only the necessary coefficients for the solution.
The problem is that I have really no idea how to it, right now.
The Code
public static long binomialIteration(int n, int k)
{
if(k<0 || n<k)
{
return 0;
}
long[][] h= new long[n+1][n+1];
for(int i=0; i<=n; i++)
{
h[i][0]=h[i][i]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=0; j<=i; j++)
{
h[i][j] = (j==0 ? 0: h[i-1][j-1]) + (i == j ? 0 : h[i-1][j]);
}
}
return h[n][k];
}
Do you want to keep your code afterall?
Because you can also compute the binominal coefficient recursively, which would reduce your function to these 4 lines:
static long binomi(int n, int k) {
if ((n == k) || (k == 0))
return 1;
else
return binomi(n - 1, k) + binomi(n - 1, k - 1);
}
What about this Code from this site
private static long binomial(int n, int k)
{
if (k>n-k)
k=n-k;
long b=1;
for (int i=1, m=n; i<=k; i++, m--)
b=b*m/i;
return b;
}
You don't say which coefficients youi need. If you need C(N,n) for some fixed N, you could translate the C code below, which uses a one dimensional array.
After the call, C[n] will hold the binomial coefficient C(N,n) for 0<=m<=N, as long as N is at most 66 -- if you need bigger N you will need to use an integral type with more bits.
static int64_t* pascals_triangle( int N)
{
int n,k;
int64_t* C = calloc( N+1, sizeof *C);
for( n=0; n<=N; ++n)
{ C[n] = 1;
k = n;
while( --k>0)
{ C[k] += C[k-1];
}
}
return C;
}
Hello I have written QuickSort with stack but I'm not sure this alghoritm is using O(n) extra space or O(log n) extra space which I want to make.
I will be very thankful if somebody could look at this code and tell me what extra space uses here stack and if it uses O(n) extra space how to do it to use only O(log n) extra space?
Here is my code
public class QuickSortStack{
public static void quickSortStack(int[] tab, int L, int R) {
Stack<Integer> stack = new Stack();
while (L < R || !stack.isEmpty()) {
if (L < R) {
int q = lomutoPartition(tab, L, R);
stack.push(R);
R = q - 1;
} else {
L = R + 2;
R = stack.pop();
}
}//end of while
}//end of QS method
public static void main(String[] args) {
int[] test= {-4,2,-4,2,-12,5,-1,6,-9,0,9};
Random random = new Random();
int[] tab= new int[20];
for (int i = 0; i < 20; i++) {
tab[i] = random.nextInt(50);
System.out.print(tab[i] + " ");
}
System.out.println();
quickSortStos(tab, 0, tab.length - 1);
for (int x : tab
) {
System.out.print(x + " ");
}
}
public static void swap(int[] tab, int i, int j) {
int tmp = tab[i];
tab[i] = tab[j];
tab[j] = tmp;
}
public static int lomutoPartition(int[] tab, int L, int R){
int i = L-1;
int x = tab[R];
for(int j = L; j < R; j++){
if(tab[j] <= x){
i = i+1;
swap(tab, i, j);
}
}
swap(tab, i+1, R);
return i+1;
}
In order to guarantee O(log N) space usage, you need to push the larger of the two partitions and loop with the smaller one. That's equivalent to a recursive solution where the non-tail recursion is always the smaller partition, guaranteeing a stack depth of no more than log2N.
When you do that, you will need to push both boundaries of the partition, or at least a boolean which tells you whether it was the first or second partition.
Fwiw, the common experience is that the iterative solution is not faster than a recursive solution. The recursive implementation is safe as long as you tail-call optimize the second recursion (for the larger partition); if your language doesn't guarantee TCO, it's easy to do it by hand.
Firstly (as the question title implies) I'm not looking for why the bellow partitioning method doesn't work, rather a modification to it so that it will work for the following input:
int[] a = {1,2,8,4,5,7};
Here's the partition method along with some other stuff:
static int[] swap (int[] a,int i,int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
return a;
}
static int partition (int[] a,int l,int r){
int i = l;
int j = r;
int v = a[l];
while (true) {
while (a[i] < v) {
if (i == r) break;
i++;
}
while (a[j] > v) {
if (j == l) break;
j--;
}
if (i >= j) break;
a = swap(a,i,j);
}
a = swap(a, l, j);
return j;
}
void sort(int[] a,int l,int r){
int j = partition(a, l, r);
sort(a, l, j-1);
sort(a, j+1, r);
}
public static void main(String[] args) {
int[] a = {1,2,8,4,5,7};
System.out.println(partition(a,0,5));
}
Output:
0
The output is the index of the pivot returned from the partition method. 0, as the index of the pivot, makes sense in terms of the definition, i.e. everything left of the pivot is smaller and everything right of the pivot is larger, but clearly runs into a problem in sort namely:
sort(a, l, j-1);
where you have the right pointer being negative (j-1 = 0-1 = -1). My question again being is there a modification to the above method(s) that will maintain the definition (everything left of the pivot is smaller and everything right of the pivot is larger) and not run into the problem in sort.
The missing part is the line
if ( l >= r ) return;
in the beginning of the sort method. This is actually the recursion stop step so it is necessary to have it anyway to prevent endless recursion. But besides that, it also solves your problem, because if you call sort(0,-1) then -1 is less than 0, so it prevents further processing of that index.
I am working on a quicksort from my data structures and algorithms book. In the book it lists a quicksort method then a hoare partition that it wants you to use with the quick sort. I seem to be having an issue where my hoare partition is using out of bounds numbers on the array. Either it uses 8 or if I try to fix that it goes to -1. Am I converting the books pseudo correctly into java?
Quicksort pseudo code
QuickSort(A, p, r)
if p<r
q = partition(A, p, r);
QuickSort(A, p, q - 1);
QuickSort(A, q, r);
Hoare-Partition Pseudo Code
Hoare-Partition(A,p,r)
x= A[p]
i = p-1
j=r+1
while true
repeat
j=j-1
until A [j] <= x
repeat
i = i +1
until A[i] >= x
if i < l
exchange A[i] with A[j]
else return j
My code
public class RunSort {
/**
* #param args
*/
public static void main(String[] args) {
int[] sortNumbers = {4,5,6,2,3,7,2,1};
int[] sorted = new int[sortNumbers.length];
sorted = QuickSort(sortNumbers, 1, sortNumbers.length);
System.out.print(sorted);
}
public static int[] QuickSort(int[] A, int p, int r){
if(p < r){
int q = partition(A, p, r);
QuickSort(A, p, q - 1);
QuickSort(A, q, r);
}
return A;
}
public static int partition(int[] A, int p, int r){
int x = A[p];
int i = p - 1;
int j = r + 1;
int temp;
while(true){
while(A[j] <= x && j != 0){
j--;
}
while(A[i] >= x && i != A.length){
i++;
}
if(i < j){
temp = A[i];
A[i] = A[j];
A[j] = temp;
}else{
return j;
}
}
}
}
Hint: repeat {...} until (condition) does not do the same thing as while (condition) {...}.
Depending on the text, pseudocode often uses 1..arrayLength as the index bounds on an array, but in Java, et al., it's 0..arrayLength-1. You'll need to adjust the arguments to the main QuickSort call in main.
(As a nitpick, QuickSort should start with a lowercase letter by convention.)