home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / comp / lang / c / 20016 < prev    next >
Encoding:
Internet Message Format  |  1993-01-21  |  5.2 KB

  1. Path: sparky!uunet!spool.mu.edu!agate!dog.ee.lbl.gov!horse.ee.lbl.gov!torek
  2. From: torek@horse.ee.lbl.gov (Chris Torek)
  3. Newsgroups: comp.lang.c
  4. Subject: Re: qsort/pointer question (should be in FAQ?)
  5. Date: 21 Jan 1993 14:37:35 GMT
  6. Organization: Lawrence Berkeley Laboratory, Berkeley CA
  7. Lines: 135
  8. Message-ID: <28540@dog.ee.lbl.gov>
  9. References: <1993Jan20.213331.5197@noose.ecn.purdue.edu> <C16Boy.Lo5@portal.hq.videocart.com> <1993Jan21.102641.14862@noose.ecn.purdue.edu>
  10. NNTP-Posting-Host: 128.3.112.15
  11.  
  12. In article <1993Jan20.213331.5197@noose.ecn.purdue.edu>
  13. mccauley@ecn.purdue.edu (Darrell McCauley) writes:
  14. >>>I need to sort a 2 dimensional double array:
  15. >>>   qsort (z, 10, 2*sizeof (double), zcmp);
  16. >>>and I cannot figure out how to write the comparison function. ...
  17.  
  18. In article <C16Boy.Lo5@portal.hq.videocart.com>
  19. dfuller@portal.hq.videocart.com (Dave Fuller) correctly points out
  20. that `2 * sizeof(double)' is at best suspicious, and notes how two-
  21. dimensional arrays are laid out in memory (i.e., in row major order
  22. and *always* contiguous).  (See my previous posting on things that
  23. are not arrays, but `act like them'; in this case some or all parts
  24. of the arrays may not be contiguous.)
  25.  
  26. In article <1993Jan21.102641.14862@noose.ecn.purdue.edu>
  27. mccauley@ecn.purdue.edu (Darrell McCauley) provides the missing
  28. information (see below) and asks:
  29. >Is this the case when the array is dynamically allocated?
  30.  
  31. If a space is not contiguous, qsort cannot sort it.
  32.  
  33. Qsort *can* be used to sort a contiguous set of pointers to
  34. discontiguous areas.  The result is sorted *pointers*, not sorted
  35. areas.  If you do want contiguous areas, you can sort the pointers,
  36. then copy to contiguous space; this may be faster than sorting the
  37. areas themselves (because swapping pointers can be done more easily
  38. than swapping large memory regions).
  39.  
  40. >According to the FAQ, you have to allocate nrows*ncolumns in one malloc
  41. >call to get contiguous memory chunks
  42.  
  43. The is correct.
  44.  
  45. >(even then, though, are you assured of getting contiguous memory?
  46.  
  47. Yes.
  48.  
  49. >If nrows*ncolumns is too large of a chunk, won't unix split it up among
  50. >different memory locations?).
  51.  
  52. (`Unix'?  This is comp.lang.c, not comp.unix.programmer.)  The C
  53. language requires that malloc return at least as many bytes, as one
  54. flat piece of memory, as requested.  If this is not available, malloc()
  55. should return NULL.  On modern computers, the underlying memory may
  56. reside in separate physical boxes or chips or computers, but it must
  57. *appear* contiguous to the programmer.
  58.  
  59. >Anyway, sticking the the problem at hand, I'm doing memory allocation
  60. >the normal way:
  61. >
  62. >         double **array;
  63. >     array = (double **)malloc(nrows * sizeof(double *));
  64. >         for(i = 0; i < nrows; ++i)
  65. >           array[i] = (double *)calloc(ncolumns * sizeof(double));
  66.  
  67. In this case, a valid qsort call might be:
  68.  
  69.     qsort((void *)array, nrows, sizeof(double *), mycompare);
  70.  
  71. where mycompare has previously been defined as, e.g.:
  72.  
  73.     int
  74.     mycompare(const void *a, const void *b) {
  75.         const double *l, *r;
  76.  
  77.         /*
  78.          * Each element of the array being sorted is a `double *'.
  79.          * qsort passes a pointer to each element, or a `double **',
  80.          * but encodes it in a `const void *' (a and b).  Here we
  81.          * fetch the array elements, i.e., the row vectors.  Each
  82.          * points to (the first element of) a column (a set of
  83.          * `ncolumns' doubles).
  84.          */
  85.         l = *(const double **)a;
  86.         r = *(const double **)b;
  87.  
  88.         /*
  89.          * Now l points to the column currently on the left, and r
  90.          * to the one on the right.  We want to sort rows according
  91.          * to the value in column 0 (l[0], r[0]).
  92.          */
  93.         if (l[0] < r[0])
  94.             return (-1);    /* l before r (already in order) */
  95.         if (l[0] > r[0])
  96.             return (1);    /* r before l (reverse them) */
  97.         return (0);        /* order irrelevant */
  98.     }
  99.  
  100. Dave Fuller goes on to add:
  101. >>If you want to do a 2-d array sort (by row i assume), you are going to
  102. >>be writing your own routines to do it. 
  103.  
  104. Again, qsort can sort *anything contiguous*.  It can NOT sort disjoint
  105. objects, such as elements of a linked list.  Merge sorts are good for
  106. lists, but if you like, you can `arrayify' the list, sort it with
  107. qsort, and `listify' the resulting sorted array.  In some cases, lists
  108. are built `inside' arrays anyway---this is more common in languages
  109. like FORTRAN, where pointers must be simulated, than in C, but it does
  110. happen---and in these cases the sort may be `free' (discounting any
  111. problems with holes).
  112.  
  113. Note that qsort is not guaranteed to be stable.  That is, given something
  114. like:
  115.  
  116.     (5 tiger)
  117.     (2 elephant)
  118.     (1 raven)
  119.     (2 zebra)
  120.  
  121. if you were to sort these numerically (comparing only the numbers) with
  122. qsort, you could get either:
  123.  
  124.     (1 raven)
  125.     (2 elephant)
  126.     (2 zebra)
  127.     (5 tiger)
  128.  
  129. or:
  130.  
  131.     (1 raven)
  132.     (2 zebra)
  133.     (2 elephant)
  134.     (5 tiger)
  135.  
  136. A stable sort guarantees the former, in which `elephant' comes before
  137. `zebra' because it *used to* come before zebra.
  138.  
  139. Qsort can be forced stable by the simple expedient of numbering the
  140. elements in advance, and adding the numbers as a final sort key for
  141. otherwise-identical elements.  Merge sorts are typically inherently
  142. stable, which is another reason to use merge sort.  If your C library
  143. implements qsort using a merge sort, be glad. :-)
  144. -- 
  145. In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 510 486 5427)
  146. Berkeley, CA        Domain:    torek@ee.lbl.gov
  147.