sort.red 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. module sort; % A simple sorting routine.
  2. % Author: Arthur C. Norman.
  3. symbolic procedure sort(l,pred);
  4. % Sort the list l according to the given predicate. If l is a list
  5. % of numbers then the predicate "lessp" will sort the list into
  6. % ascending order. The predicate should be a strict inequality,
  7. % i.e. it should return NIL if the two items compared are equal. As
  8. % implemented here SORT just calls STABLE-SORT, but as a matter of
  9. % style any use where the ordering of incomparable items in the
  10. % output matters ought to use STABLE!-SORT directly, thereby
  11. % allowing the replacement of this code with a faster non-stable
  12. % method. (Note: the previous REDUCE sort function also happened to
  13. % be stable, so this code should give exactly the same results for
  14. % all calls where the predicate is self-consistent and never has
  15. % both pred(a,b) and pred(b,a) true).
  16. stable!-sortip(append(l, nil), pred);
  17. symbolic procedure stable!-sort(l,pred);
  18. % Sorts a list, as SORT, but if two items x and y in the input list
  19. % satisfy neither pred(x,y) nor pred(y,x) [i.e. they are equal so far
  20. % as the given ordering predicate is concerned] this function
  21. % guarantees that they will appear in the output list in the same
  22. % order that they were in the input.
  23. stable!-sortip(append(l, nil), pred);
  24. symbolic procedure stable!-sortip(l, pred);
  25. % As stable!-sort, but over-writes the input list to make the output.
  26. % It is not intended that people should call this function directly:
  27. % it is present just as the implementation of the main sort
  28. % procedures defined above.
  29. begin scalar l1,l2,w;
  30. if null l then return l; % Input list of length 0
  31. l1 := l;
  32. l2 := cdr l;
  33. if null l2 then return l; % Input list of length 1
  34. % Now I have dealt with the essential special cases of lists of
  35. % length 0 and 1 (which do not need sorting at all). Since it
  36. % possibly speeds things up just a little I will now have some
  37. % fairly ugly code that makes special cases of lists of length 2.
  38. % I could easily have special code for length 3 lists here (and
  39. % include it, but commented out), but at present my measurements
  40. % suggest that the speed improvement that it gives is minimal and
  41. % the increase in code bulk is large enough to give some pain.
  42. l := cdr l2;
  43. if null l then << % Input list of length 2
  44. if apply2(pred, car l2, car l1) then <<
  45. l := car l1;
  46. rplaca(l1, car l2);
  47. rplaca(l2, l) >>;
  48. return l1 >>;
  49. % Now I will check to see if the list is in fact in order already
  50. % Doing so will have a cost - but sometimes that cost will be
  51. % repaid when I am able to exit especially early. The result of
  52. % all this is that I will have a best case behaviour with linear
  53. % cost growth for inputs that are initially in the correct order,
  54. % while my average and worst-case costs will increase by a
  55. % constant factor.
  56. l := l1;
  57. % In the input list is NOT already in order then I expect that
  58. % this loop will exit fairly early, and so will not contribute
  59. % much to the total cost. If it exits very late then probably in
  60. % the next recursion down the first half of the list will be
  61. % found to be already sorted, and again I have a chance to win.
  62. while l2 and not apply2(pred, car l2, car l) do
  63. <<l := l2; l2 := cdr l2 >>;
  64. if null l2 then return l1;
  65. l2 := l1;
  66. l := cddr l2;
  67. while l and cdr l do << l2 := cdr l2; l := cddr l >>;
  68. l := l2;
  69. l2 := cdr l2;
  70. rplacd(l, nil);
  71. % The two sub-lists are then sorted.
  72. l1 := stable!-sortip(l1, pred);
  73. l2 := stable!-sortip(l2, pred);
  74. % Now I merge the sorted fragments, giving priority to item from
  75. % the earlier part of the original list.
  76. l := w := list nil;
  77. while l1 and l2 do <<
  78. if apply2(pred, car l2, car l1) then <<
  79. rplacd(w, l2); w := l2; l2 := cdr l2 >>
  80. else <<rplacd(w, l1); w := l1; l1 := cdr l1>>>>;
  81. if l1 then l2 := l1;
  82. rplacd(w,l2);
  83. return cdr l
  84. end;
  85. symbolic procedure idsort u;
  86. % lexicographically sort list of ids.
  87. sort(u,function idcompare);
  88. symbolic procedure idcompare(u,v);
  89. % compare lexicographical ordering of two ids.
  90. idcomp1(explode2 u,explode2 v);
  91. symbolic procedure idcomp1(u,v);
  92. if null u then t
  93. else if null v then nil
  94. else if car u eq car v then idcomp1(cdr u,cdr v)
  95. else orderp(car u,car v);
  96. % Comparison functions and special cases for sorting.
  97. symbolic procedure lesspcar(a,b); car a < car b;
  98. symbolic procedure lesspcdr(a,b); cdr a < cdr b;
  99. symbolic procedure lessppair(a,b);
  100. if car a = car b then cdr a<cdr b else car a<car b;
  101. symbolic procedure greaterpcdr(a,b); cdr a > cdr b;
  102. symbolic procedure lesspcdadr(a,b); cdadr a < cdadr b;
  103. symbolic procedure lesspdeg(a,b);
  104. if domainp b then nil else if domainp a then t else ldeg a<ldeg b;
  105. symbolic procedure ordopcar(a,b); ordop(car a,car b);
  106. symbolic procedure orderfactors(a,b);
  107. if cdr a = cdr b then ordp(car a,car b) else cdr a < cdr b;
  108. symbolic procedure sort!-factors l;
  109. % Sort factors as found into some sort of standard order. The order
  110. % used here is more or less random, but will be self-consistent.
  111. sort(l,function orderfactors);
  112. endmodule;
  113. end;