Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Learning LINQ: QuickSort

Tags:

c#

.net

linq

I took the plunge this afternoon and began studying LINQ, so far just mucking around with LINQ on collections. One of the first things I tried was to implement QSort.

Now -- ignoring the fact that I could just use an ORDERBY and that this is a very silly qsort implementation -- what I came up with was this:

public class lqsort
{
    public static List<int> QSLinq(List<int> _items)
    {
        if (_items.Count <= 1)
            return _items;

        int _pivot = _items[0];

        List<int> _less = (from _item in _items where _item < _pivot select _item).ToList();
        List<int> _same = (from _item in _items where _item == _pivot select _item).ToList();
        List<int> _greater = (from _item in _items where _item > _pivot select _item).ToList();

        return (QSLinq(_less).Concat(_same.Concat(QSLinq(_greater)))).ToList();
    }
}

The only thing that really bugs me is all of the casting involved. Are there any LINQ tricks I might use? Or am I just using LINQ for things it wasn't intended for?

like image 701
Dana Avatar asked Oct 08 '08 21:10

Dana


2 Answers

Just change the type of the parameter to IEnumerable and use the var construct instead of your List<int> for your local variables.

This will make your QSLinq method better because it will accept more types of parameters, for example int[], as well as List<int>.

See the new method:

    public static IEnumerable<int> QSLinq(IEnumerable<int> _items)
    {
        if (_items.Count() <= 1)
            return _items;

        var _pivot = _items.First();

        var _less = from _item in _items where _item < _pivot select _item;
        var _same = from _item in _items where _item == _pivot select _item;
        var _greater = from _item in _items where _item > _pivot select _item;

        return QSLinq(_less).Concat(QSLinq(_same)).Concat(QSLinq(_greater));
    }

Hope this helps.

like image 65
Alfred B. Thordarson Avatar answered Oct 12 '22 07:10

Alfred B. Thordarson


Fun Question! This doesn't outperform OrderBy, but it does limit the repeated enumerations some.

    public static IEnumerable<int> QSort2(IEnumerable<int> source)
    {
        if (!source.Any())
            return source;
        int first = source.First();
        return source
            .GroupBy(i => i.CompareTo(first))
            .OrderBy(g => g.Key)
            .SelectMany(g => g.Key == 0 ? g : QSort2(g));
    }

I inadvertently generated a stackoverflow during development, as I QSorted when the Key == 0.


Just for fun I tested these solutions. I commited the cardinal performance testing sin (testing in debug mode), but I don't think that affects the big O effect we'll see. Here is the input (reversed input is worst case for quicksort)

IEnumerable<int> source = Enumerable.Range(0, 1000).Reverse().ToList();
  • The triple concat-where solution took 71000 milliseconds.
  • My solution took 330 milliseconds
  • OrderBy.ToArray took 15 milliseconds (the timer's resolution, so actual time is probably less)
like image 43
Amy B Avatar answered Oct 12 '22 06:10

Amy B