/* deadxc is also NOT used by FourSort. It is employed for a test to invoke cut3duplicates */ void deadxc(int N, int M, int depthLimit) { if ( depthLimit <= 0 ) { heapc(A, N, M); return; } int L = M - N; if ( L < cut3Limit ) { quicksort0c(N, M, depthLimit); return; } depthLimit--; int pivotx; int midpointx = (M+N)/2; if ( L <= 30 ) { // being defensive pivotx = med(A, N, midpointx, M, compareXY); } else { int step = L * 0.1; int P = med(A, N + step, N + 2*step, N + 3*step, compareXY); int Q = med(A, midpointx - step, midpointx, midpointx + step, compareXY); int R = med(A, M - 3*step, M - 2*step, M - step, compareXY); pivotx = med(A, P, Q, R, compareXY); } void deadxc(); cut3duplicates(N, M, pivotx, deadxc, depthLimit); } // end deadxc
// Cut2c does 2-partitioning with one pivot. // Cut2c invokes dflgm when trouble is encountered. void cut2c(void **A, int N, int M, int depthLimit, int (*compareXY)()) { int L; Start: L = M - N + 1; if ( L <= 1 ) return; // /* if ( L < 8 ) { // insertionsort insertionsort(A, N, M, compareXY); return; } // */ if ( depthLimit <= 0 ) { heapc(A, N, M, compareXY); return; } depthLimit--; // /* if ( L < cut2Limit ) { // This alternative over esaping to quicksort0c reduced 1/2% comparions int middlex = N + (L>>1); // N + L/2; int p0 = middlex; if ( 7 < L ) { int pn = N; int pm = M; if ( 51 < L ) { int d = (L-2)>>3; // L/8; pn = med(A, pn, pn + d, pn + 2 * d, compareXY); p0 = med(A, p0 - d, p0, p0 + d, compareXY); pm = med(A, pm - 2 * d, pm - d, pm, compareXY); }
void cut2c(int N, int M, int depthLimit) { int L; Start: if ( depthLimit <= 0 ) { heapc(A, N, M); return; } L = M - N; if ( L < cut2Limit ) { quicksort0c(N, M, depthLimit); return; } depthLimit--; // Check for duplicates int sixth = (M - N + 1) / 6; int e1 = N + sixth; int e5 = M - sixth; int e3 = (N+M) / 2; // The midpoint int e4 = e3 + sixth; int e2 = e3 - sixth; // Sort these elements using a 5-element sorting network void *ae1 = A[e1], *ae2 = A[e2], *ae3 = A[e3], *ae4 = A[e4], *ae5 = A[e5]; void *t; // if (ae1 > ae2) { t = ae1; ae1 = ae2; ae2 = t; } if ( compareXY(ae1, ae2) > 0 ) { t = ae1; ae1 = ae2; ae2 = t; } if ( compareXY(ae4, ae5) > 0 ) { t = ae4; ae4 = ae5; ae5 = t; } if ( compareXY(ae1, ae3) > 0 ) { t = ae1; ae1 = ae3; ae3 = t; } if ( compareXY(ae2, ae3) > 0 ) { t = ae2; ae2 = ae3; ae3 = t; } if ( compareXY(ae1, ae4) > 0 ) { t = ae1; ae1 = ae4; ae4 = t; } if ( compareXY(ae3, ae4) > 0 ) { t = ae3; ae3 = ae4; ae4 = t; } if ( compareXY(ae2, ae5) > 0 ) { t = ae2; ae2 = ae5; ae5 = t; } if ( compareXY(ae2, ae3) > 0 ) { t = ae2; ae2 = ae3; ae3 = t; } if ( compareXY(ae4, ae5) > 0 ) { t = ae4; ae4 = ae5; ae5 = t; } A[e1] = ae1; A[e2] = ae2; A[e3] = ae3; A[e4] = ae4; A[e5] = ae5; // Fix end points if ( compareXY(ae1, A[N]) < 0 ) iswap(N, e1, A); if ( compareXY(A[M], ae5) < 0 ) iswap(M, e5, A); int duplicate = -1; // if ( ae1, ae5 ) { duplicate = e1; } else if ( compareXY(ae1, ae5) == 0 ) { duplicate = e1; } else if ( compareXY(ae1, ae4) == 0 ) { duplicate = e1; } else if ( compareXY(ae2, ae5) == 0 ) { duplicate = e2; } else if ( compareXY(ae1, ae3) == 0 ) { duplicate = e1; } else if ( compareXY(ae2, ae4) == 0 ) { duplicate = e2; } else if ( compareXY(ae3, ae5) == 0 ) { duplicate = e3; } else if ( compareXY(ae1, ae2) == 0 ) { duplicate = e1; } else if ( compareXY(ae2, ae3) == 0 ) { duplicate = e2; } else if ( compareXY(ae3, ae4) == 0 ) { duplicate = e3; } else if ( compareXY(ae4, ae5) == 0 ) { duplicate = e4; }; if ( 0 <= duplicate ) { void cut2c(); cut3duplicates(N, M, duplicate, cut2c, depthLimit); return; } register void *T = ae3; // pivot // test to play safe: // if ( T <= A[N] || A[M] < T ) { if ( compareXY(T, A[N]) <= 0 || compareXY(A[M], T) < 0 ) { // give up because cannot find a good pivot quicksort0c(N, M, depthLimit+1); return; } register int I, J; // indices register void *AI, *AJ; // array values // initialize running indices I= N; J= M; // The left segment has elements < T // The right segment has elements >= T Left: I = I + 1; AI = A[I]; // if (AI < T) goto Left; if ( compareXY( AI, T) < 0 ) goto Left; Right: J = J - 1; AJ = A[J]; // if ( T <= AJ ) goto Right; if ( compareXY( T, AJ) <= 0 ) goto Right; if ( I < J ) { A[I] = AJ; A[J] = AI; goto Left; } if ( (I - N) < (M - J) ) { // smallest one first cut2c(N, J, depthLimit); N = I; goto Start; } cut2c(I, M, depthLimit); M = J; goto Start; } // (* OF cut2; *) ... the brackets reminds that this was Pascal code
// Quicksort equipped with a defense against quadratic explosion; // calling heapsort if depthlimit exhausted void quicksort0c(int N, int M, int depthLimit) { // printf("Enter quicksort0c N: %d M: %d %d\n", N, M, depthLimit); while ( N < M ) { int L = M - N; if ( L <= 10 ) { insertionsort(N, M); return; } if ( depthLimit <= 0 ) { heapc(A, N, M); return; } depthLimit--; // 10 < L // grab median of 3 or 9 to get a good pivot int pn = N; int pm = M; int p0 = (pn+pm)/2; if ( 40 < L ) { // do median of 9 int d = L/8; pn = med(A, pn, pn + d, pn + 2 * d, compareXY); p0 = med(A, p0 - d, p0, p0 + d, compareXY); pm = med(A, pm - 2 * d, pm - d, pm, compareXY); /* Activation of the check for duplicates gives a slow down of 1/4% on uniform input. If you suspect that duplicates causing quadratic deterioration are not caught higher-up by cut3 you may want to experiment with this check:::: if ( L < 100 ) { // check for duplicates int duplicate = -1; if ( compareXY(A[pn], A[pm]) == 0 ) { duplicate = pn; } else if ( compareXY(A[pn], A[p0]) == 0 ) { duplicate = pn; } else if ( compareXY(A[pm], A[p0]) == 0 ) { duplicate = pm; }; if ( 0 < duplicate ) { void quicksort0(); cut3duplicates(N, M, duplicate, quicksort0, depthLimit); return; } } */ } p0 = med(A, pn, p0, pm, compareXY); // p0 is index to 'best' pivot ... iswap(N, p0, A); // ... and is put in first position as required by quicksort0c register void *p = A[N]; // pivot register int i, j; i = N; j = M; register void *ai; void *aj; /* Split array A[N,M], N<M in two segments using pivot p; construct a partition with A[N,i), A(i,M] and N <= i <= M, and N <= k <= i -> A[k] <= p and i < k <= M -> p < A[k]; Allow the worse cases: N=i or i=M. Recurse on A[N,i) and A(i,M) (or in the reverse order). This code does NOT do swapping; instead it disposes ai/aj in a hole created by setting aj/ai first. */ /* Start state: |-------------------------------| N=i j=M N = i < j = M N <= k < i -> A[k] <= p N < j < k <= M -> p < A[k] A[N] = p N < i -> p < A[i] */ while ( i < j ) { /* |-------o---------------[--------| N i j M N <= i < j <= M N <= k < i -> A[k] <= p N < j < k <= M -> p < A[k] A[N] <= p N < i -> p < A[i] p + A[N,i) + A(i,M] is a permutation of the input array */ aj = A[j]; while ( compareXY(p, aj) < 0 ) { /* |-------o---------------[--------| N i j M N = i < j <= M or N < i <= j <= M N <= k < i -> A[k] <= p N < j <= k <= M -> p < A[k] A[N] <= p N < i -> p < A[i} p + A[N,i) + A(i,M] is a permutation of the input array p < aj = A[j] */ j--; aj = A[j]; } /* |-------o---------------[--------| N i j M N = i = j < M or N < i & = i-1 <= j <= M N <= k < i -> A[k] <= p j < k <= M -> p < A[k] A[N] <= p N < i -> p < A[i} p + A[N,i) + A(i,M] is a permutation of the input array aj = A[j] <= p */ if ( j <= i ) { /* |-------o-----------------------| N i M N = i = j < M or N < i & = i-1 = j < M N <= k < i -> A[k] <= p i < k <= M -> p < A[k] A[N] <= p p + A[N,i) + A(i,M] is a permutation of the input array */ break; } // i < j A[i] = aj; // fill hole ! /* |-------]---------------o--------| N i j M N <= i < j <= M N <= k <= i -> A[k] <= p j < k <= M -> p < A[k] A[N] <= p p + A[N,j) + A(j,M] is a permutation of the input array aj = A[j] <= p */ i++; ai = A[i]; while ( i < j && compareXY(ai, p) <= 0 ) { /* |-------]---------------o--------| N i j M N < i < j <= M N <= k <= i -> A[k] <= p j < k <= M -> p < A[k] A[N] <= p p + A[N,j) + A(j,M] is a permutation of the input array aj = A[j] <= p */ i++; ai = A[i]; } if ( j <= i ) /* |----------------------o--------| N i=j M N < i = j <= M N <= k < i -> A[k] <= p j < k <= M -> p < A[k] A[N] <= p p + A[N,j) + A(j,M] is a permutation of the input array */ break; // i < j & p < ai = A[i] A[j] = ai; j--; /* |--------o--------------[--------| N i j M N < i <= j <= M N <= k < i -> A[k] <= p j < k <= M -> p < A[k] A[N] <= p N < i -> p < ai = A[i] p + A[N,i) + A(i,M] is a permutation of the input array */ } A[i] = p; /* |--------]----------------------| N i M N <= i <= M N <= k <= i -> A[k] <= p i < k <= M -> p < A[k] A[N] <= p A[N,i] + A(i,M] is a permutation of the input array */ // Recurse on the smallest one and iterate on the other one int ia = i-1; int ib = i+1; if ( i-N < M-i ) { if ( N < ia ) quicksort0c(N, ia, depthLimit); N = ib; } else { if ( ib < M ) quicksort0c(ib, M, depthLimit); M = ia; } } } // end of quicksort0c