Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Annotation of /trunk/src/sorting.c
Parent Directory
|
Revision Log
Revision 875 -
(hide annotations)
(download)
(as text)
Sat Oct 22 16:27:29 2011 UTC (13 years, 5 months ago) by amb
File MIME type: text/x-csrc
File size: 16165 byte(s)
Sat Oct 22 16:27:29 2011 UTC (13 years, 5 months ago) by amb
File MIME type: text/x-csrc
File size: 16165 byte(s)
Revert back to something very close to r869 because it is fastest by a tiny fraction.
1 | amb | 269 | /*************************************** |
2 | Merge sort functions. | ||
3 | |||
4 | Part of the Routino routing software. | ||
5 | ******************/ /****************** | ||
6 | amb | 680 | This file Copyright 2009-2011 Andrew M. Bishop |
7 | amb | 269 | |
8 | This program is free software: you can redistribute it and/or modify | ||
9 | it under the terms of the GNU Affero General Public License as published by | ||
10 | the Free Software Foundation, either version 3 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU Affero General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU Affero General Public License | ||
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | ***************************************/ | ||
21 | |||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <string.h> | ||
26 | #include <assert.h> | ||
27 | |||
28 | amb | 532 | #include "types.h" |
29 | |||
30 | amb | 449 | #include "files.h" |
31 | amb | 532 | #include "sorting.h" |
32 | amb | 269 | |
33 | |||
34 | amb | 680 | /* Global variables */ |
35 | amb | 269 | |
36 | amb | 289 | /*+ The command line '--tmpdir' option or its default value. +*/ |
37 | amb | 284 | extern char *option_tmpdirname; |
38 | amb | 269 | |
39 | amb | 358 | /*+ The amount of RAM to use for filesorting. +*/ |
40 | extern size_t option_filesort_ramsize; | ||
41 | amb | 269 | |
42 | amb | 358 | |
43 | amb | 269 | /*++++++++++++++++++++++++++++++++++++++ |
44 | amb | 310 | A function to sort the contents of a file of fixed length objects using a |
45 | limited amount of RAM. | ||
46 | amb | 269 | |
47 | The data is sorted using a "Merge sort" http://en.wikipedia.org/wiki/Merge_sort | ||
48 | and in particular an "external sort" http://en.wikipedia.org/wiki/External_sorting. | ||
49 | The individual sort steps and the merge step both use a "Heap sort" | ||
50 | http://en.wikipedia.org/wiki/Heapsort. The combination of the two should work well | ||
51 | if the data is already partially sorted. | ||
52 | |||
53 | int fd_in The file descriptor of the input file (opened for reading and at the beginning). | ||
54 | |||
55 | int fd_out The file descriptor of the output file (opened for writing and empty). | ||
56 | |||
57 | size_t itemsize The size of each item in the file that needs sorting. | ||
58 | |||
59 | int (*compare)(const void*, const void*) The comparison function (identical to qsort if the | ||
60 | data to be sorted is an array of things not pointers). | ||
61 | |||
62 | amb | 274 | int (*buildindex)(void *,index_t) If non-NULL then this function is called for each item, if it |
63 | returns 1 then it is written to the output file. | ||
64 | amb | 269 | ++++++++++++++++++++++++++++++++++++++*/ |
65 | |||
66 | amb | 311 | void filesort_fixed(int fd_in,int fd_out,size_t itemsize,int (*compare)(const void*,const void*),int (*buildindex)(void*,index_t)) |
67 | amb | 269 | { |
68 | int *fds=NULL,*heap=NULL; | ||
69 | int nfiles=0,ndata=0; | ||
70 | index_t count=0,total=0; | ||
71 | amb | 358 | size_t nitems=option_filesort_ramsize/(itemsize+sizeof(void*)); |
72 | amb | 283 | void *data=NULL,**datap=NULL; |
73 | amb | 269 | char *filename; |
74 | int i,more=1; | ||
75 | |||
76 | /* Allocate the RAM buffer and other bits */ | ||
77 | |||
78 | data=malloc(nitems*itemsize); | ||
79 | datap=malloc(nitems*sizeof(void*)); | ||
80 | |||
81 | amb | 284 | filename=(char*)malloc(strlen(option_tmpdirname)+24); |
82 | amb | 269 | |
83 | /* Loop around, fill the buffer, sort the data and write a temporary file */ | ||
84 | |||
85 | do | ||
86 | { | ||
87 | int fd,n=0; | ||
88 | |||
89 | /* Read in the data and create pointers */ | ||
90 | |||
91 | for(i=0;i<nitems;i++) | ||
92 | { | ||
93 | datap[i]=data+i*itemsize; | ||
94 | |||
95 | if(ReadFile(fd_in,datap[i],itemsize)) | ||
96 | { | ||
97 | more=0; | ||
98 | break; | ||
99 | } | ||
100 | |||
101 | total++; | ||
102 | } | ||
103 | |||
104 | n=i; | ||
105 | |||
106 | amb | 546 | /* Shortcut if there is no data and no previous files (i.e. no data at all) */ |
107 | |||
108 | if(nfiles==0 && n==0) | ||
109 | goto tidy_and_exit; | ||
110 | |||
111 | amb | 543 | /* No new data read in this time round */ |
112 | |||
113 | amb | 269 | if(n==0) |
114 | break; | ||
115 | |||
116 | /* Sort the data pointers using a heap sort */ | ||
117 | |||
118 | amb | 503 | filesort_heapsort(datap,n,compare); |
119 | amb | 269 | |
120 | /* Shortcut if all read in and sorted at once */ | ||
121 | |||
122 | amb | 310 | if(nfiles==0 && !more) |
123 | amb | 269 | { |
124 | for(i=0;i<n;i++) | ||
125 | { | ||
126 | amb | 274 | if(!buildindex || buildindex(datap[i],count)) |
127 | { | ||
128 | WriteFile(fd_out,datap[i],itemsize); | ||
129 | count++; | ||
130 | } | ||
131 | amb | 269 | } |
132 | |||
133 | amb | 283 | goto tidy_and_exit; |
134 | amb | 269 | } |
135 | |||
136 | /* Create a temporary file and write the result */ | ||
137 | |||
138 | amb | 284 | sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,nfiles); |
139 | amb | 269 | |
140 | amb | 502 | fd=OpenFileNew(filename); |
141 | amb | 269 | |
142 | for(i=0;i<n;i++) | ||
143 | WriteFile(fd,datap[i],itemsize); | ||
144 | |||
145 | CloseFile(fd); | ||
146 | |||
147 | nfiles++; | ||
148 | } | ||
149 | while(more); | ||
150 | |||
151 | /* Shortcut if only one file (unlucky for us there must have been exactly | ||
152 | nitems, lucky for us we still have the data in RAM) */ | ||
153 | |||
154 | if(nfiles==1) | ||
155 | { | ||
156 | for(i=0;i<nitems;i++) | ||
157 | { | ||
158 | amb | 274 | if(!buildindex || buildindex(datap[i],count)) |
159 | { | ||
160 | WriteFile(fd_out,datap[i],itemsize); | ||
161 | count++; | ||
162 | } | ||
163 | amb | 269 | } |
164 | |||
165 | DeleteFile(filename); | ||
166 | |||
167 | amb | 283 | goto tidy_and_exit; |
168 | amb | 269 | } |
169 | |||
170 | /* Check that number of files is less than file size */ | ||
171 | |||
172 | assert(nfiles<nitems); | ||
173 | |||
174 | /* Open all of the temporary files */ | ||
175 | |||
176 | fds=(int*)malloc(nfiles*sizeof(int)); | ||
177 | |||
178 | for(i=0;i<nfiles;i++) | ||
179 | { | ||
180 | amb | 284 | sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,i); |
181 | amb | 269 | |
182 | fds[i]=ReOpenFile(filename); | ||
183 | |||
184 | DeleteFile(filename); | ||
185 | } | ||
186 | |||
187 | /* Perform an n-way merge using a binary heap */ | ||
188 | |||
189 | amb | 875 | heap=(int*)malloc((1+nfiles)*sizeof(int)); |
190 | amb | 269 | |
191 | /* Fill the heap to start with */ | ||
192 | |||
193 | for(i=0;i<nfiles;i++) | ||
194 | { | ||
195 | int index; | ||
196 | |||
197 | datap[i]=data+i*itemsize; | ||
198 | |||
199 | ReadFile(fds[i],datap[i],itemsize); | ||
200 | |||
201 | amb | 875 | index=i+1; |
202 | |||
203 | amb | 867 | heap[index]=i; |
204 | amb | 269 | |
205 | /* Bubble up the new value */ | ||
206 | |||
207 | amb | 875 | while(index>1) |
208 | amb | 269 | { |
209 | int newindex; | ||
210 | int temp; | ||
211 | |||
212 | amb | 875 | newindex=index/2; |
213 | amb | 269 | |
214 | amb | 869 | if(compare(datap[heap[index]],datap[heap[newindex]])>=0) |
215 | break; | ||
216 | |||
217 | amb | 269 | temp=heap[index]; |
218 | heap[index]=heap[newindex]; | ||
219 | heap[newindex]=temp; | ||
220 | |||
221 | index=newindex; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | /* Repeatedly pull out the root of the heap and refill from the same file */ | ||
226 | |||
227 | ndata=nfiles; | ||
228 | |||
229 | do | ||
230 | { | ||
231 | amb | 875 | int index=1; |
232 | amb | 269 | |
233 | amb | 867 | if(!buildindex || buildindex(datap[heap[index]],count)) |
234 | amb | 274 | { |
235 | amb | 867 | WriteFile(fd_out,datap[heap[index]],itemsize); |
236 | amb | 274 | count++; |
237 | } | ||
238 | amb | 269 | |
239 | amb | 867 | if(ReadFile(fds[heap[index]],datap[heap[index]],itemsize)) |
240 | amb | 269 | { |
241 | amb | 875 | heap[index]=heap[ndata]; |
242 | amb | 870 | ndata--; |
243 | amb | 269 | } |
244 | |||
245 | /* Bubble down the new value */ | ||
246 | |||
247 | amb | 875 | while((2*index)<ndata) |
248 | amb | 269 | { |
249 | amb | 873 | int newindex; |
250 | amb | 269 | int temp; |
251 | |||
252 | amb | 875 | newindex=2*index; |
253 | amb | 269 | |
254 | amb | 875 | if(compare(datap[heap[newindex]],datap[heap[newindex+1]])>=0) |
255 | amb | 873 | newindex=newindex+1; |
256 | amb | 869 | |
257 | if(compare(datap[heap[index]],datap[heap[newindex]])<=0) | ||
258 | break; | ||
259 | |||
260 | amb | 269 | temp=heap[newindex]; |
261 | heap[newindex]=heap[index]; | ||
262 | heap[index]=temp; | ||
263 | |||
264 | index=newindex; | ||
265 | } | ||
266 | |||
267 | amb | 875 | if((2*index)==ndata) |
268 | amb | 269 | { |
269 | int newindex; | ||
270 | int temp; | ||
271 | |||
272 | amb | 875 | newindex=2*index; |
273 | amb | 269 | |
274 | amb | 869 | if(compare(datap[heap[index]],datap[heap[newindex]])<=0) |
275 | ; /* break */ | ||
276 | else | ||
277 | { | ||
278 | temp=heap[newindex]; | ||
279 | heap[newindex]=heap[index]; | ||
280 | heap[index]=temp; | ||
281 | } | ||
282 | amb | 269 | } |
283 | } | ||
284 | while(ndata>0); | ||
285 | |||
286 | /* Tidy up */ | ||
287 | |||
288 | amb | 283 | tidy_and_exit: |
289 | amb | 269 | |
290 | amb | 283 | if(fds) |
291 | { | ||
292 | for(i=0;i<nfiles;i++) | ||
293 | CloseFile(fds[i]); | ||
294 | free(fds); | ||
295 | } | ||
296 | |||
297 | if(heap) | ||
298 | free(heap); | ||
299 | |||
300 | amb | 269 | free(data); |
301 | free(datap); | ||
302 | free(filename); | ||
303 | } | ||
304 | |||
305 | |||
306 | /*++++++++++++++++++++++++++++++++++++++ | ||
307 | amb | 310 | A function to sort the contents of a file of variable length objects (each |
308 | amb | 867 | preceded by its length in FILESORT_VARSIZE bytes) using a limited amount of RAM. |
309 | amb | 310 | |
310 | The data is sorted using a "Merge sort" http://en.wikipedia.org/wiki/Merge_sort | ||
311 | and in particular an "external sort" http://en.wikipedia.org/wiki/External_sorting. | ||
312 | The individual sort steps and the merge step both use a "Heap sort" | ||
313 | http://en.wikipedia.org/wiki/Heapsort. The combination of the two should work well | ||
314 | if the data is already partially sorted. | ||
315 | |||
316 | int fd_in The file descriptor of the input file (opened for reading and at the beginning). | ||
317 | |||
318 | int fd_out The file descriptor of the output file (opened for writing and empty). | ||
319 | |||
320 | int (*compare)(const void*, const void*) The comparison function (identical to qsort if the | ||
321 | data to be sorted is an array of things not pointers). | ||
322 | |||
323 | int (*buildindex)(void *,index_t) If non-NULL then this function is called for each item, if it | ||
324 | returns 1 then it is written to the output file. | ||
325 | ++++++++++++++++++++++++++++++++++++++*/ | ||
326 | |||
327 | amb | 311 | void filesort_vary(int fd_in,int fd_out,int (*compare)(const void*,const void*),int (*buildindex)(void*,index_t)) |
328 | amb | 310 | { |
329 | int *fds=NULL,*heap=NULL; | ||
330 | int nfiles=0,ndata=0; | ||
331 | index_t count=0,total=0; | ||
332 | amb | 311 | FILESORT_VARINT nextitemsize,largestitemsize=0; |
333 | amb | 310 | void *data=NULL,**datap=NULL; |
334 | char *filename; | ||
335 | int i,more=1; | ||
336 | |||
337 | /* Allocate the RAM buffer and other bits */ | ||
338 | |||
339 | amb | 358 | data=malloc(option_filesort_ramsize); |
340 | amb | 310 | |
341 | filename=(char*)malloc(strlen(option_tmpdirname)+24); | ||
342 | |||
343 | /* Loop around, fill the buffer, sort the data and write a temporary file */ | ||
344 | |||
345 | amb | 311 | if(ReadFile(fd_in,&nextitemsize,FILESORT_VARSIZE)) /* Always have the next item size known in advance */ |
346 | amb | 310 | goto tidy_and_exit; |
347 | |||
348 | do | ||
349 | { | ||
350 | int fd,n=0; | ||
351 | amb | 311 | size_t ramused=FILESORT_VARALIGN-FILESORT_VARSIZE; |
352 | amb | 310 | |
353 | amb | 358 | datap=data+option_filesort_ramsize; |
354 | amb | 310 | |
355 | /* Read in the data and create pointers */ | ||
356 | |||
357 | amb | 311 | while((ramused+FILESORT_VARSIZE+nextitemsize)<=((void*)datap-sizeof(void*)-data)) |
358 | amb | 310 | { |
359 | amb | 311 | FILESORT_VARINT itemsize=nextitemsize; |
360 | amb | 310 | |
361 | if(itemsize>largestitemsize) | ||
362 | largestitemsize=itemsize; | ||
363 | |||
364 | amb | 311 | *(FILESORT_VARINT*)(data+ramused)=itemsize; |
365 | amb | 310 | |
366 | amb | 311 | ramused+=FILESORT_VARSIZE; |
367 | amb | 310 | |
368 | amb | 311 | ReadFile(fd_in,data+ramused,itemsize); |
369 | amb | 310 | |
370 | amb | 311 | *--datap=data+ramused; /* points to real data */ |
371 | amb | 310 | |
372 | amb | 311 | ramused+=itemsize; |
373 | |||
374 | ramused =FILESORT_VARALIGN*((ramused+FILESORT_VARSIZE-1)/FILESORT_VARALIGN); | ||
375 | ramused+=FILESORT_VARALIGN-FILESORT_VARSIZE; | ||
376 | |||
377 | amb | 310 | total++; |
378 | n++; | ||
379 | |||
380 | amb | 311 | if(ReadFile(fd_in,&nextitemsize,FILESORT_VARSIZE)) |
381 | amb | 310 | { |
382 | more=0; | ||
383 | break; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | amb | 543 | /* No new data read in this time round */ |
388 | |||
389 | amb | 310 | if(n==0) |
390 | break; | ||
391 | |||
392 | /* Sort the data pointers using a heap sort */ | ||
393 | |||
394 | amb | 503 | filesort_heapsort(datap,n,compare); |
395 | amb | 310 | |
396 | /* Shortcut if all read in and sorted at once */ | ||
397 | |||
398 | if(nfiles==0 && !more) | ||
399 | { | ||
400 | for(i=0;i<n;i++) | ||
401 | { | ||
402 | if(!buildindex || buildindex(datap[i],count)) | ||
403 | { | ||
404 | amb | 311 | FILESORT_VARINT itemsize=*(FILESORT_VARINT*)(datap[i]-FILESORT_VARSIZE); |
405 | amb | 310 | |
406 | amb | 311 | WriteFile(fd_out,datap[i]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE); |
407 | amb | 310 | count++; |
408 | } | ||
409 | } | ||
410 | |||
411 | goto tidy_and_exit; | ||
412 | } | ||
413 | |||
414 | /* Create a temporary file and write the result */ | ||
415 | |||
416 | sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,nfiles); | ||
417 | |||
418 | amb | 502 | fd=OpenFileNew(filename); |
419 | amb | 310 | |
420 | for(i=0;i<n;i++) | ||
421 | { | ||
422 | amb | 311 | FILESORT_VARINT itemsize=*(FILESORT_VARINT*)(datap[i]-FILESORT_VARSIZE); |
423 | amb | 310 | |
424 | amb | 311 | WriteFile(fd,datap[i]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE); |
425 | amb | 310 | } |
426 | |||
427 | CloseFile(fd); | ||
428 | |||
429 | nfiles++; | ||
430 | } | ||
431 | while(more); | ||
432 | |||
433 | /* Check that number of files is less than file size */ | ||
434 | |||
435 | amb | 311 | largestitemsize=FILESORT_VARALIGN*(1+(largestitemsize+FILESORT_VARALIGN-FILESORT_VARSIZE)/FILESORT_VARALIGN); |
436 | amb | 310 | |
437 | amb | 358 | assert(nfiles<((option_filesort_ramsize-nfiles*sizeof(void*))/largestitemsize)); |
438 | amb | 310 | |
439 | /* Open all of the temporary files */ | ||
440 | |||
441 | fds=(int*)malloc(nfiles*sizeof(int)); | ||
442 | |||
443 | for(i=0;i<nfiles;i++) | ||
444 | { | ||
445 | sprintf(filename,"%s/filesort.%d.tmp",option_tmpdirname,i); | ||
446 | |||
447 | fds[i]=ReOpenFile(filename); | ||
448 | |||
449 | DeleteFile(filename); | ||
450 | } | ||
451 | |||
452 | /* Perform an n-way merge using a binary heap */ | ||
453 | |||
454 | amb | 875 | heap=(int*)malloc((1+nfiles)*sizeof(int)); |
455 | amb | 310 | |
456 | amb | 358 | datap=data+option_filesort_ramsize-nfiles*sizeof(void*); |
457 | amb | 310 | |
458 | /* Fill the heap to start with */ | ||
459 | |||
460 | for(i=0;i<nfiles;i++) | ||
461 | { | ||
462 | int index; | ||
463 | amb | 311 | FILESORT_VARINT itemsize; |
464 | amb | 310 | |
465 | amb | 311 | datap[i]=data+FILESORT_VARALIGN-FILESORT_VARSIZE+i*largestitemsize; |
466 | amb | 310 | |
467 | amb | 311 | ReadFile(fds[i],&itemsize,FILESORT_VARSIZE); |
468 | amb | 310 | |
469 | amb | 311 | *(FILESORT_VARINT*)(datap[i]-FILESORT_VARSIZE)=itemsize; |
470 | amb | 310 | |
471 | ReadFile(fds[i],datap[i],itemsize); | ||
472 | |||
473 | amb | 875 | index=i+1; |
474 | |||
475 | amb | 867 | heap[index]=i; |
476 | amb | 310 | |
477 | /* Bubble up the new value */ | ||
478 | |||
479 | amb | 875 | while(index>1) |
480 | amb | 310 | { |
481 | int newindex; | ||
482 | int temp; | ||
483 | |||
484 | amb | 875 | newindex=index/2; |
485 | amb | 310 | |
486 | amb | 869 | if(compare(datap[heap[index]],datap[heap[newindex]])>=0) |
487 | break; | ||
488 | |||
489 | amb | 310 | temp=heap[index]; |
490 | heap[index]=heap[newindex]; | ||
491 | heap[newindex]=temp; | ||
492 | |||
493 | index=newindex; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | /* Repeatedly pull out the root of the heap and refill from the same file */ | ||
498 | |||
499 | ndata=nfiles; | ||
500 | |||
501 | do | ||
502 | { | ||
503 | amb | 875 | int index=1; |
504 | amb | 311 | FILESORT_VARINT itemsize; |
505 | amb | 310 | |
506 | amb | 867 | if(!buildindex || buildindex(datap[heap[index]],count)) |
507 | amb | 310 | { |
508 | amb | 867 | itemsize=*(FILESORT_VARINT*)(datap[heap[index]]-FILESORT_VARSIZE); |
509 | amb | 310 | |
510 | amb | 867 | WriteFile(fd_out,datap[heap[index]]-FILESORT_VARSIZE,itemsize+FILESORT_VARSIZE); |
511 | amb | 310 | count++; |
512 | } | ||
513 | |||
514 | amb | 867 | if(ReadFile(fds[heap[index]],&itemsize,FILESORT_VARSIZE)) |
515 | amb | 310 | { |
516 | amb | 875 | heap[index]=heap[ndata]; |
517 | amb | 870 | ndata--; |
518 | amb | 310 | } |
519 | else | ||
520 | { | ||
521 | amb | 867 | *(FILESORT_VARINT*)(datap[heap[index]]-FILESORT_VARSIZE)=itemsize; |
522 | amb | 310 | |
523 | amb | 867 | ReadFile(fds[heap[index]],datap[heap[index]],itemsize); |
524 | amb | 310 | } |
525 | |||
526 | /* Bubble down the new value */ | ||
527 | |||
528 | amb | 875 | while((2*index)<ndata) |
529 | amb | 310 | { |
530 | amb | 873 | int newindex; |
531 | amb | 310 | int temp; |
532 | |||
533 | amb | 875 | newindex=2*index; |
534 | amb | 310 | |
535 | amb | 875 | if(compare(datap[heap[newindex]],datap[heap[newindex+1]])>=0) |
536 | amb | 873 | newindex=newindex+1; |
537 | amb | 869 | |
538 | if(compare(datap[heap[index]],datap[heap[newindex]])<=0) | ||
539 | break; | ||
540 | |||
541 | amb | 310 | temp=heap[newindex]; |
542 | heap[newindex]=heap[index]; | ||
543 | heap[index]=temp; | ||
544 | |||
545 | index=newindex; | ||
546 | } | ||
547 | |||
548 | amb | 875 | if((2*index)==ndata) |
549 | amb | 310 | { |
550 | int newindex; | ||
551 | int temp; | ||
552 | |||
553 | amb | 875 | newindex=2*index; |
554 | amb | 310 | |
555 | amb | 869 | if(compare(datap[heap[index]],datap[heap[newindex]])<=0) |
556 | ; /* break */ | ||
557 | else | ||
558 | { | ||
559 | temp=heap[newindex]; | ||
560 | heap[newindex]=heap[index]; | ||
561 | heap[index]=temp; | ||
562 | } | ||
563 | amb | 310 | } |
564 | } | ||
565 | while(ndata>0); | ||
566 | |||
567 | /* Tidy up */ | ||
568 | |||
569 | tidy_and_exit: | ||
570 | |||
571 | if(fds) | ||
572 | { | ||
573 | for(i=0;i<nfiles;i++) | ||
574 | CloseFile(fds[i]); | ||
575 | free(fds); | ||
576 | } | ||
577 | |||
578 | if(heap) | ||
579 | free(heap); | ||
580 | |||
581 | free(data); | ||
582 | free(filename); | ||
583 | } | ||
584 | |||
585 | |||
586 | /*++++++++++++++++++++++++++++++++++++++ | ||
587 | amb | 269 | A function to sort an array of pointers efficiently. |
588 | |||
589 | The data is sorted using a "Heap sort" http://en.wikipedia.org/wiki/Heapsort, | ||
590 | amb | 873 | in particular, this is good because it can operate in-place and doesn't |
591 | amb | 269 | allocate more memory like using qsort() does. |
592 | |||
593 | void **datap A pointer to the array of pointers to sort. | ||
594 | |||
595 | size_t nitems The number of items of data to sort. | ||
596 | |||
597 | int(*compare)(const void *, const void *) The comparison function (identical to qsort if the | ||
598 | data to be sorted was an array of things not pointers). | ||
599 | ++++++++++++++++++++++++++++++++++++++*/ | ||
600 | |||
601 | amb | 503 | void filesort_heapsort(void **datap,size_t nitems,int(*compare)(const void*, const void*)) |
602 | amb | 269 | { |
603 | amb | 875 | void **datap1=&datap[-1]; |
604 | amb | 269 | int i; |
605 | |||
606 | /* Fill the heap by pretending to insert the data that is already there */ | ||
607 | |||
608 | amb | 875 | for(i=2;i<=nitems;i++) |
609 | amb | 269 | { |
610 | int index=i; | ||
611 | |||
612 | /* Bubble up the new value (upside-down, put largest at top) */ | ||
613 | |||
614 | amb | 875 | while(index>1) |
615 | amb | 269 | { |
616 | int newindex; | ||
617 | void *temp; | ||
618 | |||
619 | amb | 875 | newindex=index/2; |
620 | amb | 269 | |
621 | amb | 875 | if(compare(datap1[index],datap1[newindex])<=0) /* reversed compared to filesort_fixed() above */ |
622 | amb | 869 | break; |
623 | |||
624 | amb | 875 | temp=datap1[index]; |
625 | datap1[index]=datap1[newindex]; | ||
626 | datap1[newindex]=temp; | ||
627 | amb | 269 | |
628 | index=newindex; | ||
629 | } | ||
630 | } | ||
631 | |||
632 | /* Repeatedly pull out the root of the heap and swap with the bottom item */ | ||
633 | |||
634 | amb | 875 | for(i=nitems;i>1;i--) |
635 | amb | 269 | { |
636 | amb | 875 | int index=1; |
637 | amb | 269 | void *temp; |
638 | |||
639 | amb | 875 | temp=datap1[index]; |
640 | datap1[index]=datap1[i]; | ||
641 | datap1[i]=temp; | ||
642 | amb | 269 | |
643 | /* Bubble down the new value (upside-down, put largest at top) */ | ||
644 | |||
645 | amb | 875 | while((2*index)<(i-1)) |
646 | amb | 269 | { |
647 | amb | 873 | int newindex; |
648 | amb | 269 | void *temp; |
649 | |||
650 | amb | 875 | newindex=2*index; |
651 | amb | 269 | |
652 | amb | 875 | if(compare(datap1[newindex],datap1[newindex+1])<=0) /* reversed compared to filesort_fixed() above */ |
653 | amb | 873 | newindex=newindex+1; |
654 | amb | 869 | |
655 | amb | 875 | if(compare(datap1[index],datap1[newindex])>=0) /* reversed compared to filesort_fixed() above */ |
656 | amb | 869 | break; |
657 | |||
658 | amb | 875 | temp=datap1[newindex]; |
659 | datap1[newindex]=datap1[index]; | ||
660 | datap1[index]=temp; | ||
661 | amb | 269 | |
662 | index=newindex; | ||
663 | } | ||
664 | |||
665 | amb | 875 | if((2*index)==(i-1)) |
666 | amb | 269 | { |
667 | int newindex; | ||
668 | void *temp; | ||
669 | |||
670 | amb | 875 | newindex=2*index; |
671 | amb | 269 | |
672 | amb | 875 | if(compare(datap1[index],datap1[newindex])>=0) /* reversed compared to filesort_fixed() above */ |
673 | amb | 869 | ; /* break */ |
674 | else | ||
675 | { | ||
676 | amb | 875 | temp=datap1[newindex]; |
677 | datap1[newindex]=datap1[index]; | ||
678 | datap1[index]=temp; | ||
679 | amb | 869 | } |
680 | amb | 269 | } |
681 | } | ||
682 | } |
Properties
Name | Value |
---|---|
cvs:description | Functions to perform sorting. |