aboutsummaryrefslogtreecommitdiff
path: root/dlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'dlist.c')
-rw-r--r--dlist.c539
1 files changed, 539 insertions, 0 deletions
diff --git a/dlist.c b/dlist.c
new file mode 100644
index 0000000..140d3a3
--- /dev/null
+++ b/dlist.c
@@ -0,0 +1,539 @@
1/* dlist -- double linked list */
2
3/* Standard C */
4#include <stdio.h>
5#include <stdlib.h>
6#include <stdbool.h>
7#include <assert.h>
8#include <time.h>
9
10/* Project */
11#include "util.h"
12
13typedef int T;
14
15struct dlist {
16 struct dlist_element *head, *tail;
17};
18
19struct dlist_element {
20 struct dlist_element *prev, *next;
21 T data;
22};
23
24void
25dlist_init(struct dlist *dlist)
26{
27 dlist->head = NULL;
28 dlist->tail = NULL;
29}
30
31static struct dlist_element *
32create_element(T data)
33{
34 struct dlist_element *element;
35
36 element = malloc(sizeof *element);
37 if ( element != NULL ) {
38 element->data = data;
39 }
40
41 return element;
42}
43
44struct dlist_element *
45dlist_push_front(struct dlist *dlist, T data)
46{
47 struct dlist_element *element;
48
49 element = create_element(data);
50 if ( element != NULL ) {
51 element->prev = NULL; /* Vorgänger ist in jedem Fall NULL */
52
53 if ( dlist->head == NULL ) { /* empty list */
54 element->next = NULL;
55 dlist->tail = element;
56 }
57 else { /* non empty list */
58 element->next = dlist->head;
59 element->next->prev = element;
60 }
61
62 dlist->head = element; /* Neues Element ist in jedem Fall der neue Anfang! */
63 }
64 else
65 ERROR("out of memory");
66
67 return element;
68}
69
70struct dlist_element *
71dlist_push_back(struct dlist *dlist, T data)
72{
73 struct dlist_element *element;
74
75 element = create_element(data);
76 if ( element != NULL ) {
77 element->next = NULL; /* Nachfolger ist in jedem Fall NULL */
78
79 if ( dlist->head == NULL ) { /* empty list */
80 element->prev = NULL;
81 dlist->head = element;
82 }
83 else { /* non empty list */
84 element->prev = dlist->tail;
85 element->prev->next = element;
86 }
87
88 dlist->tail = element; /* Neues Element ist in jedem Fall das neue Ende! */
89 }
90 else
91 ERROR("out of memory");
92
93 return element;
94}
95
96bool
97dlist_pop_front(struct dlist *dlist, T *data)
98{
99 if ( dlist->head != NULL ) {
100 struct dlist_element *element = dlist->head;
101
102 dlist->head = element->next;
103
104 if ( dlist->head == NULL )
105 dlist->tail = NULL;
106 else
107 element->next->prev = NULL;
108
109 *data = element->data;
110 free(element);
111
112 return true;
113 }
114 else
115 return false;
116}
117
118bool
119dlist_pop_back(struct dlist *dlist, T *data)
120{
121 if ( dlist->head != NULL ) {
122 struct dlist_element *element = dlist->tail;
123
124 dlist->tail = element->prev;
125
126 if ( dlist->tail == NULL )
127 dlist->head = NULL;
128 else
129 element->prev->next = NULL;
130
131 *data = element->data;
132 free(element);
133
134 return true;
135 }
136 else
137 return false;
138}
139
140struct dlist_element *
141dlist_insert_next(struct dlist *dlist, struct dlist_element *element, T data)
142{
143 struct dlist_element *new_element;
144
145 new_element = create_element(data);
146 if ( new_element != NULL ) {
147 if ( dlist->head == NULL ) {
148 dlist->head = new_element;
149 dlist->head->prev = NULL;
150 dlist->head->next = NULL;
151 dlist->tail = new_element;
152 }
153 else {
154 new_element->next = element->next;
155 new_element->prev = element;
156
157 if ( element->next == NULL )
158 dlist->tail = new_element;
159 else
160 element->next->prev = new_element;
161
162 element->next = new_element;
163 }
164 }
165 else
166 ERROR("out of memory");
167
168 return new_element;
169}
170
171struct dlist_element *
172dlist_insert_prev(struct dlist *dlist, struct dlist_element *element, T data)
173{
174 struct dlist_element *new_element;
175
176 new_element = create_element(data);
177 if ( new_element != NULL ) {
178 if ( dlist->head == NULL ) {
179 dlist->head = new_element;
180 dlist->head->prev = NULL;
181 dlist->head->next = NULL;
182 dlist->tail = new_element;
183 }
184 else {
185 new_element->next = element;
186 new_element->prev = element->prev;
187
188 if ( element->prev == NULL )
189 dlist->head = new_element;
190 else
191 element->prev->next = new_element;
192
193 element->prev = new_element;
194 }
195 }
196 else
197 ERROR("out of memory");
198
199 return new_element;
200}
201
202void
203dlist_remove(struct dlist *dlist, struct dlist_element *element)
204{
205 if ( element == dlist->head ) {
206 dlist->head = element->next;
207
208 if ( dlist->head == NULL )
209 dlist->tail = NULL;
210 else
211 element->next->prev = NULL;
212 }
213 else {
214 element->prev->next = element->next;
215
216 if ( element->next == NULL )
217 dlist->tail = element->prev;
218 else
219 element->next->prev = element->prev;
220 }
221
222 free(element);
223}
224
225void
226dlist_free(struct dlist *dlist)
227{
228 struct dlist_element *elem, *next;
229
230 for ( elem = dlist->head; elem; elem = next ) {
231 next = elem->next;
232 free(elem);
233 }
234
235 dlist_init(dlist);
236}
237
238void
239dlist_apply_rev(struct dlist *dlist, void (*visit)(T data, void *cl), void *cl)
240{
241 for ( struct dlist_element *elem = dlist->tail; elem; elem = elem->prev )
242 visit(elem->data, cl);
243}
244
245void
246print_list(const char *msg, struct dlist *dlist)
247{
248 printf("%s:", msg);
249
250 for ( struct dlist_element *elem = dlist->head; elem; elem = elem->next )
251 printf(" %d", elem->data);
252
253 putchar('\n');
254}
255
256void
257print_list_rev(const char *msg, struct dlist *dlist)
258{
259 printf("%s:", msg);
260
261 for ( struct dlist_element *elem = dlist->tail; elem; elem = elem->prev )
262 printf(" %d", elem->data);
263
264 putchar('\n');
265}
266
267void
268remove_if(struct dlist *list)
269{
270 struct dlist_element *elem, *next;
271
272 for ( elem = list->head; elem; elem = next ) {
273 next = elem->next;
274
275 if ( (elem->data & 1) == 1 )
276 dlist_remove(list, elem);
277 }
278}
279
280void
281dlist_sort_xxx(struct dlist *list)
282{
283 if ( list->head == NULL )
284 return;
285
286 int insize = 1;
287
288 while (1) {
289 struct dlist_element *p;
290
291 p = list->head;
292 list->head = NULL;
293 list->tail = NULL;
294
295 int nmerges = 0; /* count number of merges we do in this pass */
296
297 while (p) {
298
299 struct dlist_element *q;
300
301 nmerges++; /* there exists a merge to be done */
302 /* step `insize' places along from p */
303 q = p;
304 int psize = 0;
305 for (int i = 0; i < insize; i++) {
306 psize++;
307 q = q->next;
308 if (!q) break;
309 }
310
311 /* if q hasn't fallen off end, we have two lists to merge */
312 int qsize = insize;
313
314 /* now we have two lists; merge them */
315 while (psize > 0 || (qsize > 0 && q)) {
316
317 struct dlist_element *e;
318
319 /* decide whether next element of merge comes from p or q */
320 if (psize == 0) {
321 /* p is empty; e must come from q. */
322 e = q; q = q->next; qsize--;
323 } else if (qsize == 0 || !q) {
324 /* q is empty; e must come from p. */
325 e = p; p = p->next; psize--;
326 } else if (p->data < q->data) {
327 /* First element of p is lower ;
328 * e must come from p. */
329 e = p; p = p->next; psize--;
330 } else {
331 /* First element of q is lower; e must come from q. */
332 e = q; q = q->next; qsize--;
333 }
334
335 /* add the next element to the merged list */
336 if (list->tail) {
337 list->tail->next = e;
338 } else {
339 list->head = e;
340 }
341 e->prev = list->tail;
342 list->tail = e;
343 }
344
345 /* now p has stepped `insize' places along, and q has too */
346 p = q;
347 }
348 list->tail->next = NULL;
349
350 /* If we have done only one merge, we're finished. */
351 if (nmerges <= 1) /* allow for nmerges==0, the empty list case */
352 return; // list;
353
354 /* Otherwise repeat, merging lists twice the size */
355 insize *= 2;
356 }
357}
358
359struct dlist *
360dlist_merge(struct dlist *list1, struct dlist *list2)
361{
362 struct dlist_element *head = NULL,
363 *cur = NULL,
364 *e1 = list1->head,
365 *e2 = list2->head;
366
367 while ( e1 != NULL && e2 != NULL ) // Solange in e1 UND e2 Elemente sind...
368 {
369 if ( e1->data < e2->data )
370 {
371 e1->prev = cur;
372 if ( cur != NULL )
373 cur->next = e1;
374 else
375 head = e1;
376 cur = e1;
377 e1 = e1->next;
378 }
379 else
380 {
381 e2->prev = cur;
382 if ( cur != NULL )
383 cur->next = e2;
384 else
385 head = e2;
386 cur = e2;
387 e2 = e2->next;
388 }
389 }
390
391 if ( e1 != NULL ) // in e1 sind noch Elemente vorhanden!
392 {
393 assert(e2 == NULL);
394
395 e1->prev = cur;
396 if ( cur != NULL )
397 cur->next = e1;
398 else
399 head = e1;
400
401 // list1->tail zeigt bereits auf das letzte Element in list1
402 }
403 else /* if ( e2 != NULL ) */
404 {
405 assert(e1 == NULL);
406 assert(e2 != NULL);
407
408 e2->prev = cur;
409 if ( cur != NULL )
410 cur->next = e2;
411 else
412 head = e2;
413
414 list1->tail = list2->tail; // list2->tail ist das Ende der Liste
415 }
416
417 // Kopf neu setzen...
418 list1->head = head;
419
420 // Liste2 ist leer
421 list2->head = NULL;
422 list2->tail = NULL;
423
424 // Zeiger auf Liste1 zurückliefern
425 return list1;
426}
427
428struct dlist *
429dlist_sort(struct dlist *list)
430{
431 if ( list->head == NULL || list->head->next == NULL ) // Leer oder nur ein Element? => Fertig
432 return list;
433
434 struct dlist_element *slow = list->head,
435 *fast = list->head->next;
436
437 while ( fast != NULL && fast->next != NULL )
438 slow = slow->next, fast = fast->next->next;
439
440 struct dlist list1 = { .head = list->head, .tail = slow },
441 list2 = { .head = slow->next, .tail = list->tail };
442
443 list1.tail->next = list2.head->prev = NULL;
444
445 dlist_merge(dlist_sort(&list1), dlist_sort(&list2));
446
447 list->head = list1.head;
448 list->tail = list1.tail;
449
450 return list;
451}
452
453void merge_test(void)
454{
455 struct dlist l1, l2;
456
457 dlist_init(&l1);
458 dlist_init(&l2);
459
460 dlist_push_back(&l1, 7);
461 dlist_push_back(&l1, 10);
462 dlist_push_back(&l1, 11);
463 dlist_push_back(&l1, 19);
464 dlist_push_back(&l1, 23);
465
466 dlist_push_back(&l2, 4);
467 dlist_push_back(&l2, 14);
468 dlist_push_back(&l2, 15);
469
470 struct dlist *ptr;
471 ptr = dlist_merge(&l1, &l2);
472
473 struct dlist_element *cur;
474 for ( cur = ptr->head; cur; cur = cur->next ) {
475 if ( cur->prev ) printf("%4d", cur->prev->data); else printf("xxx ");
476 printf("%4d", cur->data);
477 if ( cur->next ) printf("%4d", cur->next->data); else printf(" xxx");
478
479 puts("");
480 }
481
482 dlist_free(&l1);
483 dlist_free(&l2);
484}
485
486void ls()
487{
488 struct dlist list;
489
490 dlist_init(&list);
491
492 for ( int i = 0; i != 30000000; ++i )
493 dlist_insert_prev(&list, list.tail, rand() % 9999);
494
495 //print_list("Unsortiert:", &list);
496 printf("start\n");
497 clock_t start = clock();
498 dlist_sort(&list);
499 clock_t ende = clock();
500
501 printf("Dauer: %.3fsec\n", ((double) ende-start)/CLOCKS_PER_SEC);
502 //print_list("Sortiert:", &list);
503 //print_list_rev("Sortiert:", &list);
504
505 dlist_free(&list);
506}
507
508
509int
510main(void)
511{
512 ls();
513
514#if 0
515 merge_test();
516#endif
517
518#if 0
519 struct dlist list;
520
521 dlist_init(&list);
522
523 for ( int i = 0; i != 10; ++i )
524 dlist_insert_prev(&list, list.tail, i);
525
526 print_list("Ausgabe: ", &list);
527
528 remove_if(&list);
529
530 print_list("Ausgabe: ", &list);
531
532 dlist_free(&list);
533
534 ls();
535
536 return EXIT_SUCCESS;
537#endif
538}
539