1 | /** \file mergesort2.c
|
---|
2 | * MergeSort implementation.
|
---|
3 | * Unbeknownst that C already chooses the best algorithim according to the
|
---|
4 | * problem at hand, a mergesort algorithm was implemented by naturalmergesort(),
|
---|
5 | * which does the sorting, and merge() which joins two sorted pieces in an array
|
---|
6 | * together.
|
---|
7 | *
|
---|
8 | Project: CP
|
---|
9 | \author Jan Hamaekers
|
---|
10 | \date 2000
|
---|
11 |
|
---|
12 | $Id: mergesort2.c,v 1.10 2006/12/05 18:11:16 foo Exp $
|
---|
13 |
|
---|
14 | File: mergesort2.c
|
---|
15 | Usage:
|
---|
16 | Insert in your Code
|
---|
17 | \verbatim
|
---|
18 | #include"mergesort2.h"
|
---|
19 | double GetKey(void *Element, int i) { }
|
---|
20 | void CopyElement(void *Element, int i, void *Element, int j)
|
---|
21 | \endverbatim
|
---|
22 | Use:
|
---|
23 | naturalmergesort(a,b,l,r,&GetKey,&CopyElement)
|
---|
24 | struct Element* a, *b b als Puffer Speicher reservieren !!!
|
---|
25 | int l,r
|
---|
26 |
|
---|
27 | */
|
---|
28 |
|
---|
29 | #include<stdlib.h>
|
---|
30 | #include "mergesort2.h"
|
---|
31 |
|
---|
32 | /** Merge two sorted sequences a[l]-a[m] and a[m+1]-a[r] -> a[l]-a[r].
|
---|
33 | * Goes in both sequences through all elements, at every one step comparing the two by GetKey
|
---|
34 | * and copying the lower one. Eventually, the rest of the remaining sequence is copied (into
|
---|
35 | * the dummyarray). And dummyarray back to original one.
|
---|
36 | * \param *a array containging both sequences that is to be sorted
|
---|
37 | * \param l start of first sequence
|
---|
38 | * \param m end of first sequence, also one before start of second sequence
|
---|
39 | * \param r end of second sequence
|
---|
40 | * \param *b dummyarray (used for copying hither and thither, size b = r-l+1)
|
---|
41 | * \param (*GetKey)(void *, int i, void *) pointer to function that decides whether a[i] is "bigger" than a[j]
|
---|
42 | * \param *Args additional arguments for *GetKey function, passed to it on calling
|
---|
43 | * \param (*CopyElement)(void *, int i, void *, int j) pointer to function, copying element b[j] to a[i]
|
---|
44 | */
|
---|
45 | static void merge(void *a, int l, int m, int r, void *b, double (*GetKey)(void *, int i, void *), void *Args, void (*CopyElement)(void *, int i, void *, int j)) {
|
---|
46 | int h,i=l,j=m+1,k=l; // i,j start at their respective sequences
|
---|
47 | while (i <= m && j <= r) { // elements are copied from both parts (a[l..m] and a[m+1..r]) in order into dummyarray b[l..r]
|
---|
48 | if (GetKey(a,i,Args) <= GetKey(a,j,Args)) {
|
---|
49 | CopyElement(b, k, a, i);
|
---|
50 | i++;
|
---|
51 | } else {
|
---|
52 | CopyElement(b, k, a, j);
|
---|
53 | j++;
|
---|
54 | }
|
---|
55 | k++;
|
---|
56 | }
|
---|
57 | if (i > m) { // if in one of the sequences there yet remain some elements, copy them (simple for loop)
|
---|
58 | for (h=j; h <=r;h++) CopyElement(b, k+h-j, a, h);
|
---|
59 | } else {
|
---|
60 | for (h=i; h <=m;h++) CopyElement(b, k+h-i, a, h);
|
---|
61 | } // finally copy elements back to a
|
---|
62 | for (h=l; h <= r; h++) CopyElement(a, h, b, h);
|
---|
63 | }
|
---|
64 |
|
---|
65 | /** Mergesort an array /a a[l,-,r].
|
---|
66 | * By a divide-and-conquer strategy an array is sorted: Seek first ordered sequence, mark, seek
|
---|
67 | * from thereon second order sequence, mark, merge these, until end and then begin again until
|
---|
68 | * sorted. Note, that thus already present ordered partial sequences are looked for and used.
|
---|
69 | * \param *a array to be sorted
|
---|
70 | * \param l start of to-be-sorted sequence in /a a
|
---|
71 | * \param r end of to-be-sorted sequence in /a a
|
---|
72 | * \param *b dummyarray (size b = r-l+1)
|
---|
73 | * \param (*GetKey)(void *, int i, void *) pointer to function that decides whether a[i] is "bigger" than a[j]
|
---|
74 | * \param *Args additional arguments for *GetKey function, passed to it on calling
|
---|
75 | * \param (*CopyElement)(void *, int i, void *, int j) pointer to function, copying element b[j] to a[i]
|
---|
76 | * \note Should be replaced by C's own qsort-routine, that's always optimal.
|
---|
77 | * \sa merge()
|
---|
78 | */
|
---|
79 | void naturalmergesort(void *a, void *b, int l, int r, double (*GetKey)(void *, int i, void *), void *Args, void (*CopyElement)(void *, int i, void *, int j)) {
|
---|
80 | /* C_min = O(N)
|
---|
81 | C_max = O(N)
|
---|
82 | */
|
---|
83 | int ll=0, mm=0, rr=0;
|
---|
84 | do {
|
---|
85 | rr = l-1;
|
---|
86 | while (rr < r) {
|
---|
87 | ll = rr+1;
|
---|
88 | mm = ll;
|
---|
89 | while (mm < r && GetKey(a, mm+1, Args) >= GetKey(a, mm, Args)) mm++; // mm is increased until a lower element is found
|
---|
90 | if (mm < r) { // was whole sequence in order already?
|
---|
91 | rr = mm+1; // mm
|
---|
92 | while (rr<r && GetKey(a, rr+1, Args) >= GetKey(a, rr, Args)) rr++; // from mm on rr is increased until a lower element is found
|
---|
93 | merge(a,ll,mm,rr,b,GetKey,Args,CopyElement); // merge these two ordered sequences: a[ll..mm], a[mm+1..rr]
|
---|
94 | } else { // ... we are finished!
|
---|
95 | rr = mm;
|
---|
96 | }
|
---|
97 | }
|
---|
98 | } while (ll != l);
|
---|
99 | }
|
---|