00001 /*@HEADER 00002 // *********************************************************************** 00003 // 00004 // Ifpack: Object-Oriented Algebraic Preconditioner Package 00005 // Copyright (2002) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // This library is free software; you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as 00012 // published by the Free Software Foundation; either version 2.1 of the 00013 // License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, but 00016 // WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00023 // USA 00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00025 // 00026 // *********************************************************************** 00027 //@HEADER 00028 */ 00029 00030 /* Modified by Edmond Chow, to sort integers and carry along an array of 00031 doubles */ 00032 #if 0 /* test program */ 00033 00034 #include <stdlib.h> 00035 #include <stdio.h> 00036 00037 void quicksort (int *const pbase, double *const daux, size_t total_elems); 00038 #define QSORTLEN 20 00039 00040 int main() 00041 { 00042 int h[QSORTLEN]; 00043 double d[QSORTLEN]; 00044 int i; 00045 00046 for (i=0; i<QSORTLEN; i++) 00047 { 00048 h[i] = rand() >> 20; 00049 d[i] = (double) -h[i]; 00050 } 00051 00052 printf("before sorting\n"); 00053 for (i=0; i<QSORTLEN; i++) 00054 printf("%d %f\n", h[i], d[i]); 00055 00056 quicksort(h, d, QSORTLEN); 00057 00058 printf("after sorting\n"); 00059 for (i=0; i<QSORTLEN; i++) 00060 printf("%d %f\n", h[i], d[i]); 00061 00062 return 0; 00063 } 00064 #endif /* test program */ 00065 00066 /* Copyright (C) 1991, 1992, 1996, 1997 Free Software Foundation, Inc. 00067 This file is part of the GNU C Library. 00068 Written by Douglas C. Schmidt (schmidt@ics.uci.edu). 00069 00070 The GNU C Library is free software; you can redistribute it and/or 00071 modify it under the terms of the GNU Library General Public License as 00072 published by the Free Software Foundation; either version 2 of the 00073 License, or (at your option) any later version. 00074 00075 The GNU C Library is distributed in the hope that it will be useful, 00076 but WITHOUT ANY WARRANTY; without even the implied warranty of 00077 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00078 Library General Public License for more details. 00079 00080 You should have received a copy of the GNU Library General Public 00081 License along with the GNU C Library; see the file COPYING.LIB. If not, 00082 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00083 Boston, MA 02111-1307, USA. */ 00084 00085 #include <string.h> 00086 00087 /* Swap integers pointed to by a and b, and corresponding doubles */ 00088 #define SWAP(a, b) \ 00089 do { \ 00090 itemp = *a; \ 00091 *a = *b; \ 00092 *b = itemp; \ 00093 dtemp = daux[a-pbase]; \ 00094 daux[a-pbase] = daux[b-pbase]; \ 00095 daux[b-pbase] = dtemp; \ 00096 } while (0) 00097 00098 /* Discontinue quicksort algorithm when partition gets below this size. 00099 This particular magic number was chosen to work best on a Sun 4/260. */ 00100 #define MAX_THRESH 4 00101 00102 /* Stack node declarations used to store unfulfilled partition obligations. */ 00103 typedef struct 00104 { 00105 int *lo; 00106 int *hi; 00107 } stack_node; 00108 00109 /* The next 4 #defines implement a very fast in-line stack abstraction. */ 00110 #define STACK_SIZE (8 * sizeof(unsigned long int)) 00111 #define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top)) 00112 #define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) 00113 #define STACK_NOT_EMPTY (stack < top) 00114 00115 00116 /* Order size using quicksort. This implementation incorporates 00117 four optimizations discussed in Sedgewick: 00118 00119 1. Non-recursive, using an explicit stack of pointer that store the 00120 next array partition to sort. To save time, this maximum amount 00121 of space required to store an array of MAX_INT is allocated on the 00122 stack. Assuming a 32-bit integer, this needs only 32 * 00123 sizeof(stack_node) == 136 bits. Pretty cheap, actually. 00124 00125 2. Chose the pivot element using a median-of-three decision tree. 00126 This reduces the probability of selecting a bad pivot value and 00127 eliminates certain extraneous comparisons. 00128 00129 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving 00130 insertion sort to order the MAX_THRESH items within each partition. 00131 This is a big win, since insertion sort is faster for small, mostly 00132 sorted array segments. 00133 00134 4. The larger of the two sub-partitions is always pushed onto the 00135 stack first, with the algorithm then concentrating on the 00136 smaller partition. This *guarantees* no more than log (n) 00137 stack size is needed (actually O(1) in this case)! */ 00138 00139 void quicksort (int *const pbase, double *const daux, size_t total_elems) 00140 { 00141 int itemp; 00142 double dtemp; 00143 const size_t size = 1; 00144 register int *base_ptr = (int *) pbase; 00145 00146 /* Allocating SIZE bytes for a pivot buffer facilitates a better 00147 algorithm below since we can do comparisons directly on the pivot. */ 00148 int pivot_buffer[1]; 00149 const size_t max_thresh = MAX_THRESH * size; 00150 00151 /* edmond: return if total_elems less than zero */ 00152 if (total_elems <= 0) 00153 /* Avoid lossage with unsigned arithmetic below. */ 00154 return; 00155 00156 if (total_elems > MAX_THRESH) 00157 { 00158 int *lo = base_ptr; 00159 int *hi = &lo[size * (total_elems - 1)]; 00160 /* Largest size needed for 32-bit int!!! */ 00161 stack_node stack[STACK_SIZE]; 00162 stack_node *top = stack + 1; 00163 00164 while (STACK_NOT_EMPTY) 00165 { 00166 int *left_ptr; 00167 int *right_ptr; 00168 00169 int *pivot = pivot_buffer; 00170 00171 /* Select median value from among LO, MID, and HI. Rearrange 00172 LO and HI so the three values are sorted. This lowers the 00173 probability of picking a pathological pivot value and 00174 skips a comparison for both the LEFT_PTR and RIGHT_PTR. */ 00175 00176 int *mid = lo + size * ((hi - lo) / size >> 1); 00177 00178 if (*mid - *lo < 0) 00179 SWAP (mid, lo); 00180 if (*hi - *mid < 0) 00181 SWAP (mid, hi); 00182 else 00183 goto jump_over; 00184 if (*mid - *lo < 0) 00185 SWAP (mid, lo); 00186 jump_over:; 00187 *pivot = *mid; 00188 pivot = pivot_buffer; 00189 00190 left_ptr = lo + size; 00191 right_ptr = hi - size; 00192 00193 /* Here's the famous ``collapse the walls'' section of quicksort. 00194 Gotta like those tight inner loops! They are the main reason 00195 that this algorithm runs much faster than others. */ 00196 do 00197 { 00198 while (*left_ptr - *pivot < 0) 00199 left_ptr += size; 00200 00201 while (*pivot - *right_ptr < 0) 00202 right_ptr -= size; 00203 00204 if (left_ptr < right_ptr) 00205 { 00206 SWAP (left_ptr, right_ptr); 00207 left_ptr += size; 00208 right_ptr -= size; 00209 } 00210 else if (left_ptr == right_ptr) 00211 { 00212 left_ptr += size; 00213 right_ptr -= size; 00214 break; 00215 } 00216 } 00217 while (left_ptr <= right_ptr); 00218 00219 /* Set up pointers for next iteration. First determine whether 00220 left and right partitions are below the threshold size. If so, 00221 ignore one or both. Otherwise, push the larger partition's 00222 bounds on the stack and continue sorting the smaller one. */ 00223 00224 if ((size_t) (right_ptr - lo) <= max_thresh) 00225 { 00226 if ((size_t) (hi - left_ptr) <= max_thresh) 00227 /* Ignore both small partitions. */ 00228 POP (lo, hi); 00229 else 00230 /* Ignore small left partition. */ 00231 lo = left_ptr; 00232 } 00233 else if ((size_t) (hi - left_ptr) <= max_thresh) 00234 /* Ignore small right partition. */ 00235 hi = right_ptr; 00236 else if ((right_ptr - lo) > (hi - left_ptr)) 00237 { 00238 /* Push larger left partition indices. */ 00239 PUSH (lo, right_ptr); 00240 lo = left_ptr; 00241 } 00242 else 00243 { 00244 /* Push larger right partition indices. */ 00245 PUSH (left_ptr, hi); 00246 hi = right_ptr; 00247 } 00248 } 00249 } 00250 00251 /* Once the BASE_PTR array is partially sorted by quicksort the rest 00252 is completely sorted using insertion sort, since this is efficient 00253 for partitions below MAX_THRESH size. BASE_PTR points to the beginning 00254 of the array to sort, and END_PTR points at the very last element in 00255 the array (*not* one beyond it!). */ 00256 00257 #define min(x, y) ((x) < (y) ? (x) : (y)) 00258 00259 { 00260 int *const end_ptr = &base_ptr[size * (total_elems - 1)]; 00261 int *tmp_ptr = base_ptr; 00262 int *thresh = min(end_ptr, base_ptr + max_thresh); 00263 register int *run_ptr; 00264 00265 /* Find smallest element in first threshold and place it at the 00266 array's beginning. This is the smallest array element, 00267 and the operation speeds up insertion sort's inner loop. */ 00268 00269 for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) 00270 if (*run_ptr - *tmp_ptr < 0) 00271 tmp_ptr = run_ptr; 00272 00273 if (tmp_ptr != base_ptr) 00274 SWAP (tmp_ptr, base_ptr); 00275 00276 /* Insertion sort, running from left-hand-side up to right-hand-side. */ 00277 00278 run_ptr = base_ptr + size; 00279 while ((run_ptr += size) <= end_ptr) 00280 { 00281 tmp_ptr = run_ptr - size; 00282 while (*run_ptr - *tmp_ptr < 0) 00283 tmp_ptr -= size; 00284 00285 tmp_ptr += size; 00286 if (tmp_ptr != run_ptr) 00287 { 00288 int *trav; 00289 00290 trav = run_ptr + size; 00291 while (--trav >= run_ptr) 00292 { 00293 int c = *trav; 00294 double c2 = daux[trav-pbase]; 00295 00296 int *hi, *lo; 00297 00298 for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) 00299 { 00300 *hi = *lo; 00301 daux[hi-pbase] = daux[lo-pbase]; 00302 } 00303 *hi = c; 00304 daux[hi-pbase] = c2; 00305 } 00306 } 00307 } 00308 } 00309 }
1.3.9.1