Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Examples  

qksort.c

Go to the documentation of this file.
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 &gt; cle2</i>
00115               <li>0 if <i>cle1 == cle2</i>
00116               <li>-1 if <i>cle1 &lt; 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 &lt; cle2</i>
00121               <li>0 if <i>cle1 == cle2</i>
00122               <li>-1 if <i>cle1 &gt; 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 &gt; cle2</i>
00268               <li>0 if <i>cle1 == cle2</i>
00269               <li>-1 if <i>cle1 &lt; 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 &lt; cle2</i>
00274               <li>0 if <i>cle1 == cle2</i>
00275               <li>-1 if <i>cle1 &gt; 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 

Generated on Thu Apr 3 16:23:43 2003 for Common_C_libraries by doxygen1.3-rc1