sort.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /* Copyright (C) 1999,2000,2001,2002, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
  2. * This library is free software; you can redistribute it and/or
  3. * modify it under the terms of the GNU Lesser General Public License
  4. * as published by the Free Software Foundation; either version 3 of
  5. * the License, or (at your option) any later version.
  6. *
  7. * This library is distributed in the hope that it will be useful, but
  8. * WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. * Lesser General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU Lesser General Public
  13. * License along with this library; if not, write to the Free Software
  14. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. * 02110-1301 USA
  16. */
  17. /* Written in December 1998 by Roland Orre <orre@nada.kth.se>
  18. * This implements the same sort interface as slib/sort.scm
  19. * for lists and vectors where slib defines:
  20. * sorted?, merge, merge!, sort, sort!
  21. * For scsh compatibility sort-list and sort-list! are also defined.
  22. * In cases where a stable-sort is required use stable-sort or
  23. * stable-sort!. An additional feature is
  24. * (restricted-vector-sort! vector less? startpos endpos)
  25. * which allows you to sort part of a vector.
  26. * Thanks to Aubrey Jaffer for the slib/sort.scm library.
  27. * Thanks to Richard A. O'Keefe (based on Prolog code by D.H.D.Warren)
  28. * for the merge sort inspiration.
  29. * Thanks to Douglas C. Schmidt (schmidt@ics.uci.edu) for the
  30. * quicksort code.
  31. */
  32. #ifdef HAVE_CONFIG_H
  33. # include <config.h>
  34. #endif
  35. #include "libguile/_scm.h"
  36. #include "libguile/eval.h"
  37. #include "libguile/arrays.h"
  38. #include "libguile/array-map.h"
  39. #include "libguile/feature.h"
  40. #include "libguile/vectors.h"
  41. #include "libguile/async.h"
  42. #include "libguile/dynwind.h"
  43. #include "libguile/validate.h"
  44. #include "libguile/sort.h"
  45. /* We have two quicksort variants: one for contigous vectors and one
  46. for vectors with arbitrary increments between elements. Note that
  47. increments can be negative.
  48. */
  49. #define NAME quicksort1
  50. #define INC_PARAM /* empty */
  51. #define INC 1
  52. #include "libguile/quicksort.i.c"
  53. #define NAME quicksort
  54. #define INC_PARAM ssize_t inc,
  55. #define INC inc
  56. #include "libguile/quicksort.i.c"
  57. SCM_DEFINE (scm_restricted_vector_sort_x, "restricted-vector-sort!", 4, 0, 0,
  58. (SCM vec, SCM less, SCM startpos, SCM endpos),
  59. "Sort the vector @var{vec}, using @var{less} for comparing\n"
  60. "the vector elements. @var{startpos} (inclusively) and\n"
  61. "@var{endpos} (exclusively) delimit\n"
  62. "the range of the vector which gets sorted. The return value\n"
  63. "is not specified.")
  64. #define FUNC_NAME s_scm_restricted_vector_sort_x
  65. {
  66. size_t vlen, spos, len;
  67. ssize_t vinc;
  68. scm_t_array_handle handle;
  69. SCM *velts;
  70. velts = scm_vector_writable_elements (vec, &handle, &vlen, &vinc);
  71. spos = scm_to_unsigned_integer (startpos, 0, vlen);
  72. len = scm_to_unsigned_integer (endpos, spos, vlen) - spos;
  73. if (vinc == 1)
  74. quicksort1 (velts + spos*vinc, len, less);
  75. else
  76. quicksort (velts + spos*vinc, len, vinc, less);
  77. scm_array_handle_release (&handle);
  78. return SCM_UNSPECIFIED;
  79. }
  80. #undef FUNC_NAME
  81. /* (sorted? sequence less?)
  82. * is true when sequence is a list (x0 x1 ... xm) or a vector #(x0 ... xm)
  83. * such that for all 1 <= i <= m,
  84. * (not (less? (list-ref list i) (list-ref list (- i 1)))). */
  85. SCM_DEFINE (scm_sorted_p, "sorted?", 2, 0, 0,
  86. (SCM items, SCM less),
  87. "Return @code{#t} iff @var{items} is a list or a vector such that\n"
  88. "for all 1 <= i <= m, the predicate @var{less} returns true when\n"
  89. "applied to all elements i - 1 and i")
  90. #define FUNC_NAME s_scm_sorted_p
  91. {
  92. long len, j; /* list/vector length, temp j */
  93. SCM item, rest; /* rest of items loop variable */
  94. if (SCM_NULL_OR_NIL_P (items))
  95. return SCM_BOOL_T;
  96. if (scm_is_pair (items))
  97. {
  98. len = scm_ilength (items); /* also checks that it's a pure list */
  99. SCM_ASSERT_RANGE (1, items, len >= 0);
  100. if (len <= 1)
  101. return SCM_BOOL_T;
  102. item = SCM_CAR (items);
  103. rest = SCM_CDR (items);
  104. j = len - 1;
  105. while (j > 0)
  106. {
  107. if (scm_is_true (scm_call_2 (less, SCM_CAR (rest), item)))
  108. return SCM_BOOL_F;
  109. else
  110. {
  111. item = SCM_CAR (rest);
  112. rest = SCM_CDR (rest);
  113. j--;
  114. }
  115. }
  116. return SCM_BOOL_T;
  117. }
  118. else
  119. {
  120. scm_t_array_handle handle;
  121. size_t i, len;
  122. ssize_t inc;
  123. const SCM *elts;
  124. SCM result = SCM_BOOL_T;
  125. elts = scm_vector_elements (items, &handle, &len, &inc);
  126. for (i = 1; i < len; i++, elts += inc)
  127. {
  128. if (scm_is_true (scm_call_2 (less, elts[inc], elts[0])))
  129. {
  130. result = SCM_BOOL_F;
  131. break;
  132. }
  133. }
  134. scm_array_handle_release (&handle);
  135. return result;
  136. }
  137. return SCM_BOOL_F;
  138. }
  139. #undef FUNC_NAME
  140. /* (merge a b less?)
  141. takes two lists a and b such that (sorted? a less?) and (sorted? b less?)
  142. and returns a new list in which the elements of a and b have been stably
  143. interleaved so that (sorted? (merge a b less?) less?).
  144. Note: this does _not_ accept vectors. */
  145. SCM_DEFINE (scm_merge, "merge", 3, 0, 0,
  146. (SCM alist, SCM blist, SCM less),
  147. "Merge two already sorted lists into one.\n"
  148. "Given two lists @var{alist} and @var{blist}, such that\n"
  149. "@code{(sorted? alist less?)} and @code{(sorted? blist less?)},\n"
  150. "return a new list in which the elements of @var{alist} and\n"
  151. "@var{blist} have been stably interleaved so that\n"
  152. "@code{(sorted? (merge alist blist less?) less?)}.\n"
  153. "Note: this does _not_ accept vectors.")
  154. #define FUNC_NAME s_scm_merge
  155. {
  156. SCM build;
  157. if (SCM_NULL_OR_NIL_P (alist))
  158. return blist;
  159. else if (SCM_NULL_OR_NIL_P (blist))
  160. return alist;
  161. else
  162. {
  163. long alen, blen; /* list lengths */
  164. SCM last;
  165. SCM_VALIDATE_NONEMPTYLIST_COPYLEN (1, alist, alen);
  166. SCM_VALIDATE_NONEMPTYLIST_COPYLEN (2, blist, blen);
  167. if (scm_is_true (scm_call_2 (less, SCM_CAR (blist), SCM_CAR (alist))))
  168. {
  169. build = scm_cons (SCM_CAR (blist), SCM_EOL);
  170. blist = SCM_CDR (blist);
  171. blen--;
  172. }
  173. else
  174. {
  175. build = scm_cons (SCM_CAR (alist), SCM_EOL);
  176. alist = SCM_CDR (alist);
  177. alen--;
  178. }
  179. last = build;
  180. while ((alen > 0) && (blen > 0))
  181. {
  182. SCM_TICK;
  183. if (scm_is_true (scm_call_2 (less, SCM_CAR (blist), SCM_CAR (alist))))
  184. {
  185. SCM_SETCDR (last, scm_cons (SCM_CAR (blist), SCM_EOL));
  186. blist = SCM_CDR (blist);
  187. blen--;
  188. }
  189. else
  190. {
  191. SCM_SETCDR (last, scm_cons (SCM_CAR (alist), SCM_EOL));
  192. alist = SCM_CDR (alist);
  193. alen--;
  194. }
  195. last = SCM_CDR (last);
  196. }
  197. if ((alen > 0) && (blen == 0))
  198. SCM_SETCDR (last, alist);
  199. else if ((alen == 0) && (blen > 0))
  200. SCM_SETCDR (last, blist);
  201. }
  202. return build;
  203. }
  204. #undef FUNC_NAME
  205. static SCM
  206. scm_merge_list_x (SCM alist, SCM blist,
  207. long alen, long blen,
  208. SCM less)
  209. {
  210. SCM build, last;
  211. if (SCM_NULL_OR_NIL_P (alist))
  212. return blist;
  213. else if (SCM_NULL_OR_NIL_P (blist))
  214. return alist;
  215. else
  216. {
  217. if (scm_is_true (scm_call_2 (less, SCM_CAR (blist), SCM_CAR (alist))))
  218. {
  219. build = blist;
  220. blist = SCM_CDR (blist);
  221. blen--;
  222. }
  223. else
  224. {
  225. build = alist;
  226. alist = SCM_CDR (alist);
  227. alen--;
  228. }
  229. last = build;
  230. while ((alen > 0) && (blen > 0))
  231. {
  232. SCM_TICK;
  233. if (scm_is_true (scm_call_2 (less, SCM_CAR (blist), SCM_CAR (alist))))
  234. {
  235. SCM_SETCDR (last, blist);
  236. blist = SCM_CDR (blist);
  237. blen--;
  238. }
  239. else
  240. {
  241. SCM_SETCDR (last, alist);
  242. alist = SCM_CDR (alist);
  243. alen--;
  244. }
  245. last = SCM_CDR (last);
  246. }
  247. if ((alen > 0) && (blen == 0))
  248. SCM_SETCDR (last, alist);
  249. else if ((alen == 0) && (blen > 0))
  250. SCM_SETCDR (last, blist);
  251. }
  252. return build;
  253. } /* scm_merge_list_x */
  254. SCM_DEFINE (scm_merge_x, "merge!", 3, 0, 0,
  255. (SCM alist, SCM blist, SCM less),
  256. "Takes two lists @var{alist} and @var{blist} such that\n"
  257. "@code{(sorted? alist less?)} and @code{(sorted? blist less?)} and\n"
  258. "returns a new list in which the elements of @var{alist} and\n"
  259. "@var{blist} have been stably interleaved so that\n"
  260. " @code{(sorted? (merge alist blist less?) less?)}.\n"
  261. "This is the destructive variant of @code{merge}\n"
  262. "Note: this does _not_ accept vectors.")
  263. #define FUNC_NAME s_scm_merge_x
  264. {
  265. if (SCM_NULL_OR_NIL_P (alist))
  266. return blist;
  267. else if (SCM_NULL_OR_NIL_P (blist))
  268. return alist;
  269. else
  270. {
  271. long alen, blen; /* list lengths */
  272. SCM_VALIDATE_NONEMPTYLIST_COPYLEN (1, alist, alen);
  273. SCM_VALIDATE_NONEMPTYLIST_COPYLEN (2, blist, blen);
  274. return scm_merge_list_x (alist, blist, alen, blen, less);
  275. }
  276. }
  277. #undef FUNC_NAME
  278. /* This merge sort algorithm is same as slib's by Richard A. O'Keefe.
  279. The algorithm is stable. We also tried to use the algorithm used by
  280. scsh's merge-sort but that algorithm showed to not be stable, even
  281. though it claimed to be.
  282. */
  283. static SCM
  284. scm_merge_list_step (SCM * seq, SCM less, long n)
  285. {
  286. SCM a, b;
  287. if (n > 2)
  288. {
  289. long mid = n / 2;
  290. SCM_TICK;
  291. a = scm_merge_list_step (seq, less, mid);
  292. b = scm_merge_list_step (seq, less, n - mid);
  293. return scm_merge_list_x (a, b, mid, n - mid, less);
  294. }
  295. else if (n == 2)
  296. {
  297. SCM p = *seq;
  298. SCM rest = SCM_CDR (*seq);
  299. SCM x = SCM_CAR (*seq);
  300. SCM y = SCM_CAR (SCM_CDR (*seq));
  301. *seq = SCM_CDR (rest);
  302. SCM_SETCDR (rest, SCM_EOL);
  303. if (scm_is_true (scm_call_2 (less, y, x)))
  304. {
  305. SCM_SETCAR (p, y);
  306. SCM_SETCAR (rest, x);
  307. }
  308. return p;
  309. }
  310. else if (n == 1)
  311. {
  312. SCM p = *seq;
  313. *seq = SCM_CDR (p);
  314. SCM_SETCDR (p, SCM_EOL);
  315. return p;
  316. }
  317. else
  318. return SCM_EOL;
  319. } /* scm_merge_list_step */
  320. SCM_DEFINE (scm_sort_x, "sort!", 2, 0, 0,
  321. (SCM items, SCM less),
  322. "Sort the sequence @var{items}, which may be a list or a\n"
  323. "vector. @var{less} is used for comparing the sequence\n"
  324. "elements. The sorting is destructive, that means that the\n"
  325. "input sequence is modified to produce the sorted result.\n"
  326. "This is not a stable sort.")
  327. #define FUNC_NAME s_scm_sort_x
  328. {
  329. long len; /* list/vector length */
  330. if (SCM_NULL_OR_NIL_P (items))
  331. return items;
  332. if (scm_is_pair (items))
  333. {
  334. SCM_VALIDATE_LIST_COPYLEN (1, items, len);
  335. return scm_merge_list_step (&items, less, len);
  336. }
  337. else if (scm_is_vector (items))
  338. {
  339. scm_restricted_vector_sort_x (items,
  340. less,
  341. scm_from_int (0),
  342. scm_vector_length (items));
  343. return items;
  344. }
  345. else
  346. SCM_WRONG_TYPE_ARG (1, items);
  347. }
  348. #undef FUNC_NAME
  349. SCM_DEFINE (scm_sort, "sort", 2, 0, 0,
  350. (SCM items, SCM less),
  351. "Sort the sequence @var{items}, which may be a list or a\n"
  352. "vector. @var{less} is used for comparing the sequence\n"
  353. "elements. This is not a stable sort.")
  354. #define FUNC_NAME s_scm_sort
  355. {
  356. if (SCM_NULL_OR_NIL_P (items))
  357. return items;
  358. if (scm_is_pair (items))
  359. return scm_sort_x (scm_list_copy (items), less);
  360. else if (scm_is_vector (items))
  361. return scm_sort_x (scm_vector_copy (items), less);
  362. else
  363. SCM_WRONG_TYPE_ARG (1, items);
  364. }
  365. #undef FUNC_NAME
  366. static void
  367. scm_merge_vector_x (SCM *vec,
  368. SCM *temp,
  369. SCM less,
  370. size_t low,
  371. size_t mid,
  372. size_t high,
  373. ssize_t inc)
  374. {
  375. size_t it; /* Index for temp vector */
  376. size_t i1 = low; /* Index for lower vector segment */
  377. size_t i2 = mid + 1; /* Index for upper vector segment */
  378. #define VEC(i) vec[(i)*inc]
  379. /* Copy while both segments contain more characters */
  380. for (it = low; (i1 <= mid) && (i2 <= high); ++it)
  381. {
  382. if (scm_is_true (scm_call_2 (less, VEC(i2), VEC(i1))))
  383. temp[it] = VEC(i2++);
  384. else
  385. temp[it] = VEC(i1++);
  386. }
  387. {
  388. /* Copy while first segment contains more characters */
  389. while (i1 <= mid)
  390. temp[it++] = VEC(i1++);
  391. /* Copy while second segment contains more characters */
  392. while (i2 <= high)
  393. temp[it++] = VEC(i2++);
  394. /* Copy back from temp to vp */
  395. for (it = low; it <= high; it++)
  396. VEC(it) = temp[it];
  397. }
  398. } /* scm_merge_vector_x */
  399. static void
  400. scm_merge_vector_step (SCM *vec,
  401. SCM *temp,
  402. SCM less,
  403. size_t low,
  404. size_t high,
  405. ssize_t inc)
  406. {
  407. if (high > low)
  408. {
  409. size_t mid = (low + high) / 2;
  410. SCM_TICK;
  411. scm_merge_vector_step (vec, temp, less, low, mid, inc);
  412. scm_merge_vector_step (vec, temp, less, mid+1, high, inc);
  413. scm_merge_vector_x (vec, temp, less, low, mid, high, inc);
  414. }
  415. } /* scm_merge_vector_step */
  416. SCM_DEFINE (scm_stable_sort_x, "stable-sort!", 2, 0, 0,
  417. (SCM items, SCM less),
  418. "Sort the sequence @var{items}, which may be a list or a\n"
  419. "vector. @var{less} is used for comparing the sequence elements.\n"
  420. "The sorting is destructive, that means that the input sequence\n"
  421. "is modified to produce the sorted result.\n"
  422. "This is a stable sort.")
  423. #define FUNC_NAME s_scm_stable_sort_x
  424. {
  425. long len; /* list/vector length */
  426. if (SCM_NULL_OR_NIL_P (items))
  427. return items;
  428. if (scm_is_pair (items))
  429. {
  430. SCM_VALIDATE_LIST_COPYLEN (1, items, len);
  431. return scm_merge_list_step (&items, less, len);
  432. }
  433. else if (scm_is_vector (items))
  434. {
  435. scm_t_array_handle temp_handle, vec_handle;
  436. SCM temp, *temp_elts, *vec_elts;
  437. size_t len;
  438. ssize_t inc;
  439. vec_elts = scm_vector_writable_elements (items, &vec_handle,
  440. &len, &inc);
  441. if (len == 0) {
  442. scm_array_handle_release (&vec_handle);
  443. return items;
  444. }
  445. temp = scm_c_make_vector (len, SCM_UNDEFINED);
  446. temp_elts = scm_vector_writable_elements (temp, &temp_handle,
  447. NULL, NULL);
  448. scm_merge_vector_step (vec_elts, temp_elts, less, 0, len-1, inc);
  449. scm_array_handle_release (&temp_handle);
  450. scm_array_handle_release (&vec_handle);
  451. return items;
  452. }
  453. else
  454. SCM_WRONG_TYPE_ARG (1, items);
  455. }
  456. #undef FUNC_NAME
  457. SCM_DEFINE (scm_stable_sort, "stable-sort", 2, 0, 0,
  458. (SCM items, SCM less),
  459. "Sort the sequence @var{items}, which may be a list or a\n"
  460. "vector. @var{less} is used for comparing the sequence elements.\n"
  461. "This is a stable sort.")
  462. #define FUNC_NAME s_scm_stable_sort
  463. {
  464. if (SCM_NULL_OR_NIL_P (items))
  465. return SCM_EOL;
  466. if (scm_is_pair (items))
  467. return scm_stable_sort_x (scm_list_copy (items), less);
  468. else if (scm_is_vector (items))
  469. return scm_stable_sort_x (scm_vector_copy (items), less);
  470. else
  471. SCM_WRONG_TYPE_ARG (1, items);
  472. }
  473. #undef FUNC_NAME
  474. SCM_DEFINE (scm_sort_list_x, "sort-list!", 2, 0, 0,
  475. (SCM items, SCM less),
  476. "Sort the list @var{items}, using @var{less} for comparing the\n"
  477. "list elements. The sorting is destructive, that means that the\n"
  478. "input list is modified to produce the sorted result.\n"
  479. "This is a stable sort.")
  480. #define FUNC_NAME s_scm_sort_list_x
  481. {
  482. long len;
  483. SCM_VALIDATE_LIST_COPYLEN (1, items, len);
  484. return scm_merge_list_step (&items, less, len);
  485. }
  486. #undef FUNC_NAME
  487. SCM_DEFINE (scm_sort_list, "sort-list", 2, 0, 0,
  488. (SCM items, SCM less),
  489. "Sort the list @var{items}, using @var{less} for comparing the\n"
  490. "list elements. This is a stable sort.")
  491. #define FUNC_NAME s_scm_sort_list
  492. {
  493. long len;
  494. SCM_VALIDATE_LIST_COPYLEN (1, items, len);
  495. items = scm_list_copy (items);
  496. return scm_merge_list_step (&items, less, len);
  497. }
  498. #undef FUNC_NAME
  499. void
  500. scm_init_sort ()
  501. {
  502. #include "libguile/sort.x"
  503. scm_add_feature ("sort");
  504. }
  505. /*
  506. Local Variables:
  507. c-file-style: "gnu"
  508. End:
  509. */