|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 5383 (0x1507) Types: TextFile Names: »crack-sort.c«
└─⟦4f9d7c866⟧ Bits:30007245 EUUGD6: Sikkerheds distributionen └─⟦this⟧ »./crack/Sources/crack-sort.c«
#include "crack.h" #define Compare(a,b) (strcmp(a,b)) /* * Sort a list of struct DICT by using an iterative bottom-up merge sort. * This particular piece of code took me ages to do (well, 2 days + 3 weeks * research) and provides a FAST way of sorting a linked list without the * overhead of increasing memory usage via malloc() or brk(). Why ? Because I * have to assume that there is no more memory, thats why. It's all Brian * Thompsett's fault! Really! Filling the swapspace on a SparcStation2 and * expecting Crack to survive! Argh! 8-) */ /* Since this code is so nice, I'll comment it fairly thoroughly */ struct DICT * SortDict (chain3, listlength) register struct DICT *chain3; long int listlength; { /* misc counters */ register int i; long int discarded; /* 2^n for n = 0..x */ long int n; /* head of the first extracted subchain */ register struct DICT *chain1; /* head of second subchain */ register struct DICT *chain2; /* useful temp pointer */ register struct DICT *scratch; /* PTR TO ELEMENT containing TAIL of unsorted list pre-merging */ struct DICT *lead_in; /* PTR TO HEAD of unsorted list after extracting chains */ struct DICT *lead_out; /* dummy structures used as fenceposts */ struct DICT dummy1; struct DICT dummy2; /* Put the incoming list into 'dummy1' posthole */ dummy1.next = chain3; /* For values of n = 2^(0..30) limited by listlength */ for (n = 1L; n < listlength; n *= 2) { /* Store place to get/put head of list in 'lead_in' */ lead_in = &dummy1; /* Set chain1 to the head of unsorted list */ for (chain1 = lead_in -> next; chain1; chain1 = lead_in -> next) { /* Break connection head and chain1 */ lead_in -> next = (struct DICT *) 0; /* Extract up to length 'n', park on last element before chain2 */ for (i = n - 1, scratch = chain1; i && scratch -> next; scratch = scratch -> next) { i--; }; /* If chain1 is undersized/exact, there is no chain2 */ if (i || !scratch -> next) { /* put chain1 back where you got it and break */ lead_in -> next = chain1; break; } /* Get pointer to head of chain2 */ chain2 = scratch -> next; /* Break connection between chain1 & chain2 */ scratch -> next = (struct DICT *) 0; /* Extract up to length 'n', park on last element of chain2 */ for (i = n - 1, scratch = chain2; i && scratch -> next; scratch = scratch -> next) { i--; }; /* Even if it's NULL, store rest of list in 'lead_out' */ lead_out = scratch -> next; /* Break connection between chain2 & tail of unsorted list */ scratch -> next = (struct DICT *) 0; /* Now, mergesort chain1 & chain2 to chain3 */ /* Set up dummy list fencepost */ chain3 = &dummy2; chain3 -> next = (struct DICT *) 0; /* While there is something in each list */ while (chain1 && chain2) { /* Compare them */ i = Compare (chain1 -> word, chain2 -> word); if (i < 0) { /* a < b */ chain3 -> next = chain1; chain3 = chain1; chain1 = chain1 -> next; } else if (i > 0) { /* a > b */ chain3 -> next = chain2; chain3 = chain2; chain2 = chain2 -> next; } else { /* * a == b. Link them both in. Don't try to get rid of the * multiple copies here, because if you free up any * elements at this point the listsize changes and the * algorithm runs amok. */ chain3 -> next = chain1; chain3 = chain1; chain1 = chain1 -> next; chain3 -> next = chain2; chain3 = chain2; chain2 = chain2 -> next; } } /* * Whatever is left is sorted and therefore linkable straight * onto the end of the current list. */ if (chain1) { chain3 -> next = chain1; } else { chain3 -> next = chain2; } /* Skip to the end of the sorted list */ while (chain3 -> next) { chain3 = chain3 -> next; } /* Append this lot to where you got chain1 from ('lead_in') */ lead_in -> next = dummy2.next; /* Append rest of unsorted list to chain3 */ chain3 -> next = lead_out; /* Set 'lead_in' for next time to last element of 'chain3' */ lead_in = chain3; } } /* Now, Uniq the list */ discarded = 0; /* Chain1 to the head of the list, Chain2 to the next */ chain1 = dummy1.next; chain2 = chain1 -> next; /* While not at end of list */ while (chain2) { /* Whilst (chain1) == (chain2) */ while (!Compare (chain1 -> word, chain2 -> word)) { /* Bump the discard count */ discarded++; /* Store the next element */ scratch = chain2 -> next; /* Get some memory back */ free (chain2); /* ...<snigger>... */ /* Assign the skip, break if you run off the end of list */ if (!(chain2 = scratch)) { break; } } /* Set comparison ptr to new element or terminate */ chain1 -> next = chain2; /* If not terminated */ if (chain2) { /* set the compared pointer to its successor */ chain1 = chain2; chain2 = chain2 -> next; } } Log ("Sort discarded %ld words; FINAL DICTIONARY SIZE: %ld\n", discarded, listlength - discarded); return (dummy1.next); }