简体   繁体   中英

Quicksort algorithm (C#)

I would like to ask what's actually wrong on this code. I tried to understand quicksort (2-way) by myself so I looked into this page: http://me.dt.in.th/page/Quicksort/#disqus_thread after that I tried to code it by myself and landed here:

    public void Sort(Comparison<TList> del, long l, long r)
    {
        // inspired by: http://me.dt.in.th/page/Quicksort/
        if (l >= r) return;

        // partitioning
        for(long i = l + 1; i <= r; i++)
        {
            if (del.Invoke(this[i], this[l]) < 0)
            {
                Swap(i, l);
            }
        }

        // recursion
        Sort(del, l, l - 1);
        Sort(del, l + 1, r);
    }

Then I looked into the comments on the mentioned website and found this:

void qsort(char *v[], int left, int right)
{
    int i, last;
    void swap(char *v[], int i, int j);

    if (left >= right)
        return;
    swap(v, left, (left + right) / 2);

    last = left;

    for (i = left + 1; i <= right; i++)
        if (strcmp(v[i], v[left]) < 0)
            swap(v, ++last, i);
    swap(v, left, last);
    qsort(v, left, last - 1);
    qsort(v, last + 1, right);
}

and now I'm really curious why my code is still working, tested it with this (it's included in a linked list by the way):

    static void Main(string[] args)
    {
        MyList<int> obj;

        do
        {
            obj = MyList.Random(100, 0, 100);
            obj.Sort(stdc);
            obj.Sort(stdc);
        } while (obj.IsSorted(stdc));

        Log("Not sorted", obj);

        Console.ReadKey(true);
    }

and this:

    public bool IsSorted(Comparison<TList> del)
    {
        var el = start;

        if (el != null)
        {
            while (el.Next != null)
            {
                if (del.Invoke(el.Value, el.Next.Value) > 0) // eq. to this[i] > this[i + 1]
                    return false;
                el = el.Next;
            }
        }

        return true;
    }

and this:

    public static MyList<int> Random(int num, int min = 0, int max = 1)
    {
        var res = new MyList<int>();
        var rand = new Random();

        while (num > 0)
        {
            res.Add(rand.Next(min, max));
            num--;
        }

        return res;
    }

Your quicksort code is not really quicksort, and it will be slow. The line

        Sort(del, l, l - 1);

will not do anything, since the recursed into call will detect l >= (l-1). The line

        Sort(del, l + 1, r);

only reduces the size of the partition [l,r] by one to [l+1,r], so the time complexity will always be O(n^2), but it looks like it will work, just slowly.

The qsort() function swaps the left and middle values, this will avoid worst case issue if data is already sorted, but doesn't do much else. The key is that it updates "last", so that when partition is completed, the value at v[last] will be the pivot value, and then it makes recursive calls using "last" instead of "left" or in your code's case, "l".

The qsort shown is a variation of Lomuto partition scheme. Take a look at the wiki article which also includes the alternate Hoare partition scheme:

https://en.wikipedia.org/wiki/Quicksort#Algorithm

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM