-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsortable.c
176 lines (144 loc) · 4.78 KB
/
sortable.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* ========================================================================== */
/* */
/* Experimental inline version of a Divide & Conquer type sort algorihm */
/* Support: Garden Sylvain [email protected] */
/* */
/* Description: */
/* This code aims a O(n) complexity when the to-be-ordered list is the */
/* concatenation of y (y << n) median-sized sub-lists. */
/* There are a lot of applicative case. */
/* ========================================================================== */
#include <stdlib.h>
#include "sortable.h"
#include "quickheap.h"
// A Heap for lists
static QuickHeapS listHeapS = QuickHeapInitializerFor(struct sList) ;
static QuickHeap listHeap = &listHeapS ;
// A settable function to compare lists. Please set it before sorting!
// must return (arg1 < arg2)
int (*ListDataPrior)(void *, void *) = NULL ;
// create a list item
List ListNew() {
//QuickHeapReserve(listHeap, 2048); // This will work only once. That's fine.
return (List)QuickHeapAlloc(listHeap) ;
}
// free a list item and return next
List ListFree(List p) {
List next = p->next ;
QuickHeapFree(listHeap, (void *)p) ;
return next ;
}
// merge 2 lists
// sort direction is kept by altering links in place
List ListMerge(List previous, List after) {
List head, last, tmp ;
if (!previous && !after) return NULL ;
if (!previous || (after && ListPrior(after, previous)))
{ // 1st swapping of after & previous lists
tmp = previous ;
previous = after ;
after = tmp ;
}
head = last = previous ;
previous = ListNext(last) ;
while (previous && after)
{
if (ListPrior(after, previous))
{
// swap after & previous lists // xor swap?
tmp = previous ;
previous = after ;
after = tmp ;
// correct link to previous
ListSetNext(last, previous) ;
}
last = previous ;
previous = ListNext(last) ;
}
if (after)
ListSetNext(last, after) ;
return head ;
}
// cut list at end of the first rise, and returns the next rise
List ListGetNextRise(List list) {
List last, l ;
if (!list) return NULL ;
// sorting break search loop
for (last = l = list, l = ListNext(l) ;
l && !ListPrior(l, last) ;
last = l, l = ListNext(l)) ;
// cut l at ordering break
if (l) ListSetNext(last, NULL) ;
return l ;
}
// look for n=2^level consecutive rises in a list
// and merge them each others according to a binary tree scheme
// in 'list' : a list
// in 'level' : binary tree size
// returns: the ordered sub-list
// out 'remaining' : the remaining unordered part of the list
static List down(List list, int level, List *remaining) {
List sub_remaining, l1, l2 ;
if (!list)
{
*remaining = NULL ;
return NULL ;
}
if (!level)
{
*remaining = ListGetNextRise(list) ;
return list ;
}
l1 = down(list, level-1, &sub_remaining) ;
l2 = down(sub_remaining, level-1, remaining) ;
return ListMerge(l1, l2) ;
}
// repeat until exhaustion of the unordered part of the list :
// merge-sort a part of list of same weight than the already ordered list
// then merge both as a weight+1 ordered list
List inlineDivideAndConquerSort(List list) {
List done = NULL, remaining, ordered ;
int level = 0 ;
if (!list) return NULL ;
done = list ;
list = ListGetNextRise(list) ;
while (list) {
ordered = down(list, level, &remaining) ;
done = ListMerge(done, ordered) ;
level++ ;
list = remaining ;
}
return done ;
}
// compile the test exe with "gcc -Dtest foo.c -o test"
#ifdef TEST
#include <stdio.h>
int intDataPrior(void *a, void *b) {
return ((int)a) >= ((int b)) ;
}
void main()
{
List demo = NULL, orderedList ;
ListSetDataPrior(intDataPrior) ;
// create a random list of integers
for (int i = 0 ; i < 1000 ; i++) {
List n = ListNew() ;
ListSetNext(n, demo) ;
{
int* ip = malloc(int) ;
*ip = (int)random(10000) ;
ListSetData(n, ip) ;
}
demo = n ;
}
orderedList = inlineDivideAndConquerSort(demo) ;
for (List p = orderedList ; p ; p = ListNext(p) ) {
printf("%d\t", *((int *)ListData(p)) ;
}
printf("\n") ;
while (orderedList) {
free(ListData(orderedList)) ;
orderedList = ListFree(orderedList) ;
}
}
#endif // TEST