sort.c 16 KB

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