2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Sort a list using a variant of the MergeSort algorithm.
9 #include <exec/lists.h>
12 #if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
13 __attribute__((regparm(2)))
15 /*****************************************************************************
18 static inline struct MinNode
*Merge(
22 int (*compare
)(struct MinNode
*n1
, struct MinNode
*n2
, void *data
),
26 Given a list of ordered circular sublists, merge pairs of ordered sublists into one
27 ordered circular sublist.
30 l - The first node of the first sublist. The sublists must be linked one
31 after the other one, and must be circular lists, that is their
32 first node's Pred pointer must point to their last node.
34 I.e., the 2nd sublist will be at l->mln_Pred->mln_Succ, the 3rd will be at
35 l->mln_Pred->mln_Succ->mln_Pred->mln_Succ and so on.
37 compare - Pointer to the comparison function used to merge the
40 data - Pointer to user-defined data which will be passed untouched
41 to the comparison function.
44 Pointer to the first node of the resulting list of sublists, with the same
45 format of the input list, but with pairs of sublists merged into one.
47 ******************************************************************************/
49 struct MinNode
*l1
, *last_l1
, *l2
, *last_l2
, *next_l
;
50 struct MinNode
*first
= NULL
, **first_ptr
, **last_ptr
= &first
;
54 /* l1 points to the 1st sublist, l2 points to the 2nd.
56 Should there be no l2, we don't need to do anything special, as
57 l1 will already be linked with the rest of the list AND it won't
58 obviously need to be merged with another list. */
59 while (l1
&& (l2
= (last_l1
= l1
->mln_Pred
)->mln_Succ
))
61 last_l2
= l2
->mln_Pred
;
63 next_l
= last_l2
->mln_Succ
;
65 /* This will make the below loop slightly faster, since there will only
66 be tests against the constant NULL. */
67 last_l1
->mln_Succ
= NULL
;
68 last_l2
->mln_Succ
= NULL
;
70 /* Pointer to the beginning of the merged sublist */
74 if (compare(l1
, l2
, data
) < 0)
76 l1
->mln_Pred
= (struct MinNode
*)((char *)last_ptr
-
77 offsetof(struct MinNode
, mln_Succ
));
83 l2
->mln_Pred
= (struct MinNode
*)((char *)last_ptr
-
84 offsetof(struct MinNode
, mln_Succ
));
89 last_ptr
= &(*last_ptr
)->mln_Succ
;
94 l1
->mln_Pred
= (struct MinNode
*)((char *)last_ptr
-
95 offsetof(struct MinNode
, mln_Succ
));
98 (*first_ptr
)->mln_Pred
= last_l1
;
99 last_ptr
= &last_l1
->mln_Succ
;
104 l2
->mln_Pred
= (struct MinNode
*)((char *)last_ptr
-
105 offsetof(struct MinNode
, mln_Succ
));
108 (*first_ptr
)->mln_Pred
= last_l2
;
109 last_ptr
= &last_l2
->mln_Succ
;
113 (*first_ptr
)->mln_Pred
= (struct MinNode
*)((char *)last_ptr
-
114 offsetof(struct MinNode
, mln_Succ
));
117 l1
= *last_ptr
= next_l
;
123 /*****************************************************************************
126 #include <clib/alib_protos.h>
131 int (*compare
)(struct MinNode
*n1
, struct MinNode
*n2
, void *data
),
135 Sorts an Exec-style doubly linked list, by using a variant of the merge sorting
136 algorithm, which is Theta(n log n ). No additional space is required other than
137 the one needed for local variables in the function itself. The function is not
141 l - The list to sort.
143 compare - Pointer to the comparison function which establishes the order
144 of the elements in the list
146 data - Pointer to user-defined data which will be passed untouched
147 to the comparison function.
150 The given list, sorted in place.
152 ******************************************************************************/
154 struct MinNode
*head
= (struct MinNode
*)GetHead(l
);
155 struct MinNode
*tail
= (struct MinNode
*)GetTail(l
);
157 struct MinNode
*l1
, *l2
,
160 if (!head
|| head
== tail
)
163 tail
->mln_Succ
= NULL
;
166 /* The Merge() function requires a list of sublists, each of which
167 has to be a circular list. Since the given list doesn't have these
168 properties, we need to divide the sorting algorithm in 2 parts:
170 1) we first go trough the list once, making every node's Pred pointer
171 point to the node itself, so that the given list of n nodes is
172 transformed in a list of n circular sublists. Here we do the merging
173 "manually", without the help of the Merge() function, as we have to
174 deal with just couples of nodes, thus we can do some extra optimization.
176 2) We then feed the resulting list to the Merge() function, as many times as
177 it takes to the Merge() function to give back just one circular list, rather
178 than a list of circular sublists: that will be our sorted list. */
180 /* This is the first part. */
185 /* It can happen that the 2 nodes are already in the right,
186 order and thus we only need to make a circular list out
187 of them, or their order needs to be reversed, but
188 in either case, the below line is necessary, because:
190 1) In the first case, it serves to build the
193 2) In the 2nd case, it does 1/4 of the job of
194 reversing the order of the nodes (the
195 other 3/4 are done inside the if block). */
198 if (compare(l1
, l2
, data
) >= 0)
200 /* l2 comes before l1, so rearrange them and
201 make a circular list out of them. */
202 l1
->mln_Succ
= l2
->mln_Succ
;
210 last_ptr
= &l1
->mln_Pred
->mln_Succ
;
212 } while (l1
&& (l2
= l1
->mln_Succ
));
214 /* An orphan node? Add it at the end of the list of sublists and
215 make a circular list out of it. */
222 /* And this is the 2nd part. */
223 while (first
->mln_Pred
->mln_Succ
)
224 first
= Merge(first
, compare
, data
);
226 /* Now we fix up the list header */
228 l
->mlh_TailPred
= first
->mln_Pred
;
229 first
->mln_Pred
->mln_Succ
= (struct MinNode
*)&l
->mlh_Tail
;
230 first
->mln_Pred
= (struct MinNode
*)&l
->mlh_Head
;