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