Algorithm Alley by Mingfu Gong Example 1 gsort1() running time <= gLoop*N/2 + 2*gLoop*N*log(N)/log(N2/N1). Example 2 gsort2() running time <= (gLoop+2)*N/2 + 2*N*log(N)/log(N2/N1) + 2*(gLoop-1)*N*log(log(N))/log(N2/N1). Example 3 1/2 < GNDR <= 2/3 Listing One // adaptive group sort - 1: running time <= gLoop*N/2 + // 2*gLoop*N*log(N)/log(N2/N1). long gsort1(long *array, long N, long N1, long N2) { long numGroup; // number of groups long gLoop = 0; // number of AGS loops do { // AGS loop numGroups = N ; while (numGroups > 1) { // group-sort loop // update numGroup numGroup = numGroup * N1 / N2; for (i = 0; i < N-numGroup; i++) { //bidirectional bubble-sort loop cmprSwap2(array[i], array[i+numGroup]); cmprSwap2(array[N-1-i-numGroup], array[N-1-i]); } } gLoop++; } while (!isSortedArray(array, N)); return gLoop; } Listing Two //adaptive group sort - 2: running time <= (gLoop+2)*N/2 + // 2*N*log(N)/log(N2/N1) + 2*(gLoop-1)*N*log(log(N))/log(N2/N1). long gsort2(long *array, long N, long N1, long N2) { long maxNumGroup; // maximum group number long numGroup; // number of groups long divider; // to calculate numGroup long oldDivider; // to calculate numGroup long gLoop = 0; // number of AGS loops long i; // pre-process to reduce number of swaps; maxNumGroup = N / 2; for ( i = 0; i < maxNumGroup; i++ ) { cmprSwap2(array[i], array[N-1-i]); } maxNumGroup = N; while (!isSortedArray(array, N)) { // AGS loop gLoop++; numGroups = maxNumGroup; oldDivider = divider = 1; while (numGroups > 1) { // group-sort loop // update numGroup divider = divider * N2 / N1; if (divider == oldDivider) divider++; oldDivider = divider; numGroup = maxNumGroup / divider; if (0 == numGroup) numGroup = 1; for (i = 0; i < N - numGroup; i++) { // bidirectional // bubble-sort loop cmprSwap2(array[i], array[i+numGroup]); cmprSwap2(array[N-1-i-numGroup], array[N-1-i]); } } maxNumGroup = log(N); //reset maxNumGroup; } return gLoop; } Listing Three //adaptive group sort - 3 long gsort2(long *array, long N, long N1, long N2) { long maxNumGroup; // maximum group number long numGroup; // number of groups long divider; // to calculate numGroup long oldDivider; // to calculate numGroup long gLoop = 0; // number of AGS loops long i; // pre-process to reduce number of swaps; maxNumGroup = N / 2; for ( i = 0; i < maxNumGroup; i++ ) { cmprSwap2(array[i], array[N-1-i]); } maxNumGroup = N; while (!isSortedArray(array, N)) { // AGS loop gLoop++; numGroups = maxNumGroup; oldDivider = divider = 1; while (numGroups > 1) { // group-sort loop // update numGroup divider = divider * N2 / N1; if (divider == oldDivider) divider++; oldDivider = divider; numGroup = maxNumGroup / divider; if (0 == numGroup) numGroup = 1; if (numGroup < 2*log(N)) { //reset GNDR N1 = 2; N2 = 3; } for (i = 0; i < N - numGroup; i++) { // bidirectional // bubble-sort loop cmprSwap2(array[i], array[i+numGroup]); cmprSwap2(array[N-1-i-numGroup], array[N-1-i]); } } maxNumGroup = log(N); //reset maxNumGroup; } return gLoop; } Listing Four // similar interface as qsort(); Depends on compiler, template normally // slower than simular C/C++ functions. template void gsort(T *array, int arraySize, int (*ComparisonPointer)(const T*, const T*)) { T tmp; int maxStep; // maximum group number int step; // number of groups int divider; // to calculate step int oldDivider; // to calculate step int logN; int i, j; int N1, N2; boolean firstSet = TRUE; if (NULL == array || 1 >= arraySize ) return; if (sizeof(T) >= 8) { //set GNDR by swaping cost. N1 = 2; N2 = 3; } else { N1 = 5; N2 = 9; } // pre-processing; maxStep = arraySize / 2; for (i = 0, j = arraySize-1; i < maxStep; i++, j--) { if (ComparisonPointer(&array[i], &array[j]) > 0) { tmp = array[i]; array[i] = array[j]; array[j] = tmp; } } if (2 == arraySize) return; logN = (int) (log((double)arraySize)); if (logN < 2) logN = 2; maxStep = arraySize; while (TRUE) { //AGS loop; for (i = arraySize - 2; i >= 0; i--) { //isSortedArray(); if (ComparisonPointer(&array[i], &array[i+1]) > 0) break; } if (0 >= i) break; // is sorted array; step = maxStep; oldDivider = divider = 1; while (step > 1) { // group-sort loop; divider = (divider * N2) / N1; if (divider == oldDivider) divider++; oldDivider = divider; step = maxStep / divider; if (firstSet && step <= 2*logN) { // reset GNDR = 2/3 firstSet = FALSE; N1 = 2; N2 = 3; } if (0 == step) step = 1; for (i = 0, j = arraySize-1; i < maxStep; i++, j--) // bidirection bubble-sort for each group; if (ComparisonPointer(&array[i], &array[i+step]) > 0) { tmp = array[i]; array[i] = array[i+step]; array[i+step] = tmp; } if (ComparisonPointer(&array[j-step], &array[j]) > 0) { tmp = array[j-step]; array[j-step] = array[j]; array[j] = tmp; } } } maxStep = logN; } } Listing Five //################################################################ // Test program for Adaptive Group Sort (AGS) algorithm statistic analysis. // 05/04/98 M. Gong - initial code. //################################################################ long gsort2(long *array, long arraySize, long n1, long n2); long gsort3(long *array, long arraySize, long n1, long n2); // static long numCmpr, numSwap; // static short cmprSwap2(long &smaller, long &larger); static short isSortedArray(long *array, long arraySize); static void biDirectionGroupSort(long *array, long arraySize, long step, long loops); //for test static void initArray(long *array, long N); static void swap(long &l1, long &l2); int main(int argc, char **argv); // int main(int argc, char **argv) { long minloop, maxloop, avrloop; long mincmpr, maxcmpr; long minswap, maxswap; double avrswap, avrcmpr; long gsortLoops; double avrf, minf, maxf; double loopf; double nlogn; double logN; long n1, n2; long seed1, seed2, arraySize, n; long *array = NULL; if (argc <6) { printf("usage: %s arraySize seedStart seedEnd n1 n2\n", argv[0]); return FALSE; } arraySize = atoi(argv[1]); seed1 = atoi(argv[2]); seed2 = atoi(argv[3]); n1 = atoi(argv[4]); n2 = atoi(argv[5]); logN = log((double)arraySize) / log(2.0); if (seed1 > seed2) swap(seed1, seed2); printf("****** adaptive group sort: numCmpr = K * N * log2(N); numSwap = S * N * log2(N);\n"); printf(" seed1 = %d; seed2 = %d; N = %d; n1 = %d; n2 = %d; log2(N) = %.3f;\n", seed1, seed2, arraySize, n1, n2, logN); minloop = 0x7FFFFFFF; maxloop = 0; avrloop = 0; mincmpr = 0x7FFFFFFF; maxcmpr = 0, avrcmpr = 0; minswap = 0x7FFFFFFF; maxswap = 0; avrswap = 0; array = new long[arraySize]; if (NULL == array) return FALSE; for(n = seed1; n <= seed2; n++) { numCmpr = 0; numSwap = 0; srand(n); initArray(array,arraySize); gsortLoops = gsort2((long*)array, arraySize, n1, n2); if (minloop > gsortLoops) minloop = gsortLoops; if (maxloop < gsortLoops) maxloop = gsortLoops; avrloop += gsortLoops; if (mincmpr > numCmpr) mincmpr = numCmpr; if (maxcmpr < numCmpr) maxcmpr = numCmpr; avrcmpr += ((float) numCmpr) / (float)(seed2 - seed1 +1); if (minswap > numSwap) minswap = numSwap; if (maxswap < numSwap) maxswap = numSwap; avrswap += ((float) numSwap) / (float)(seed2 - seed1 +1); } loopf = (double) (seed2 - seed1 +1); nlogn = logN * ((double)arraySize); avrf= ((double)avrloop) / loopf; printf("\tmin : max : average loop = %d : %d : %.3f\n", minloop, maxloop, avrf); avrf = avrcmpr / nlogn; minf = ((double)mincmpr) / nlogn; maxf = ((double)maxcmpr) / nlogn; printf("\tmin : max : average K = %.3f : %.3f : %.3f\n", minf, maxf, avrf); avrf = avrswap / nlogn; minf = ((double)minswap) / nlogn; maxf = ((double)maxswap) / nlogn; printf("\tmin : max : average S = %.3f : %.3f : %.3f\n", minf, maxf, avrf); delete [] array; return TRUE; } // static void initArray(long *array, long N) { long i; for (i = 0; i < N; i++) { array[i] = (long) rand(); } } // static void swap(long &l1, long &l2) { long tmp = l1; l1 = l2; l2 = tmp; } //reset maxStep = logN after the first AGS loop; long gsort2(long *array, long arraySize, long N1, long N2) { long maxStep; // maximum group number long step; // number of groups long divider; // to calculate step long oldDivider; // to calculate step long i; long gsortloops = 0; long logN; if (1 >= arraySize) return 0; if (2 == arraySize) { cmprSwap2(array[0], array[1]); return 0; } if (N1 > N2) swap(N1, N2); else if (N1 == N2) { N1 = 2; N2 = 3; } maxStep = arraySize / 2; for (i = 0; i < maxStep; i++) { // pre-processing cmprSwap2(array[i], array[arraySize-1-i]); } logN = (long) (log((double)arraySize)); maxStep = arraySize; while (!isSortedArray(array, arraySize)) { // AGS Loop step = maxStep; oldDivider = divider = 1; while (step > 1) { // group-sort loop divider = (divider * N2) / N1; if (divider == oldDivider) divider++; oldDivider = divider; step = maxStep / divider; if (0 == step) step = 1; biDirectionGroupSort(array, arraySize, step, 0); } gsortloops++; maxStep = logN; if (maxStep < 2) maxStep = 2; } return gsortloops; } //reset maxStep = logN after the first AGS loop; //reset GNDR to 2/3 when step < logN; long gsort3(long *array, long arraySize, long N1, long N2) { long maxStep; // maximum group number long step; // number of groups long divider; // to calculate step long oldDivider; // to calculate step long i; long gsortloops = 0; long logN; if (1 >= arraySize) return 0; if (2 == arraySize) { cmprSwap2(array[0], array[1]); return 0; } if (N1 > N2) swap(N1, N2); else if (N1 == N2) { N1 = 2; N2 = 3; } maxStep = arraySize / 2; for (i = 0; i < maxStep; i++) { // pre-processing cmprSwap2(array[i], array[arraySize-1-i]); } logN = (long) (log((double)arraySize)); maxStep = arraySize; while (!isSortedArray(array, arraySize)) { // AGS Loop step = maxStep; oldDivider = divider = 1; while (step > 1) { // group-sort loop divider = (divider * N2) / N1; if (divider == oldDivider) divider++; oldDivider = divider; step = maxStep / divider; if (step <= 2*logN) { // reset GNDR = 2/3 N1 = 2; N2 = 3; } if (0 == step) step = 1; biDirectionGroupSort(array, arraySize, step, 0); } gsortloops++; maxStep = logN; if (maxStep < 2) maxStep = 2; } return gsortloops; } //bidirection bubble-sort for each group static void biDirectionGroupSort(long *array, long arraySize, long step, long loops) { long i; long maxIndex, lastIndex; lastIndex = arraySize - 1; maxIndex = arraySize - step - loops; for (i = loops; i < maxIndex; i++) { // bi-directional group sort cmprSwap2(array[i], array[i+step]); cmprSwap2(array[lastIndex-i-step], array[lastIndex-i]); } } //return TRUE if swapped static short cmprSwap2(long &smaller, long &larger) { numCmpr++; if (smaller > larger) { long tmp = smaller; smaller = larger; larger = tmp; numSwap++; return 1; } return 0; } //return TRUE if array is sorted static short isSortedArray(long *array, long arraySize) { arraySize--; for (long i = 0; i < arraySize; i++) { if (cmprSwap2(array[i], array[i+1]) > 0) return 0; } return 1; } 9