为什么我的链表快速排序比数组慢很多?
Why my implementation of linked list quick sort is much slower than array one?
我是算法题,需要我实现链表和数组的快速排序算法。
我已经完成了这两个部分,算法正在运行,但我的快速排序链表实现似乎存在一些错误。
这是我的快速排序链表实现。
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;
}
这是快速排序数组和链表的表现。 (左边n,右边时间)
Picture
如您所见,qs 链表需要 10 分钟才能对 6400 个元素进行排序。我认为这不正常..
我也不认为这是因为数据结构,因为我使用相同的结构进行选择排序并且链表和数组的性能相似。
GitHub 回购以防我忘记提供一些代码。 Repo
我会看看你的链表,尤其是交换方法。除非我们看到链表的实现,否则我认为问题所在。
您使用链表有什么原因吗?他们有 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]);
}
}
10 分钟对于 6400 个元素来说是一个非常长的时间。它通常需要 2 或 3 个可怕的错误,而不仅仅是一个。
不幸的是,我只看到一个可怕的错误:您对 SortLinkedList(items, p.Next(), null);
的第二次递归调用一直到列表的末尾。你的意思是让它停在 high
.
这可能占了 10 分钟,但似乎不太可能。
在我看来你的排序也不正确,即使你修复了上述错误 -- 请务必测试输出!
链表的快速排序通常与数组的快速排序略有不同。使用第一个节点的数据值作为枢轴值。然后代码创建了 3 个列表,一个用于 values < pivot,一个用于 values == pivot,一个用于 values > pivot。然后它对 < pivot 和 > pivot 列表进行递归调用。当递归调用 returns 时,这 3 个列表现在已排序,因此代码只需要连接这 3 个列表。
要加快列表的连接速度,请跟踪指向最后一个节点的指针。为了简化这一点,使用循环列表,并使用指向最后一个节点的指针作为访问列表的主要方式。这使得附加(加入)列表更简单(无需扫描)。一旦进入函数,使用 last->next 以获得指向列表第一个节点的指针。
两种最坏情况的数据模式是已经排序的数据或已经反向排序的数据。如果使用指向最后一个节点方法的循环列表,那么最后一个节点和第一个节点的平均值可以用作 2 的中位数,这可能会有所帮助(注意节点列表 == pivot 可能最终为空)。
最坏情况下的时间复杂度为 O(n^2)。最坏情况下的堆栈使用是 O(n)。通过对列表 < pivot 和 list > pivot 中较小的一个使用递归,可以减少堆栈的使用。在 return 之后,现在排序的较小列表将与列表 == pivot 连接并保存在第 4 个列表中。然后排序过程将迭代剩余的未排序列表,然后与保存的列表合并(或可能加入)。
使用任何方法(包括 bottom up merge sort )对链表进行排序,比将链表移动到数组、对数组排序,然后从排序后的数组创建链表要慢。然而,我描述的快速排序方法将比使用带有链表的面向数组的算法快得多。
我是算法题,需要我实现链表和数组的快速排序算法。
我已经完成了这两个部分,算法正在运行,但我的快速排序链表实现似乎存在一些错误。
这是我的快速排序链表实现。
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;
}
这是快速排序数组和链表的表现。 (左边n,右边时间)
Picture
如您所见,qs 链表需要 10 分钟才能对 6400 个元素进行排序。我认为这不正常..
我也不认为这是因为数据结构,因为我使用相同的结构进行选择排序并且链表和数组的性能相似。
GitHub 回购以防我忘记提供一些代码。 Repo
我会看看你的链表,尤其是交换方法。除非我们看到链表的实现,否则我认为问题所在。
您使用链表有什么原因吗?他们有 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]);
}
}
10 分钟对于 6400 个元素来说是一个非常长的时间。它通常需要 2 或 3 个可怕的错误,而不仅仅是一个。
不幸的是,我只看到一个可怕的错误:您对 SortLinkedList(items, p.Next(), null);
的第二次递归调用一直到列表的末尾。你的意思是让它停在 high
.
这可能占了 10 分钟,但似乎不太可能。
在我看来你的排序也不正确,即使你修复了上述错误 -- 请务必测试输出!
链表的快速排序通常与数组的快速排序略有不同。使用第一个节点的数据值作为枢轴值。然后代码创建了 3 个列表,一个用于 values < pivot,一个用于 values == pivot,一个用于 values > pivot。然后它对 < pivot 和 > pivot 列表进行递归调用。当递归调用 returns 时,这 3 个列表现在已排序,因此代码只需要连接这 3 个列表。
要加快列表的连接速度,请跟踪指向最后一个节点的指针。为了简化这一点,使用循环列表,并使用指向最后一个节点的指针作为访问列表的主要方式。这使得附加(加入)列表更简单(无需扫描)。一旦进入函数,使用 last->next 以获得指向列表第一个节点的指针。
两种最坏情况的数据模式是已经排序的数据或已经反向排序的数据。如果使用指向最后一个节点方法的循环列表,那么最后一个节点和第一个节点的平均值可以用作 2 的中位数,这可能会有所帮助(注意节点列表 == pivot 可能最终为空)。
最坏情况下的时间复杂度为 O(n^2)。最坏情况下的堆栈使用是 O(n)。通过对列表 < pivot 和 list > pivot 中较小的一个使用递归,可以减少堆栈的使用。在 return 之后,现在排序的较小列表将与列表 == pivot 连接并保存在第 4 个列表中。然后排序过程将迭代剩余的未排序列表,然后与保存的列表合并(或可能加入)。
使用任何方法(包括 bottom up merge sort )对链表进行排序,比将链表移动到数组、对数组排序,然后从排序后的数组创建链表要慢。然而,我描述的快速排序方法将比使用带有链表的面向数组的算法快得多。