root/trunk/src/rt/qsort.d

Revision 506, 4.8 kB (checked in by braddr, 2 years ago)

fix array sort

  • Property svn:eol-style set to native
Line 
1 /*
2         Portions of this file are:
3         Copyright Prototronics, 1987
4         Totem Lake P.O. 8117
5         Kirkland, Washington 98034
6         (206) 820-1972
7         Licensed to Digital Mars.
8
9         June 11, 1987 from Ray Gardner's
10         Denver, Colorado) public domain version
11
12         Use qsort2.d instead of this file if a redistributable version of
13         _adSort() is required.
14 */
15
16 module rt.qsort;
17
18 /*
19 **    Sorts an array starting at base, of length nbr_elements, each
20 **    element of size width_bytes, ordered via compare_function; which
21 **    is called as  (*comp_fp)(ptr_to_element1, ptr_to_element2)
22 **    and returns < 0 if element1 < element2, 0 if element1 = element2,
23 **    > 0 if element1 > element2.  Most of the refinements are due to
24 **    R. Sedgewick.  See "Implementing Quicksort Programs", Comm. ACM,
25 **    Oct. 1978, and Corrigendum, Comm. ACM, June 1979.
26 */
27
28 //debug=qsort;          // uncomment to turn on debugging printf's
29
30
31 struct Array
32 {
33     size_t length;
34     void*  ptr;
35 }
36
37
38 private const int _maxspan = 7; // subarrays of _maxspan or fewer elements
39                                 // will be sorted by a simple insertion sort
40
41 /* Adjust _maxspan according to relative cost of a swap and a compare.  Reduce
42 _maxspan (not less than 1) if a swap is very expensive such as when you have
43 an array of large structures to be sorted, rather than an array of pointers to
44 structures.  The default value is optimized for a high cost for compares. */
45
46
47 extern (C) void[] _adSort(Array a, TypeInfo ti)
48 {
49   byte*[40] stack;              // stack
50   byte* i, j;            // scan and limit pointers
51   auto width = ti.tsize();
52
53   auto base = cast(byte *)a.ptr;
54   auto thresh = _maxspan * width;        // size of _maxspan elements in bytes
55   auto sp = stack.ptr;                   // stack pointer
56   auto limit = base + a.length * width;  // pointer past end of array
57   while (1)                              // repeat until done then return
58   {
59     while (limit - base > thresh)        // if more than _maxspan elements
60     {
61       //swap middle, base
62       ti.swap((cast(uint)(limit - base) >> 1) -
63            (((cast(uint)(limit - base) >> 1)) % width) + base, base);
64
65       i = base + width;                 // i scans from left to right
66       j = limit - width;                // j scans from right to left
67
68       if (ti.compare(i, j) > 0)         // Sedgewick's
69         ti.swap(i, j);                  //    three-element sort
70       if (ti.compare(base, j) > 0)      // sets things up
71         ti.swap(base, j);               // so that
72       if (ti.compare(i, base) > 0)      // *i <= *base <= *j
73         ti.swap(i, base);               // *base is the pivot element
74
75       while (1)
76       {
77         do                              // move i right until *i >= pivot
78           i += width;
79         while (ti.compare(i, base) < 0);
80         do                              // move j left until *j <= pivot
81           j -= width;
82         while (ti.compare(j, base) > 0);
83         if (i > j)                      // break loop if pointers crossed
84           break;
85         ti.swap(i, j);                  // else swap elements, keep scanning
86       }
87       ti.swap(base, j);                 // move pivot into correct place
88       if (j - base > limit - i)         // if left subarray is larger...
89       {
90         sp[0] = base;                   // stack left subarray base
91         sp[1] = j;                      //    and limit
92         base = i;                       // sort the right subarray
93       }
94       else                              // else right subarray is larger
95       {
96         sp[0] = i;                      // stack right subarray base
97         sp[1] = limit;                  //    and limit
98         limit = j;                      // sort the left subarray
99       }
100       sp += 2;                          // increment stack pointer
101       assert(sp < cast(byte**)stack + stack.length);
102     }
103
104     // Insertion sort on remaining subarray
105     i = base + width;
106     while (i < limit)
107     {
108       j = i;
109       while (j > base && ti.compare(j - width, j) > 0)
110       {
111         ti.swap(j - width, j);
112         j -= width;
113       }
114       i += width;
115     }
116
117     if (sp > stack.ptr)                 // if any entries on stack...
118     {
119       sp -= 2;                          // pop the base and limit
120       base = sp[0];
121       limit = sp[1];
122     }
123     else                                // else stack empty, all done
124       return *cast(void[]*)(&a);
125   }
126   assert(0);
127 }
128
129
130 unittest
131 {
132     debug(qsort) printf("array.sort.unittest()\n");
133
134     int a[] = new int[10];
135
136     a[0] = 23;
137     a[1] = 1;
138     a[2] = 64;
139     a[3] = 5;
140     a[4] = 6;
141     a[5] = 5;
142     a[6] = 17;
143     a[7] = 3;
144     a[8] = 0;
145     a[9] = -1;
146
147     a.sort;
148
149     for (int i = 0; i < a.length - 1; i++)
150     {
151         //printf("i = %d", i);
152         //printf(" %d %d\n", a[i], a[i + 1]);
153         assert(a[i] <= a[i + 1]);
154     }
155 }
Note: See TracBrowser for help on using the browser.