00001 /*! \file qksort.c 00002 This file implements the quick sort algorithm 00003 */ 00004 00005 #include <stdlib.h> 00006 #include <string.h> 00007 00008 #include <stdio.h> 00009 00010 #include "sort.h" 00011 00012 /* ------------------------------------------------------------ */ 00013 /* Compare two integers -- Not part of public API */ 00014 /* ------------------------------------------------------------ */ 00015 00016 static int compare_int(const void *int1, const void *int2) 00017 { 00018 if (*(const int *)int1 > *(const int *)int2) { return 1; } 00019 if (*(const int *)int1 < *(const int *)int2) { return -1; } 00020 return 0; 00021 } 00022 00023 /* ------------------------------------------------------------ */ 00024 /* Partitions -- Not part of public API */ 00025 /* ------------------------------------------------------------ */ 00026 00027 static int partition ( 00028 void *donnee, 00029 int taille_elt, 00030 int i, 00031 int k, 00032 int (*compare) (const void *cle1, const void *cle2) 00033 ) 00034 { 00035 char *tab = donnee; 00036 void *pivot, *temp; 00037 int r[3]; 00038 00039 /* ----------------------------------------------------------- */ 00040 /* Allocated memory */ 00041 /* ----------------------------------------------------------- */ 00042 00043 if ((pivot = malloc(taille_elt)) == NULL) { return -1; } 00044 if ((temp = malloc(taille_elt)) == NULL) { free(pivot); return -1; } 00045 00046 /* ----------------------------------------------------------- */ 00047 /* Find the pivot */ 00048 /* ----------------------------------------------------------- */ 00049 00050 r[0] = (rand() % (k - i + 1)) + i; 00051 r[1] = (rand() % (k - i + 1)) + i; 00052 r[2] = (rand() % (k - i + 1)) + i; 00053 issort(r, 3, sizeof(int), compare_int); 00054 memcpy(pivot, &tab[r[1] * taille_elt], taille_elt); 00055 00056 /* ----------------------------------------------------------- */ 00057 /* create 2 partitions around this value */ 00058 /* ----------------------------------------------------------- */ 00059 00060 i--; 00061 k++; 00062 00063 while (1) 00064 { 00065 /* --------------------------------------------------------- */ 00066 /* Move to the left */ 00067 /* --------------------------------------------------------- */ 00068 00069 do { k--; } while (compare(&tab[k * taille_elt], pivot) > 0); 00070 00071 /* --------------------------------------------------------- */ 00072 /* Move to the right */ 00073 /* --------------------------------------------------------- */ 00074 00075 do { i++; } while (compare(&tab[i * taille_elt], pivot) < 0); 00076 00077 if (i >= k) { break; } 00078 else { 00079 /* --------------------------------------------------- */ 00080 /* Swap the two elements */ 00081 /* --------------------------------------------------- */ 00082 00083 memcpy(temp, &tab[i * taille_elt], taille_elt); 00084 memcpy(&tab[i * taille_elt], &tab[k * taille_elt], taille_elt); 00085 memcpy(&tab[k * taille_elt], temp, taille_elt); 00086 } 00087 } 00088 00089 /* ----------------------------------------------------------- */ 00090 /* Free all allocated memory */ 00091 /* ----------------------------------------------------------- */ 00092 00093 free(pivot); 00094 free(temp); 00095 00096 /* ----------------------------------------------------------- */ 00097 /* Return the position */ 00098 /* ----------------------------------------------------------- */ 00099 00100 return k; 00101 00102 } 00103 00104 00105 /*! \brief Sort data using the QuickSort algorithm. 00106 \param donnee Pointer to the beginning of the array to sort. 00107 \param nb_elts Number of elements to sort. 00108 \param taille_elt Size in bytes of an element. 00109 \param i <i>i</i> <B>MUST BE</B> set to 0. 00110 \param k <i>k</i> <B>MUST BE</B> set to <i>nb_elts - 1</i>. 00111 \param compare User defined function used to compare two elements of the array. 00112 If you want to sort according to increasing values, then the function <i>compare()</i> should return: 00113 <UL> 00114 <li>1 if <i>cle1 > cle2</i> 00115 <li>0 if <i>cle1 == cle2</i> 00116 <li>-1 if <i>cle1 < cle2</i> 00117 </UL> 00118 If you want to sort according to decreasing values, then the function <i>compare()</i> should return: 00119 <UL> 00120 <li>1 if <i>cle1 < cle2</i> 00121 <li>0 if <i>cle1 == cle2</i> 00122 <li>-1 if <i>cle1 > cle2</i> 00123 </UL> 00124 \return Upon successful completion the function returns 0, otherwise it returns -1 00125 */ 00126 00127 int qksort ( 00128 void *donnee, 00129 int nb_elts, 00130 int taille_elt, 00131 int i, 00132 int k, 00133 int (*compare)(const void *cle1, const void *cle2) 00134 ) 00135 { 00136 int j; 00137 00138 00139 while (i < k) 00140 { 00141 /* --------------------------------------------------------- */ 00142 /* Find where to make a partition */ 00143 /* --------------------------------------------------------- */ 00144 00145 if ((j = partition(donnee, taille_elt, i, k, compare)) < 0) { return -1; } 00146 00147 /* --------------------------------------------------------- */ 00148 /* Sort the left side of the partition */ 00149 /* --------------------------------------------------------- */ 00150 00151 if (qksort(donnee, nb_elts, taille_elt, i, j, compare) < 0) { return -1; } 00152 00153 /* --------------------------------------------------------- */ 00154 /* Sort the right side of the partition */ 00155 /* --------------------------------------------------------- */ 00156 00157 i = j + 1; 00158 } 00159 00160 return 0; 00161 } 00162 00163 /*! \example test_sort.c 00164 This file shows how to use the qksort function. 00165 */ 00166 00167 00168 /* ------------------------------------------------------------ */ 00169 /* Partitions -- Not part of public API */ 00170 /* ------------------------------------------------------------ */ 00171 00172 static int extended_partition ( 00173 void *donnee, 00174 int taille_elt, 00175 int i, 00176 int k, 00177 int (*compare) (const void *cle1, const void *cle2), 00178 int (*copy_data)(void *src, void *dest), 00179 int (*init_elem)(void *elm) 00180 ) 00181 { 00182 char *tab = donnee; 00183 void *pivot, *temp; 00184 int r[3]; 00185 00186 /* ----------------------------------------------------------- */ 00187 /* Allocated memory */ 00188 /* ----------------------------------------------------------- */ 00189 00190 if ((pivot = malloc(taille_elt)) == NULL) { return -1; } 00191 if ((temp = malloc(taille_elt)) == NULL) { free(pivot); return -1; } 00192 00193 if (init_elem != NULL) 00194 { 00195 if (init_elem(pivot) == 1) { free(pivot); free(temp); return -1; } 00196 if (init_elem(temp) == 1) { free(pivot); free(temp); return -1; } 00197 } 00198 00199 /* ----------------------------------------------------------- */ 00200 /* Find the pivot */ 00201 /* ----------------------------------------------------------- */ 00202 00203 r[0] = (rand() % (k - i + 1)) + i; 00204 r[1] = (rand() % (k - i + 1)) + i; 00205 r[2] = (rand() % (k - i + 1)) + i; 00206 issort(r, 3, sizeof(int), compare_int); 00207 00208 if (copy_data (&tab[r[1] * taille_elt], pivot) == 1) { free(pivot); free(temp); return -1; } 00209 00210 /* ----------------------------------------------------------- */ 00211 /* create 2 partitions around this value */ 00212 /* ----------------------------------------------------------- */ 00213 00214 i--; 00215 k++; 00216 00217 while (1) 00218 { 00219 /* --------------------------------------------------------- */ 00220 /* Move to the left */ 00221 /* --------------------------------------------------------- */ 00222 00223 do { k--; } while (compare(&tab[k * taille_elt], pivot) > 0); 00224 00225 /* --------------------------------------------------------- */ 00226 /* Move to the right */ 00227 /* --------------------------------------------------------- */ 00228 00229 do { i++; } while (compare(&tab[i * taille_elt], pivot) < 0); 00230 00231 if (i >= k) { break; } 00232 else { 00233 /* --------------------------------------------------- */ 00234 /* Swap the two elements */ 00235 /* --------------------------------------------------- */ 00236 00237 if (copy_data (&tab[i * taille_elt], temp) == 1) { free(pivot); free(temp); return -1; } 00238 if (copy_data (&tab[k * taille_elt], &tab[i * taille_elt]) == 1) { free(pivot); free(temp); return -1; } 00239 if (copy_data (temp, &tab[k * taille_elt]) == 1) { free(pivot); free(temp); return -1; } 00240 } 00241 } 00242 00243 /* ----------------------------------------------------------- */ 00244 /* Free all allocated memory */ 00245 /* ----------------------------------------------------------- */ 00246 00247 free(pivot); 00248 free(temp); 00249 00250 /* ----------------------------------------------------------- */ 00251 /* Return the position */ 00252 /* ----------------------------------------------------------- */ 00253 00254 return k; 00255 } 00256 00257 00258 /*! \brief Sort data using the QuickSort algorithm. 00259 \param donnee Pointer to the beginning of the array to sort. 00260 \param nb_elts Number of elements to sort. 00261 \param taille_elt Size in bytes of an element. 00262 \param i <i>i</i> <B>MUST BE</B> set to 0. 00263 \param k <i>k</i> <B>MUST BE</B> set to <i>nb_elts - 1</i>. 00264 \param compare User defined function used to compare two elements of the array. 00265 If you want to sort according to increasing values, then the function <i>compare()</i> should return: 00266 <UL> 00267 <li>1 if <i>cle1 > cle2</i> 00268 <li>0 if <i>cle1 == cle2</i> 00269 <li>-1 if <i>cle1 < cle2</i> 00270 </UL> 00271 If you want to sort according to decreasing values, then the function <i>compare()</i> should return: 00272 <UL> 00273 <li>1 if <i>cle1 < cle2</i> 00274 <li>0 if <i>cle1 == cle2</i> 00275 <li>-1 if <i>cle1 > cle2</i> 00276 </UL> 00277 \param copy_data User defined function used to copy data. <B>The function must take care of memory management</B>. 00278 This function must return: 00279 <UL> 00280 <li>0 upon successful completion. 00281 <li>1 if an error occured. 00282 </UL> 00283 \param init_elem User defined function used to initializen an element. This function must return: 00284 <UL> 00285 <li>0 upon successful completion. 00286 <li>1 if an error occured. 00287 </UL> 00288 This function is called whenever a new element is allocated. 00289 Please note that you can specify a NULL pointer if no initialization is needed. 00290 \return Upon successful completion the function returns 0, otherwise it returns -1 00291 */ 00292 00293 int extended_qksort ( 00294 void *donnee, 00295 int nb_elts, 00296 int taille_elt, 00297 int i, 00298 int k, 00299 int (*compare)(const void *cle1, const void *cle2), 00300 int (*copy_data)(void *src, void *dest), 00301 int (*init_elem)(void *elm) 00302 ) 00303 { 00304 int j; 00305 00306 00307 while (i < k) 00308 { 00309 /* --------------------------------------------------------- */ 00310 /* Find where to make a partition */ 00311 /* --------------------------------------------------------- */ 00312 00313 if ((j = extended_partition(donnee, taille_elt, i, k, compare, copy_data, init_elem)) < 0) { return -1; } 00314 00315 /* --------------------------------------------------------- */ 00316 /* Sort the left side of the partition */ 00317 /* --------------------------------------------------------- */ 00318 00319 if (extended_qksort(donnee, nb_elts, taille_elt, i, j, compare, copy_data, init_elem) < 0) { return -1; } 00320 00321 /* --------------------------------------------------------- */ 00322 /* Sort the right side of the partition */ 00323 /* --------------------------------------------------------- */ 00324 00325 i = j + 1; 00326 } 00327 00328 return 0; 00329 } 00330 00331 /*! \example test_ext_sort.c 00332 This file shows how to use the extended_qksort() function. 00333 */ 00334