sort.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*
  2. * Implement arraysort() defined in puzzles.h.
  3. *
  4. * Strategy: heapsort.
  5. */
  6. #include <stddef.h>
  7. #include <string.h>
  8. #include "puzzles.h"
  9. static void memswap(void *av, void *bv, size_t size)
  10. {
  11. char t[4096];
  12. char *a = (char *)av, *b = (char *)bv;
  13. while (size > 0) {
  14. size_t thissize = size < sizeof(t) ? size : sizeof(t);
  15. memcpy(t, a, thissize);
  16. memcpy(a, b, thissize);
  17. memcpy(b, t, thissize);
  18. size -= thissize;
  19. a += thissize;
  20. b += thissize;
  21. }
  22. }
  23. #define PTR(i) ((char *)array + size * (i))
  24. #define SWAP(i,j) memswap(PTR(i), PTR(j), size)
  25. #define CMP(i,j) cmp(PTR(i), PTR(j), ctx)
  26. #define LCHILD(i) (2*(i)+1)
  27. #define RCHILD(i) (2*(i)+2)
  28. #define PARENT(i) (((i)-1)/2)
  29. static void downheap(void *array, size_t nmemb, size_t size,
  30. arraysort_cmpfn_t cmp, void *ctx, size_t i)
  31. {
  32. while (LCHILD(i) < nmemb) {
  33. /* Identify the smallest element out of i and its children. */
  34. size_t j = i;
  35. if (CMP(j, LCHILD(i)) < 0)
  36. j = LCHILD(i);
  37. if (RCHILD(i) < nmemb &&
  38. CMP(j, RCHILD(i)) < 0)
  39. j = RCHILD(i);
  40. if (j == i)
  41. return; /* smallest element is already where it should be */
  42. SWAP(j, i);
  43. i = j;
  44. }
  45. }
  46. void arraysort_fn(void *array, size_t nmemb, size_t size,
  47. arraysort_cmpfn_t cmp, void *ctx)
  48. {
  49. size_t i;
  50. if (nmemb < 2)
  51. return; /* trivial */
  52. /*
  53. * Stage 1: build the heap.
  54. *
  55. * Linear-time if we do it by downheaping the elements in
  56. * decreasing order of index, instead of the more obvious approach
  57. * of upheaping in increasing order. (Also, it means we don't need
  58. * the upheap function at all.)
  59. *
  60. * We don't need to downheap anything in the second half of the
  61. * array, because it can't have any children to swap with anyway.
  62. */
  63. for (i = PARENT(nmemb-1) + 1; i-- > 0 ;)
  64. downheap(array, nmemb, size, cmp, ctx, i);
  65. /*
  66. * Stage 2: dismantle the heap by repeatedly swapping the root
  67. * element (at index 0) into the last position and then
  68. * downheaping the new root.
  69. */
  70. for (i = nmemb-1; i > 0; i--) {
  71. SWAP(0, i);
  72. downheap(array, i, size, cmp, ctx, 0);
  73. }
  74. }