Slashdot Mirror


Sort Linked Lists 10X Faster Than MergeSort

virusfree tells us about a new algorithm that has been developed that the author claims can sort a linked list up to 10 times faster than MergeSort. "BitFast," a member of the Hash algorithms family, is available in C and C++ under the GPL.

73 of 326 comments (clear)

  1. How is this not a radix sort? by Anonymous Coward · · Score: 5, Informative
    1. Re:How is this not a radix sort? by Sillygates · · Score: 4, Funny

      My favorite is still: http://www.dangermouse.net/esoteric/intelligentdes ignsort.html

      Sorts in O(1) and uses no memory!

      --
      I fear the Y2038 bug
    2. Re:How is this not a radix sort? by acidrain · · Score: 4, Informative

      This algorithm is exactly how my first year comp-sci teacher taught radix sort. I'm guessing "VirusFree" stole his lecture notes.

      It's actually much cheaper to use arrays of indices or arrays of pointers internally instead of linked list operations, but "BitFast" is a good naive implementation if you don't wasn't to confuse first year comp-sci students who only just learned about linked lists.

      Here is a good paper of radix sort optimization, and it covers using radix sort with floating point.

      --
      -- http://thegirlorthecar.com funny dating game for guys
    3. Re:How is this not a radix sort? by Dirtside · · Score: 3, Funny

      Pfft, everyone knows the best sort is random sort. Randomize the list. Is it sorted? If not, randomize it again! You'll hit it eventually!

      --
      "Destroy science and religion. Science would re-emerge exactly the same; but not religion." - Penn Jillette, paraphrased
    4. Re:How is this not a radix sort? by hackstraw · · Score: 2, Interesting


      Funny, all I saw on the "site" was a donation link or something. Looked like a parked domain or something.

      But radix sorting is cool. What is very relevant to it in 2007 is that it scales superlinearly with multiple cores/CPUs which is important since most computers today have hardware that execute multiple threads simultaniously.

  2. It's radix sort. by Nick+Mathewson · · Score: 5, Informative
    From the page:

    4. Logic of BitFast BitFast works with numbers in the bit level. It applies masks to cut the numbers so it uses only the desired ( based on the programmer/problem specifications ) number of bits every run. It always start with the LSB ( Less Significant Bits ) ignoring the any other bits and every run it moves to the higher block of bits until the whole list is sorted. So is we want to sort 8 bit every run , the first timer it will sort 0-7 bits ( Least significant ), then the 8-15 bits , then the 16-23 bits and for last the 24-32 bits ( Most significant ) , having now sorted the entire list of 32bit numbers
    Congratulations, you have reinvented radix sort.
    1. Re:It's radix sort. by abradsn · · Score: 4, Insightful

      His algorythm is "in place"

      radix is not

      I agree though that the concepts for both algorithms are very similar.

    2. Re:It's radix sort. by vidarh · · Score: 5, Informative

      Making it in place is just an implementation detail, just as most other sorts can be done either in place or not (a typical example is quicksort, where most naive implementations tends to copy, while the typical C implementations tends to be in place).

    3. Re:It's radix sort. by rosscoe · · Score: 4, Funny

      Wow, he uses the new 33bit ints as well, enabling numbers twice as high as the so-old-school 32bit ints and making it just that 'little bit' better.

    4. Re:It's radix sort. by Tim+Browse · · Score: 5, Insightful

      Who do you thinks going to get the credit when they finally invent fission? The person who thought it up or those that actually made it?

      Well, I'm not sure, but I'm pretty sure it's not going to be the guy who made it again 30 years after everyone was already using it.

    5. Re:It's radix sort. by Lon · · Score: 5, Funny

      my sort goes to 11 ... wait, that is only three :(

  3. Re:Radix Sort by Anonymous Coward · · Score: 5, Funny

    How is this different from Radix sort?

    Marketing.

  4. Only lists of integers by iamacat · · Score: 2, Informative

    Nice, but you could just copy the list to array and do counting/radix sort. Does nothing for strings, floating point values, structures...

    1. Re:Only lists of integers by antifoidulus · · Score: 3, Interesting

      Not only integers, more than likely only POSITIVE integers. If you are using 2's complement that would mean that the first bit in all negative numbers would be a 1. Unless I missed something, this algorithm does not take that into account and would sort them as being larger than all positive numbers.

    2. Re:Only lists of integers by StikyPad · · Score: 2, Funny

      Does nothing for strings

      ahhiiinnoooprrssssttt

  5. radix sort vs. comparison sort by Peter+Desnoyers · · Score: 5, Informative

    It's a bit of an apples vs. oranges comparison to put this up against mergesort - mergesort is a comparison-based sort, while Papadopoulos' bitfast is a radix sort and thus O(N*W) where N is the number of elements and W is the width of each element in bits. (hint - try sorting 1000-byte strings with bitfast, and see which is fastest) And no, it doesn't have anything to do with hashing.

    However, it's definitely a clever way of implementing radix sort with linked lists, which may make it useful in some cases (e.g. OS internals) where you don't want to allocate space for a big directly-addressable array.

    1. Re:radix sort vs. comparison sort by Ignorant+Aardvark · · Score: 3, Interesting

      I ditto this. Mergesort is a true comparison sort, which means it can sort anything so long as a comparison between two values is defined, e.g. strings (in lexigraphical order), floating point numbers, 1000-digit numbers ... you get the drift. BitFast is a radix sort and only works in cases where the list elements obey certain limitations: for instance, if each list element can be expressed in 32 bits (an int).

    2. Re:radix sort vs. comparison sort by Wavicle · · Score: 5, Informative

      Actually it is much worse than you say.

      I don't know what possessed me to look at his code, but he really hasn't shown what he claims to have shown. It isn't clear to me that his code is doing what he says, but what IS clear to me is that his comparison to mergesort is very unfair. He has a TRULY AWFUL implementation of merge sort. For example, every time he goes to split a sub-list in half, he does a linear search from the current node to the end the sub-list. Having determined this value he then does ANOTHER LINEAR SEARCH to find the half-way point.

      So he has basically made an O(N^2) time complexity process just to divide the list for the merge sort. This is inside his n*log(n) merge sort. So he has an O(n^3) time complexity mergesort and trumps up how fast his modified radix sort is. Come on! Bubble sort would have beat his mergesort.

      His cleverness gets the better of him when it comes to his modified radix sort. For example, he creates two arrays (on the stack) of 65535 elements; apparently unaware that this creates an array with indexes 0..65534.

      --
      Education is a better safeguard of liberty than a standing army.
      Edward Everett (1794 - 1865)
    3. Re:radix sort vs. comparison sort by Tim+Browse · · Score: 5, Insightful

      I don't know what possessed me to look at his code

      Damn you! You made me look at his code! The goggles, they do nothing.

      His cleverness gets the better of him when it comes to his modified radix sort. For example, he creates two arrays (on the stack) of 65535 elements; apparently unaware that this creates an array with indexes 0..65534.

      I can't help feeling he should have declared Ptrs and Tails as Node* arrays, and bypassed all that random casting to longs. Not sure what's going on there. But then anyone who thinks the roundabout way he used of accessing the top 16 bits of a 32-bit memory value is 'cool' is definitely on my list of people most likely to re-invent the radix sort badly.

      At first, I thought it wasn't a stable sort, but looking further into it, that's because he mixed up the 'head' and 'tail' descriptions in the explanation (or possibly in the code).

      It is amusing that some /. posters think that doing this in-place is somehow an amazing leap of insight. Sometimes /. is like reading thedailywtf.com - you see something dumb as the main story, and then find half the people commenting on it have even less of a clue.

      I must be new here.

    4. Re:radix sort vs. comparison sort by Wavicle · · Score: 4, Informative

      But then anyone who thinks the roundabout way he used of accessing the top 16 bits of a 32-bit memory value is 'cool' is definitely on my list of people most likely to re-invent the radix sort badly.

      It is clearly a slow day for me. I have gone one step further and ported his code over to Linux (only required a change to GetTickCount) and attempted to run it. His "cool" way of using a pointer hack has caused his code to dump core. The problem is his hack being a signed short int pointer.
      Program received signal SIGSEGV, Segmentation fault.
      0x08048752 in BitFast (TailNode=0x804a018, run=0) at bitfast.h:37
                          if (Tail[val]) { //if not 0
      (gdb) p val
      $1 = -22087

      So I try putting unsigned on ptrHack.
      Program received signal SIGSEGV, Segmentation fault.
      0x08048772 in BitFast (TailNode=0x804a018, run=0) at bitfast.h:39
                          tmpN->nextNode = pN;
      (gdb) p tmpN
      $1 = (Node *) 0xffff

      Yeah. Not so sure that casting is what he really wants. I'm not entirely clear how it is his code will work. I really wanted to clean up his mergesort and re-run it to see how valid his claim is, but it looks hopeless. I'll work on it a little more, but since the problem seems to be in his algorithm, it doesn't look real hopeful.

      --
      Education is a better safeguard of liberty than a standing army.
      Edward Everett (1794 - 1865)
    5. Re:radix sort vs. comparison sort by adrianmonk · · Score: 4, Informative

      He has a TRULY AWFUL implementation of merge sort. For example, every time he goes to split a sub-list in half, he does a linear search from the current node to the end the sub-list. Having determined this value he then does ANOTHER LINEAR SEARCH to find the half-way point.

      So he has basically made an O(N^2) time complexity process just to divide the list for the merge sort. This is inside his n*log(n) merge sort. So he has an O(n^3) time complexity mergesort and trumps up how fast his modified radix sort is. Come on! Bubble sort would have beat his mergesort.

      That is maybe a bad implementation, but it actually does not make it O(n^3). In fact, it doesn't make it as bad as even O(n^2). Here's why:

      The first thing I want to establish is that linearly iterating halfway through the sublist a second time (to find the middle of it) has no effect on the asymptotic analysis. It just means going through the sublist 3/2 times, which is still a constant.

      The second thing is this: as you go deeper and deeper into the recursion, the size of the sublist is repeatedly cut in half. Thus, at every level as you go deeper into the recursion you are doing twice as many loops as the previous level (one loop for the first level, when the sublist equals the original list; two loops for the second, when you are breaking halves into quarters; four loops in the third level of recursion; and so on). BUT, although you are doing more loops, the size of the sublist is always half what it was at the previous level of recursion. So have you twice as many loops but half as many loop iterations.

      That means at every level of recursion (think of this size of the call stack if that helps in visualizing it), you are looping over the entire list once (well actually 3/2 times). And there are O(log n) levels of recursion, because every time you recurse, you are working on a list half as big as before.

      The result is that the total extra added time of this unnecessary linear traversal is O(n * log n) for the entire algorithm. Since mergesort is already O(n * log n), the extra looping to find the middle and end of the list has no effect on the asymptotic behavior of the algorithm.

    6. Re:radix sort vs. comparison sort by kigrwik · · Score: 2, Interesting

      Disclaimer: I didn't read the code, and don't intend to.

      I don't know if you're still interested, and I'm just hypothesizing here, but 0xFFFF is 65535 and some other posters noted that his array was of size 65535, which of course means that index 65535 is out of bounds by just one. This could cause your segfault.

      HTH,
      Kig.

      --
      -- don't discount flying pigs until you have good air defense
    7. Re:radix sort vs. comparison sort by Wavicle · · Score: 2, Informative

      That was indeed the problem. I did eventually get the thing running and, interestingly, despite using many published mergesort algorithms for sorting linked lists, the bitsort algorithm generally ran a constant 3-4x faster. So it appears that I was wrong about his mergesort having an asymptotic characteristic of O(n^3) and improving the efficiency of his mergesort gave only incremental performance improvement.

      Unfortunately this followup will forever be buried below the mod threshhold but it appears that despite my best efforts, radix sort (bitsort in this case) is superior to mergesort for linked lists. I tested different list sizes, different random ranges and a few other things I could think of, and bitsort always ran faster.

      The only weirdness I could not get rid of is that every time I compiled using gcc -O2 I got segfaults. I did not have time to track it down, I suspect stack smashing due to array usage irregularities.

      --
      Education is a better safeguard of liberty than a standing army.
      Edward Everett (1794 - 1865)
  6. wtf? seriously. by tomstdenis · · Score: 4, Informative

    First, it's just a radix sort [well that's my take]. Second there are too many google ads on that page. Third, merge sort is O(n log n) time, hard to beat for random data. Fourth, most people use variations of the QUICK SORT not merge sort.

    Tom

    --
    Someday, I'll have a real sig.
    1. Re:wtf? seriously. by slamb · · Score: 4, Insightful
      Fifth, most people don't sort link lists.

      Sixth, the headline "10X faster" is incorrect, as they differ asymptotically, not by a constant factor. (Run different data sets...vary by size of a single element, and by number of elements in the list. The ratio will change.)

    2. Re:wtf? seriously. by phazer · · Score: 5, Insightful

      Fifth, the author tries to "GPL" the algorithm, which is utter nonsense. GPL deals with copyright, so the most he can do is GPL his implementation of his bucket-/radix sort. Anyone is free to re-implement the algorithm, GPL or not.

      It would require a software patent to restrict the use of the algorithm to GPL programs.

      (And sixth, a quick look in a text book would have clued the author in)

    3. Re:wtf? seriously. by Anonymous+Brave+Guy · · Score: 3, Informative

      Third, merge sort is O(n log n) time, hard to beat for random data.

      Provably impossible, in fact.

      Fourth, most people use variations of the QUICK SORT not merge sort.

      I'm not sure that's a fair generalisation. There are several good O(n log n) sorting algorithms, heap sort being another obvious one, and typically things like the data structures involved, need for stability, or ease of parallelisation are the deciding factors in practice. In fact some of the best performing algorithms in real terms are theoretically O(n^2) in the worst case, hence the creation of hybrids like introsort, a quicksort variant designed to avoid the worst case by switching to heap sort after a certain recursion depth is reached.

      Anyway, I'm afraid this is another article by a 21-year-old student who is well-meaning, but not nearly experienced enough yet to appreciate that his suggestion is just rehashing (no pun intended) a lot of long-established ideas. I think the giveaway sign is that his CV on the site still lists just about every programming language and web development skill in existence. :-)

      --
      If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
    4. Re:wtf? seriously. by vidarh · · Score: 2, Insightful

      Actually sorting linked lists is useful in many cases, and can be done fairly efficiently with a well written quicksort (without the step of converting to array that this code does), since quicksort is conceptually just recursive partition around a pivot element - partitioning a linked list is cheap and can sometimes be faster than using an array if the objects being sorted are complex and stored by value (i.e. in any case where moving the linked list pointers around would be faster than copying the objects). A variety of other sorts are also easily adaptable to linked lists.

    5. Re:wtf? seriously. by TheRaven64 · · Score: 2, Insightful

      Third, merge sort is O(n log n) time, hard to beat for random data. Provably impossible, in fact. Not quite. O(n log(n)) is only the best case for comparison-based sorting. That is, if you have a less than (or greater than) predicate, you can build an algorithm that is O(n log(n)) using it. If your algorithm is not comparison-based, you can beat O(n log(n)). The most obvious example is bucket-sort, where you have k possible values. You pass over your list once, placing the value in the correct bucket, which gives you O(n) performance, at the cost of requiring k buckets worth of storage space (you can create the buckets on the fly, but then you add a O(log(n)) search into each step of the algorithm, dropping it back to O(n log(n))).
      --
      I am TheRaven on Soylent News
    6. Re:wtf? seriously. by Ivan+the+Terrible · · Score: 2, Interesting

      > the best performing algorithms in real terms are theoretically O(n^2)

      Agreed. For example, in a microcode example at work, the cost of searching for a given string was totally dominated by memory access time, so it really didn't matter which algorithm we used. So we used brute force. Pretty easy to debug, as well.

    7. Re:wtf? seriously. by kasperd · · Score: 2, Informative

      Fourth, most people use variations of the QUICK SORT not merge sort.
      Maybe for data that fits in memory. But if the data is on disk and you can't fit all of it in memory, nothing beats multiway mergesort.
      --

      Do you care about the security of your wireless mouse?
    8. Re:wtf? seriously. by Dwedit · · Score: 2, Informative

      Merge sort only requires extra memory to store a list of indexes or pointers, not extra memory for the full data. If your data is integers, then it's the same size. If your data is strings, then the array of indexes is smaller.
      As a plus, merge sort requires no recursion, which may be helpful if your stack is really tiny, like 200 bytes large.

    9. Re:wtf? seriously. by dkf · · Score: 2, Informative

      The kings of the sorting hill are quicksort, heapsort, mergesort, and insertion sort. For real data, quicksort (especially with a good pivot selector sub-algorithm) and heapsort are fastest (heapsort is also very frugal with the stack). Mergesort is a bit slower (but still O(n log n) with reasonable factors) and has the major bonus of being stable, so that elements that are equal to each other are not reordered (and that's very useful indeed with real data). Insertion sort (also stable) is the only O(n2) algorithm worth considering, and then only in a special case: when you've got some sorted data and want to add an item to it, this being a case that comes up surprisingly often. Insertion sort is also really easy to implement correctly.

      Radix sorts are reasonable, but only if the input keys are fairly short. I've never had data like that myself; for 10 character strings, a good quicksort is theoretically better for lists of a million keys or so, which is pretty good. ;-) Also, C programmers should definitely prefer to use quicksort, of course, because they've got an implementation of it in libc...

      --
      "Little does he know, but there is no 'I' in 'Idiot'!"
  7. 10X speedup? Compared to what? by DaleGlass · · Score: 2, Insightful

    It's useless to talk about the speed of a sort algorithm without discussing its complexity.

    Linear improvements are completely uninteresting. Take algorithm X in Perl, then a version in optimized assembly, and there you go, a 10X improvement without having done anything groundbreaking.

    A 10X faster bubble sort is just as useless for large enough values of n, and a 10x slower merge sort would still have a very good performance in comparison.

  8. Nice try, b ut... by Ancient_Hacker · · Score: 4, Informative
    I think you may have re-invented the "radix sort".

    It was used by 80-col card sorters, since circa 1925.

    See Knuth, Volume 3

  9. animation by hansamurai · · Score: 2, Funny

    Let me know when there's a video on Youtube of the sort doing it's thing with colored bits and animation.

  10. Re:FROTHY PISS by Anonymous Coward · · Score: 5, Funny

    No.
    You are an "HTML programmer".
    An oxymoron and a moron, simultaneously.
    Defenestrate yourself.

  11. That doesn't matter! by Anonymous Coward · · Score: 5, Funny

    This was written by VirusFree! Who wouldn't want to use something by a guy named VirusFree? It's a million times better than something by FreeVirus.

    1. Re:That doesn't matter! by ScrewMaster · · Score: 4, Funny

      No difference ... he's just saying that you can have his Virus ... Free.

      --
      The higher the technology, the sharper that two-edged sword.
  12. Re:multithreaded merge by SuperMog2002 · · Score: 2, Interesting

    I've never seen it done before, but I don't imagine it would be particularly diffucult to pull off. I'd say just add another parameter that tells the function how deep in the call stack it is. If it's less than x layers deep, fork with the child process going on to the other processor. The parent process sorts the first half of the list, and the child process sorts the second half. When the parent process finishes, it waits for the child process to finish (if it hasn't already), then collects the child's sorted list and merges as usual. The reason you'd want to track how deep you are is so that you don't wind up forking when there aren't any more processors available. For instance, if you were running on a two processor machine, you'd only want to fork once, since forking again would only add overhead without any gain. You could probably generate x on the fly based on the number of processors in the user's computer, too.

    The only problem I forsee is the case where the added overhead exceeds the gain. However, I imagine this would only be the case when you are sorting very small lists. Perhaps one could check the size of the list first and then decide whether or not forking is worth it.

    --
    Sunwalker Dezco for Warchief in 2016
  13. You're making the baby Knuth cry by aprosumer.slashdot · · Score: 5, Funny

    You're making the baby Knuth cry. Please read "The Art of Computer Programming" before proceeding any further.

  14. GPL-ed algorithm? by Wilson_6500 · · Score: 2, Interesting

    I've done a bit of scientific programming, but I'm not a computer-science-oriented person by any stretch. Thus, I'm a little confused by this. Under what license are things like Quicksort and Stupidsort (for another, very bad example) "released"? Why would a person feel it necessary to release an algorithm under any kind of license at all, in fact? No textbook would want to include GPL-ed code--wouldn't that make the entire book GPL by nature of the license?

    Please correct me if I'm mistaken, but this seems like a fairly bad precedent to set.

    1. Re:GPL-ed algorithm? by Helios1182 · · Score: 4, Informative

      You can't copyright an algorithm, so there is no license to worry about. This is a well meaning but utterly clueless person who reimplemented a well known algorithm and then made a strange constant-factor instead of asymptotic analysis.

  15. Re:multithreaded merge by TERdON · · Score: 4, Informative

    I have studied a course in parallel algorithms, including localized parallel merge sort (the algorithm you requested). It can be used to subdivide parallelized sorting theoretically unlimitedly. Links: Course homepage, The relevant chapter (PDF) of the course slides, with nice pictures and everything.

    --
    I have a really elegant proof for Fermat's last theorem. If this sig was only a bit longer...
  16. Re:Nice, but... by dlthomas · · Score: 5, Informative

    I guess it technically *is* O(N * log(N)) to the number of items, but this is misleading. It's actually O(N).

    As pretty much everyone has pointed out, it's just radix sort. The time taken by radix sort scales linearly to the number of keys, and with the log of the maximum key that can be held by the container.

    If we're dealing entirely with unique keys, this is of course >= log(N), by the pigeonhole principle and all that. If we may have duplicate keys, however, there may be more keys than container space, and radix *does* scale linearly to the keys.

    Time to prepare and overhead of this alrogrithm are negligable in any context large enough for us to care about the O() of the algorithms. For some things, this *is* better than mergesort. I'm just not sure why it was posted, as it's also not new - it was invented over 50 years ago.

  17. Re:oh really? by Ossifer · · Score: 2, Funny

    > First of all, algorithm running times and complexities are not compared as 3x or 5x faster. Please give me running time in Big O notation. Saying 10 times faster than merge sort makes no sense.

    But I came up with a sorting algorithm yesterday that's 12 times faster than bubblesort! Click here to see my advertisements....

    Seriously, mergesort (but NOT quicksort) is optimal, O(n log n) in one model. But there are sub-n log n sorting algorithms in other models. Some of them are based upon radix sort, surprise, surprise....

  18. Did KD set this guy up for ridicule on purpose? by grimJester · · Score: 5, Informative

    Ok, I'll start from his site:

    - Programming Skills : Visual Basic ***Excellent***

    Yes, that certainly is... excellent.

    - Message : "Don't ever let school, stop you from learning!"

    School could, learn you some grammar.

    The algorithm is being released under the GPL ( General Public License ). The algorithm belongs to PhoenixBit and VirusFree but you may use/modify it freely.
    *** DO NOT COPY ANYTHING FROM THIS PAGE TO ANY OTHER PAGE. IF YOU WANT SOMEONE TO READ THIS THEN LINK TO THIS PAGE ***


    In addition to trying to apply copyright to an algorithm, doesn't a restriction on copying defeat the purpose of releasing something under the GPL? Or does text in all caps trum previous text not in all caps?

    Feel free to add to this. If there are some clips of this guy with lightsabers, pleas post them.

    1. Re:Did KD set this guy up for ridicule on purpose? by Brandybuck · · Score: 3, Informative

      Geez, were you ever lucky! A ten ton joke just wooshed by inches over the top of your head! You could have been killed!

      --
      Don't blame me, I didn't vote for either of them!
    2. Re:Did KD set this guy up for ridicule on purpose? by remahl · · Score: 2, Funny

      I'll tell you what's ironic: People pointing out ironic things under the assumption they're not. That may make this message is ironic.

    3. Re:Did KD set this guy up for ridicule on purpose? by grimJester · · Score: 2, Interesting

      I think it's almost mandatory to have grammar or spelling errors in any grammar nazi post. I noticed the "pleas post" right after posting. As a newly found subset of Murphy's Law, someone should name it and become famous.

  19. solution in search of a problem by belmolis · · Score: 4, Insightful

    This is a variant of RadixSort, which is well known to be faster than any comparison sort such as MergeSort. The problem with non-comparison sorts is that as such they are restricted to sorting items representable a unstructured bit fields, which means, essentially, integers. A large part of the time, the real problem in sorting is (a) extracting the fields that you want to use as keys (since it is not generally the case that you want to sort on the entire record) and (b) arranging for each pair of records to compare as you need them to, which involves both recognizing the internal structure of keys (consider the case of dates) and imposing suitable weights for the individual components. In other words, in many situations the bulk of the code and time are devoted to parsing and transformation of records. So long as you are not using a really bad algorithm, the time devoted to the sort itself is likely to be a small percentage of the total time.

    For example, I have written a sort utility that differs from most others in its ability to parse the input into records and records into fields and in the transformations it can apply so as to use unusual sort orders and sort on things like dates, month names, and numbers in non-Western number systems. It was originally written for alphabetizing dictionaries of "exotic" languages. It is frequently the case that the time devoted to the actual sort is less than 1% of the run time.

    In sum, non-comparison sorts have a niche but are of limited utility because they get their speed from making use of additional information that is only available for a limited set of datatypes. For the great majority of applications, only comparison sorts are flexible enough to be of use.

  20. Re:oh really? by Stalus · · Score: 2, Insightful

    Well, consider the source. It was written by a 21 y/o student who has listed his primary language as Visual Basic. Obviously he isn't trained in theory. That said, a nice discovery for him, but not Slashdot news, and definitely not academic journal material.

    Quicksort may have a best expected sorting time, but still has an O(n^2), since O is worst case. I think the STL takes a pass at the list to determine how sorted the list appears to be and then picks a sorting algorithm based on that... but it's been awhile since I looked at it.

  21. Shock horror, stop the presses by sholden · · Score: 2, Informative

    Retard who thinks you can GPL an algorithm manages to reinvent an algorithm first implemented as a computer program in the 1950s, and used way before then outside of digital computers.

    Also manages to not know about memset and write C code that assumes sizeof(long)==4 and puts non-inline code in header files. I don't dare look at the C++ code since there's a large probability it will cause permanent brain damage.

  22. Re:int main by Srdjant · · Score: 2, Interesting

    His main BitFast code is in header files...
    Messy and inconsistent indenting (check c/ and c++/ files for differences)

    Difference between c/* and c++/* is that c++/ has cout instead of printf()... well done...

    This stuff should go to worsethanfailure.com (was TheDailyWTF.com)

  23. Where's the proof? by frostilicus2 · · Score: 2, Insightful

    Perhaps coming from a math background, my priorities differ from those with a CS background, but...

    Where's the proof?

    Is it peer reviewed? Has it been published? Does it exist?
    Although the lack of a proof does not make your algorithm is incorrect, I'd be suspicious. In fact, I would be unwilling to use any algorithm in my code without being sure that a good proof of its correctness exists somewhere.
    Proofs are more than formalities, they're essential: without a good proof, you're just a crank selling snake oil.

    --
    Nothing sucks like a Vax, nothing blows like a PowerMac G4
  24. Buffer overflow by TheMoog · · Score: 2, Insightful

    Unless I'm very much mistaken, there's a blatant buffer overflow in this code. In bitfast.h the "Tail" and "Head" arrays are defined as having 65535 (0xffff) entries. That's from 0-65534 inclusive.

    The code in "BitFast" then uses the array as if it can access Head[0xffff] and Tail[0xffff] - which is one past the end of the arrays. I'd guess it works by coincidence on Win32.

    Additionally, although there might be some reason I can't follow at the moment, in the float version only the top 15 bits of the values are seemingly used. This would seem to ignore the sign bit of the FP representation. Maybe there's another subtlety I'm missing, but I can't see it at the moment.

    Given these basic misunderstandings of programming concepts I'm not surprised the authors hadn't known of the radix sort which many people here have linked as being very similar indeed.

  25. How many stupidities in one post? by Lord+Duran · · Score: 2, Funny

    1. Loop ......................AddHobbie ("Computers"); ................Do Until 1=2 Since he says he's "**Excellent**" in Visual BASIC, one could ponder how he MIXED UP THE Do AND Loop STATEMENTS. 2. Don't ever let school, stop you from learning! He apparently never had... 3. 10 times faster than MergeSort? That's asymptotically, right? O(10nlogn). Call the press. (Doesn't matter that Radix Sort actually takes O(n), as long as it's 10X!) 4. BitFast start by creating two arrays of size 65535 ( pow(2,16) ) Anyone got a calculator? Somehow his numbers don't add up. Is it actually possible for a positive power of two to be odd? And...Since when do you use pow to calculate powers of two? 5. They are not the most error free,optimized,commented,beautifull code to have ever been written Gee...really?

  26. Re:FROTHY PISS by VENONA · · Score: 5, Insightful

    Explanation: pretty much bogus.

    As for the quality of your post: let me guess--you also complain about slow, bloated software, right? The old, "Intel giveth, Microsoft taketh away," adage? Users have several orders of magnitude more compute and storage power than 'back in whatever day' yet personal computers seem little more responsive, etc.

    Don't feel lonely. There's a large population of lugnuts like you, who, if they think of CS at all, largely carp about how some CS departments haven't become current technology de jour tradeschools. Some, unfortunately, have, but that's a whole different discussion, which has been seen on Slashdot time and again.

    Algorithm research is important, as is having at least something of a grasp of algorithms. In *your* next programming exercise, since you seem to regard sort efficiency as 'esoteric', feel free to reinvent the bubble sort. Also, tout it as the Next Great Thing, and submit patches against all your favorite apps. That will get you your twenty seconds of fame, I assure you.

    Sometimes I love Slashdot--but then I read a post from some random AC idiot like you: the proverbial lowest common denominator. Maybe you should restrain your efforts toward what you seem to regard as cool snarky posts, watch a thread (about which you plainly know nothing) develop, and maybe freaking *learn* something.

    OTOH, maybe I'm just bitter right now, because I've just been doing a search through Google news on climate change, and I'm pretty much convinced that the last thing the human race needs right now is people like you.

    --
    What you do with a computer does not constitute the whole of computing.
  27. Re:The algorithm belongs to PhoenixBit and VirusFr by maxwell+demon · · Score: 2, Funny

    Of course one would hope that the patent examiners at least have heared about radix sort, and therefore would reject that patent due to prior art ... but then, maybe he can avoid that by adding "with a computer" :-)

    --
    The Tao of math: The numbers you can count are not the real numbers.
  28. Memory leaks... by fprog26 · · Score: 4, Interesting

    Inside bitfast.h:
    long *Tail = new long[65535];
    long *Head = new long[65535];

    for(n = 0; n < 65535; n++){ Head[n] = 0; Tail[n] = 0; }

    Memory leak of 128KB for each time the function "Node* BitFast(Node* HeadNode,long run)" is called.

    MISSING: delete[] Tail; delete[] Head;

    Furthermore the following is faster or use memset:
    long Tail[65535] = {0};
    long Head[65535] = {0};

    Unless you are running this in DOS16, DOS32 with Pharlap or smaller 8051, 68000 processor, you do not need to use new[] or malloc() for this.

    In InsertToList, Node *tmpP = (Node*)malloc(sizeof(Node));
    free(tmpP) missing inside FreeList()... no such function

    In main.c:
    Node *L1 = malloc(sizeof(Node));
    Node *L2 = malloc(sizeof(Node));
    MISSING: free(L1); free(L2);

    In main.cpp:
    Node *L1 = new Node;
    Node *L2 = new Node;

    Instead use (no need to use heap, use stack memory):
    Node L1 = {0}, L2 = {0};

    Mixing the usage of std::cout and printf() is not recommanded.
    Use all of the former or the later, else you will have weird display on some run, unless you flush the output buffer. I suggest you use printf() all the way.
    cout << "Ok!!!!" << "\n\n" << "Merge Sort : " << tim1 << " ms\n" << "BitFast : " << tim2 << " ms\n\n";
    becomes:
    printf("Ok!!!!\n\nMerge Sort : %ld ms\nBitFast : %ld ms\n\n", tim1, tim2);

    Furthermore, your implementation of link list, and calling Length(Node*) for every equal is highly inefficient, requires O(n). Store the link list length somewhere when inserting. EqualSplit takes O(1.5n) instead of O(0.5n) because of that.

    Something like:

    typdef struct LinkList {
      Node  head;
      int   length;
    } LinkList;

    As a result, MergeSort recursively call itself, which calls EqualSplit every turn.

    You should make your header file C friendly, and avoid mixing // with /* */, malloc and new[]

    No clue why this header is needed:
    #include <iso646.h>  instead of not/and use use ! and &&
    before:  if(not p) return NULL;
    becomes: if(!p) return NULL;

    Finally, BitFast is not recursive; therefore, you should try to find an implementation of merge sort which is not recursive also, so you save on function calls, if possible.

    "However, iterative, non-recursive, implementations of merge sort, avoiding method call overhead, are not difficult to code." -- Wikipedia

    http://en.wikipedia.org/wiki/Merge_so rt

    Your function should be in a file.c or be inline.

  29. Re:oh really? by DeKO · · Score: 2, Insightful

    It only approaches O(n log n) behavior when the data are completely randomized.

    No. Quicksort is O(n log n) on average. There are pathological scenarios, but all other instances absorb the O(n^2) worst case. Sedgewick's PhD (under Knuth's) was about Quicksort, try reading it if you are nuts enough. Or even read Knuth's volume on sorting, to see hem distilating and comparing even the constants from the algorithms.

  30. Knuth vol 3 page 173 by CustomDesigned · · Score: 3, Funny

    The Art of Computer Programming, vol 3, Sorting and Searching, 1973, by Donald Knuth Page 173, Algorithm R - radix list sort. No credit is given. The algorithm has been well known and obvious since the first link list was invented. Hey! A good choice for a patent!

  31. Multiple bugs in the code, wrong measurements ! by wtarreau · · Score: 5, Interesting

    Don't use this code !

    First, there are multiple bugs in the code itself :

    1) everywhere, it is assumed that 2^16 = 65535 and not 65536. Arrays are allocated for this size too, but are used with 65536 entries. (un)fortunately for him, the space is probably allocated anyway so the program does not crash on this.

    2) a similar bug in the random number generator carefully avoids dangerous values, because he generates numbers between min and max by doing a modulo on max-min , which prevents max from being produced. This is not a
    big deal anyway, just that it hides the bug.

    3) he assumes everywhere that "long" is unsigned and "short int" too. This makes the code SegFault on Linux with negative array indexes. The fix is obvious, though.

    And most of all : times are measured in optimal conditions. Indeed, this algorithm is
    just a radix sort with a large radix (2^16). A radix algorithm is efficient when the number
    of elements is high compared to the radix, because at every level, all radix entries have to
    be scanned for existing values. In his example, he sorts 4 million elements. His code is faster
    than the merge sort on 4 million entries, just as would be any radix sort. But on smaller sets,
    it still takes the same time per level, because it has to scan all 65536 entries even if there
    are only 100 numbers. The fact is that for less than 10000 values, the mergesort becomes faster in his own code.

    When measuring algorithms complexity, we use the O(x) notation. The time per iteration is never
    considered. When the time matters (as in his example), we should consider the time per iteration (T), and the total time (t) will follow :

          t = T . complexity

    In complexity, his algorithm is O(N) on 16 bits, but the time per iteration is very high. Other sorting algorithms are O(N.log(N)). So the total time is :

          t1 = T1 . O(N) for his algorithm, and :
          t2 = T2 . O(N.log(N)) for the mergesort.

    But when T1 > T2.log(N), he looses, which is almost always because log(N) is small for 16 bits, and T2 too because operations are very simple. In his case, T1 is very high because it represents the time required to scan 65536 values.

    It's amazing that he fell in such a beginner's trap. I suppose that he's still a student, which would explain the total lack of portability and newbie's bugs in the code.

    Well tried anyway :-)

    Willy

    1. Re:Multiple bugs in the code, wrong measurements ! by slashdot.org · · Score: 2, Informative
      Good points. But, we should give the guy some credit, he does state in the readme:


      This examples are for Proof of Concept only.

      They are not the most error free,optimized,commented,beautifull code
      to have ever been written


      Personally I would never write code like this, proof of concept or not, avoiding the portability problems for example would not have taken more time to write. But pressumably more experience. So probably the best thing to do is be constructive about it.

      I'll give it a shot on some of the issues that I found:

      - don't assume long = 32 bit and short int = 16 bit. Different compilers/platforms will have different sizes. If you need to proof of concept something and don't want to deal with the portability issues, do something like:

      typedef unsigned long u32;
      typedef unsigned short u16;

      And then use u32/u16 throughout. That way, if someone wants to port the code, all they have to do is define the proper typedefs for their platform (I usually put that stuff in it's own header, like "to_port.h" or something).

      Also, it makes it very obvious that you are relying on certain vars to be of a certain size.

      - don't rely on how variables are stored in memory i.e. on what endian-ness the architecture is. If you take a 32 bit unsigned integer, the low 0-7 bits are not stored at the same memory address on different architecture. If you don't understand what I'm talking about, google for little-endian & big-endian. If you don't want to deal with special casing it, do something like #define LITTLE_ENDIAN 1 in your to_port.h, and then in the code do something like

      #ifndef LITTLE_ENDIAN
      #error This code assumes little endian
      #endif
      - this code:

      long Ptrs[65535];
            long Tail[65535];
      stores 512KB on the stack. That's generally considered quite extravagent, to put it mildly.

      - use memset instead of this code:

      for(n=0;n<65535;n++){
              Head[n]=0;
              Tail[n]=0;
          }
      as an example, Microsoft's compiler can inline memset making it extremely fast, compared to a for loop. Btw. the write-through cache on the CPU would probably prefer it if this was broken up into two separate loops, so memory gets accessed linearly, instead of jumping back and forth.
    2. Re:Multiple bugs in the code, wrong measurements ! by wtarreau · · Score: 2, Insightful

      "The fact is that for less than 10000 values, the mergesort becomes faster in his own code."

      Ok, I agree on all your other points, but this is one always irritates me. Only someone very theoretical would mention that for 10000 (integer) values or less this sort is sub-optimal. Come on, how many ms would that sort really take? For less than 10000 values you could use a 286 and get it over relatively quickly.

      I almost laughed all the way from my chair when I heard this in college. Same mistake. Nobody cares for values that low. It could be O(N^2) for all I care.


      Are you kidding ???

      Obviously you don't know what sort algorithms are use for ! Any real time system or multi-task
      subsystem (application or kernel) needs a scheduler to very quickly sort timers in order to wake
      up tasks at the right moment without scanning the whole list. For instance, in a proxy like
      Squid, you would need something like 10000 struct timeval to handle 10000
      connections. If the algorithm takes milliseconds to sort 10000 values, your proxy will be
      the slowest on earth. Worse, if it takes as much time when you have only 10 or 100 connections,
      it is a real shame. Sorting 10000 values should take microseconds in such applications.

      The same is true for kernel code. Did you ever wonder how the socket timeouts are handled ?
      When you have to update your timeouts at every packet, you need something very fast,
      clearly not an O(n^2) algorithm, nor bitfast

      Willy
  32. Re:I nominate this... by DrMindWarp · · Score: 3, Funny

    It's only March. There'll be an inventor of the internal combustion engine along shortly.

  33. Be nice by l3mst0r · · Score: 2, Informative

    I invented Radix sort once, too. Who hasn't? Let him have his 15 minutes of fame.

  34. I'm not really sure, but. by Goaway · · Score: 3, Funny

    Maybe this guy has re-invented radix sort? I can't really tell! I wish somebody would post and tell me!

  35. A couple of non-obvious notes about radix sort ... by RallyDriver · · Score: 2, Insightful


    1. Although it's technically O(n) compared to QuickSort's O(n log n), consider the fact that

    a. the number of passes required by radix sort is proportional to the key size, and that
    b. if the keys are primarily unique, then the key length will be O(log n) .... thus radix sort is actually O(n log n) when applied to practical cases, hence why everyone uses quicksort or mergesort instead.

    2. One cute feature of radix sort for very large data sets is that you only need linear access to the data, so it can be done with non-random-access external storage. The one practical implementation I've ever heard of used four 9-track tape drives.

    However, considering use in main memory, both radix sort and quicksort make efficient use of a D-cache that is 2-way set-associative or better, and both hit the whole data set once per pass -> if it swaps, it'll swap a lot :-)

  36. Re:Apropos by asylumx · · Score: 2, Funny

    "Those who cannot remember the past are doomed to repeat it." - George Santayana

  37. Re:multithreaded merge by CoughDropAddict · · Score: 2, Informative

    I notice that the course homepage talks about designing for an "idealised parallel computer" -- did it take into account the huge speed hit that comes from false sharing on real processors? That should be a major consideration if you are designing shared-memory parallel algorithms, since they can degrade performance by 1700% on modern processors. If you're not careful, your parallel algorithms could end up being much slower than single-threaded ones simply because they force so many cache bounces.

  38. Ripping apart the source by jinxidoru · · Score: 4, Informative

    The previous few posts caused me to also open up the code. Wow! What a ride! I decided that I wanted to add a few things I found as well.

    I loved that he referred to his use of the short pointer as a "cool pointer hack to avoid shifts and ifs!!!" To begin with, if we have to call that a "cool hack" then the requirements for coolness have definitely dropped a bit. I am also confused as to how this helps avoid shifts and ifs. As far as I can tell, it avoids one shift. I'd love to see the code without the "cool hack" because I'm intrigued as to how he uses an if statement to remove the higher bits.

    As stated before, I am also fond of his use of an array of size 65535 rather than 65536. I surprised he didn't run into any segmentation faults. I know that I can give him a test case that will seg fault pretty easily.

    I also question whether he understands the purpose of a header file, as the entire source for his BitSort is contained within a header file. I guess it would sort of make sense if the function was declared inline, but it isn't.

    Another fun element is how non-modular his code is. Everything is hard-coded, even though it would have been easy to declare a few constants or even make the function a template.

    Lastly though, why the crap did this article get through the editors. It is, as has been stated over and over, a radix sort and nothing different. I know that he claims it is different because it is in-place, but that is such an obvious simple change that it does not warrant a whole new algorithm. Regardless of the content, the article is so poorly written with some of the worst grammar I have read in quite some time. Slashdot really needs to improve its article standards.

  39. Quoting Knuth... by Ellen+Spertus · · Score: 2, Funny