为什么我的链表快速排序的实现要慢于数组一?

时间:2017-03-07 22:01:21

标签: c# algorithm list sorting quicksort

我一直是算法问题,需要我对链表和数组进行快速排序算法的实现 我已经完成了两个部分,算法正在运行,但似乎我的快速排序链表实现中存在一些错误。

这是我的快速排序链接列表实现。

public static void SortLinkedList(DataList items, DataList.Node low, DataList.Node high) 
    {
        if( low != null && low !=high)
        {
            DataList.Node p = _PartitionLinkedList(items, low, high);
            SortLinkedList(items, low, p);
            SortLinkedList(items, p.Next(), null);
        }


    }

    private static DataList.Node _PartitionLinkedList(DataList items, DataList.Node low, DataList.Node high) 
    {
        DataList.Node pivot = low;
        DataList.Node i = low;
        for (DataList.Node j = i.Next(); j != high; j=j.Next())
        {
            if (j.Value().CompareTo(pivot.Value()) <= 0)
            {

                items.Swap(i.Next(),j);
                i = i.Next();

            }
        }
        items.Swap(pivot, i);
        return i;
    }

这是快速排序数组实现

 public static void SortData(DataArray items, int low, int high) 
    {
        if (low < high)
        {
            int pi = _PartitionData(items, low, high);
            SortData(items, low, pi - 1);
            SortData(items, pi + 1, high);
        }

    }
 static int _PartitionData(DataArray arr, int low, int high) 
    {
        double pivot = arr[high];
        int i = (low - 1);
        for (int j = low; j <= high - 1; j++)
        {
            if (arr[j].CompareTo(pivot)<=0)
            {
                i++;
                arr.Swap(i,j);
            }
        }
        arr.Swap(i + 1, high);
        return i + 1;
    }

这是快速排序数组和链表性能。 (左,右时间)
Picture
如你所见,qs链表需要10分钟来排序6400个元素。我不认为这是正常的..

另外我不认为它是因为数据结构,因为我使用相同的结构进行选择排序,并且链表和数组的性能都相似。

GitHub repo,以防我忘记提供一些代码。 Repo

3 个答案:

答案 0 :(得分:0)

我会查看你的链表,特别是swap方法。除非我们看到链表的实现,否则我认为问题领域就在那里。

你有没有理由使用链接列表?他们有o(n)搜索,这使得快速排序n ^ 2lg(n)排序。

另一种方法是将链接列表中的所有项目添加到列表中,对列表进行排序,然后重新创建链接列表。 List.Sort()使用快速排序。

public static void SortLinkedList(DataList items) 
{
    list<object> actualList = new list<object>();

    for (DataList.Node j = i.Next(); j != null; j=j.Next())
    {
        list.add(j.Value());
    }

    actualList.Sort();

    items.Clear();
    for (int i = 0; i < actualList.Count;i++)
    {
        items.Add(actualList[i]);
    }
}

答案 1 :(得分:0)

对于6400个元素来说,10分钟是很长的一段时间。它通常需要2到3个可怕的错误,而不只是一个。

不幸的是,我只看到一个可怕的错误:你对open(FILE,'data.txt'); my $line = <FILE>; my @lines = <FILE>; print @lines; while (<FILE>) { print "$_"; } 的第二次递归调用一直到列表的末尾。你想让它停在SortLinkedList(items, p.Next(), null);

这可能占了10分钟,但似乎有点不太可能。

即使您修复了上述错误,它也会让我觉得您的排序不正确 - 请务必测试输出!

答案 2 :(得分:0)

链表的快速排序通常与数组的快速排序略有不同。使用第一个节点的数据值作为透视值。然后代码创建3个列表,一个用于值&lt; pivot,一个用于值== pivot,一个用于值&gt;枢。然后它对&lt;进行递归调用。枢轴和&gt;枢轴列表。当递归调用返回时,这3个列表现在被排序,因此代码只需要连接3个列表。

要加速列表的连接,请跟踪指向最后一个节点的指针。要简化此操作,请使用循环列表,并使用指向最后一个节点的指针作为访问列表的主要方式。这使得追加(加入)列表更简单(无扫描)。进入函数后,使用last-&gt; next以获取指向列表第一个节点的指针。

两种最坏情况数据模式已经是已排序数据或已经反向排序的数据。如果使用带有指向最后一个节点方法的指针的循环列表,那么最后一个节点和第一个节点的平均值可以用作2的中位数,这可能有所帮助(注意节点的列表==枢轴可能最终为空)。

最坏情况时间复杂度为O(n ^ 2)。最坏情况下的堆栈使用是O(n)。可以通过在列表中较小的列表上使用递归来减少堆栈使用量。枢轴和列表&gt;枢。返回后,现在排序的较小列表将与list == pivot连接并保存在第4个列表中。然后排序过程将迭代剩余的未排序列表,然后合并(或可能加入)保存的列表。

使用任何方法(包括bottom up merge sort)对链接列表进行排序比将链接列表移动到数组,排序数组,然后从排序数组创建链接列表要慢。然而,我描述的快速排序方法比使用带链表的数组定向算法要快得多。