1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.functor.example;
18
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertTrue;
21 import static org.junit.Assert.fail;
22
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Random;
27
28 import org.apache.commons.functor.BinaryFunction;
29 import org.apache.commons.functor.UnaryFunction;
30 import org.apache.commons.functor.core.Constant;
31 import org.apache.commons.functor.core.collection.IsEmpty;
32 import org.apache.commons.functor.core.comparator.IsGreaterThanOrEqual;
33 import org.apache.commons.functor.core.comparator.IsLessThan;
34 import org.apache.commons.functor.core.composite.ConditionalUnaryFunction;
35 import org.apache.commons.functor.generator.FilteredGenerator;
36 import org.apache.commons.functor.generator.IteratorToGeneratorAdapter;
37 import org.junit.Test;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 @SuppressWarnings("unchecked")
63 public class QuicksortExample {
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 @Test
85 public void testSortEmpty() {
86 List empty = Collections.EMPTY_LIST;
87 List result = quicksort(empty);
88 assertTrue("Sorting an empty list should produce an empty list.", result.isEmpty());
89 }
90
91
92
93
94
95
96 @Test
97 public void testSortSingleElementList() {
98 List list = new ArrayList();
99 list.add("element");
100
101 List sorted = quicksort(list);
102
103 assertTrue(
104 "The quicksort() method should return a distinct list.",
105 list != sorted);
106
107 assertEquals(
108 "Sorting a single-element list should produce an equivalent list",
109 list,
110 sorted);
111 }
112
113
114
115
116
117
118 @Test
119 public void testSortSingleValueList() {
120 List list = new ArrayList();
121 for (int i = 0; i < 10; i++) {
122 list.add("element");
123 }
124 List sorted = quicksort(list);
125
126 assertTrue(
127 "The quicksort() method should return a distinct list.",
128 list != sorted);
129
130 assertEquals(list, sorted);
131 }
132
133
134
135
136
137
138
139
140 @Test
141 public void testSortSorted() {
142 List list = new ArrayList();
143 for (int i = 0; i < 10; i++) {
144 list.add(new Integer(i));
145 }
146
147 List sorted = quicksort(list);
148
149 assertTrue(
150 "The quicksort() method should return a distinct list.",
151 list != sorted);
152
153 assertEquals(
154 "Sorting an already sorted list should produce an equivalent list",
155 list,
156 sorted);
157 }
158
159
160
161
162
163 @Test
164 public void testSortReversed() {
165 List expected = new ArrayList();
166 List tosort = new ArrayList();
167 for (int i = 0; i < 10; i++) {
168
169
170
171 expected.add(new Integer(i));
172
173
174
175 tosort.add(new Integer(9 - i));
176 }
177
178 assertEquals(expected, quicksort(tosort));
179 }
180
181
182
183
184 @Test
185 public void testSortShuffled() {
186 List expected = new ArrayList();
187 for (int i = 0; i < 10; i++) {
188 expected.add(new Integer(i));
189 }
190 List tosort = new ArrayList(expected);
191 Collections.shuffle(tosort);
192
193 assertEquals(expected, quicksort(tosort));
194 }
195
196
197
198
199 @Test
200 public void testSortRandom() {
201 Random random = new Random();
202
203
204
205 List tosort = new ArrayList();
206 for (int i = 0; i < 10; i++) {
207 tosort.add(new Integer(random.nextInt(10)));
208 }
209
210
211
212
213 List expected = new ArrayList(tosort);
214 Collections.sort(expected);
215
216 assertEquals(expected, quicksort(tosort));
217 }
218
219
220
221
222
223
224
225
226 private static final int SIZE = 1000;
227 private static final int COUNT = 100;
228
229 @Test
230 public void testTimings() {
231
232
233
234 long elapsed = 0L;
235
236
237
238
239 Random random = new Random();
240
241
242
243
244 for (int i = 0; i < COUNT; i++) {
245
246
247
248
249 List tosort = new ArrayList(SIZE);
250 for (int j = 0; j < SIZE; j++) {
251 tosort.add(new Integer(random.nextInt(SIZE)));
252 }
253
254
255
256
257 long start = System.currentTimeMillis();
258
259
260
261
262
263 quicksort(tosort);
264
265
266
267
268 long stop = System.currentTimeMillis();
269
270
271
272
273 elapsed += stop - start;
274 }
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300 }
301
302
303
304
305
306
307
308
309
310
311
312
313 public List quicksort(List list) {
314 return (List)(quicksort.evaluate(list));
315 }
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340 private UnaryFunction quicksort = new ConditionalUnaryFunction(
341
342 IsEmpty.instance(),
343
344 new Constant(Collections.EMPTY_LIST),
345
346 new ListFunction() {
347 public Object evaluate(List list) {
348
349 List result = new ArrayList(list.size());
350
351
352
353
354
355 result.addAll(
356 (List) quicksort.evaluate(
357 lesserTail.evaluate(
358 head.evaluate(list),
359 tail.evaluate(list))));
360
361
362
363 result.add(head.evaluate(list));
364
365
366
367
368
369 result.addAll(
370 (List) quicksort.evaluate(
371 greaterTail.evaluate(
372 head.evaluate(list),
373 tail.evaluate(list))));
374
375
376
377 return result;
378 }
379 });
380
381
382
383
384
385
386
387
388
389
390
391 public abstract class ListFunction implements UnaryFunction {
392 public abstract Object evaluate(List list);
393
394 public Object evaluate(Object obj) {
395 if (obj instanceof List) {
396 return evaluate((List) obj);
397 } else if (null == obj) {
398 throw new NullPointerException("The argument must not be null.");
399 } else {
400 throw new ClassCastException(
401 "The argument must be a List, found " +
402 obj.getClass().getName());
403 }
404 }
405 }
406
407
408
409
410
411
412 public abstract class ObjectListFunction implements BinaryFunction {
413 public abstract Object evaluate(Object head, List tail);
414
415 public Object evaluate(Object left, Object right) {
416 if (left != null && right instanceof List) {
417 return evaluate(left, (List) right);
418 } else if (null == left) {
419 throw new NullPointerException("The left argument must not be null.");
420 } else if (null == right) {
421 throw new NullPointerException("The right argument must not be null.");
422 } else {
423 throw new ClassCastException(
424 "The right argument must be a List, found " +
425 right.getClass().getName());
426 }
427 }
428 }
429
430
431
432
433
434
435
436 private UnaryFunction head = new ListFunction() {
437 public Object evaluate(List list) {
438 return list.get(0);
439 }
440 };
441
442
443
444
445 private UnaryFunction tail = new ListFunction() {
446 public Object evaluate(List list) {
447 return list.size() < 2 ?
448 Collections.EMPTY_LIST :
449 list.subList(1, list.size());
450 }
451 };
452
453
454
455
456
457
458
459 private BinaryFunction lesserTail = new ObjectListFunction() {
460 public Object evaluate(Object head, List tail) {
461 return new FilteredGenerator(
462 IteratorToGeneratorAdapter.adapt(tail.iterator()),
463 IsLessThan.instance((Comparable) head)).toCollection();
464 }
465 };
466
467
468
469
470
471
472 private BinaryFunction greaterTail = new ObjectListFunction() {
473 public Object evaluate(Object head, List tail) {
474 return new FilteredGenerator(
475 IteratorToGeneratorAdapter.adapt(tail.iterator()),
476 IsGreaterThanOrEqual.instance((Comparable) head)).toCollection();
477 }
478 };
479
480
481
482
483
484
485 public void testHeadFunction() {
486 List list = new ArrayList();
487 try {
488 head.evaluate(list);
489 fail("Expected IndexOutOfBoundsException when evaluating head of an empty list");
490 } catch(IndexOutOfBoundsException e) {
491
492 }
493
494 list.add("First");
495 assertEquals("First",head.evaluate(list));
496
497 list.add("Second");
498 assertEquals("First",head.evaluate(list));
499
500 }
501
502 public void testTailFunction() {
503 List list = new ArrayList();
504 {
505 List result = (List)(tail.evaluate(list));
506 assertTrue("Tail of an empty list is empty.",result.isEmpty());
507 }
508 list.add("First");
509 {
510 List result = (List)(tail.evaluate(list));
511 assertTrue("Tail of a one element list is empty.",result.isEmpty());
512 }
513 list.add("Second");
514 {
515 List result = (List)(tail.evaluate(list));
516 assertEquals("Tail of a two element list has one element.",1,result.size());
517 assertEquals("Second",result.get(0));
518 }
519 list.add("Third");
520 {
521 List result = (List)(tail.evaluate(list));
522 assertEquals("Tail of a three element list has two elements.",2,result.size());
523 assertEquals("Second",result.get(0));
524 assertEquals("Third",result.get(1));
525 }
526 }
527
528 public void testLesserTail() {
529 List list = new ArrayList();
530 for (int i=0;i<10;i++) {
531 list.add(new Integer(i));
532 }
533 for (int i=0;i<10;i++) {
534 Integer val = new Integer(i);
535 List lesser = (List) lesserTail.evaluate(val,list);
536 assertEquals(i,lesser.size());
537 for (int j=0;j<i;j++) {
538 assertEquals(new Integer(j),lesser.get(j));
539 }
540 }
541 }
542
543 public void testGreaterTail() {
544 List list = new ArrayList();
545 for (int i=0;i<10;i++) {
546 list.add(new Integer(i));
547 }
548 for (int i=0;i<10;i++) {
549 Integer val = new Integer(i);
550 List greater = (List) greaterTail.evaluate(val,list);
551 assertEquals(10-i,greater.size());
552 for (int j=i;j<10;j++) {
553 assertEquals(new Integer(j),greater.get(j-i));
554 }
555 }
556 }
557 }