C# 对链表进行排序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/768095/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sorting a linked list
提问by GurdeepS
I have written a basic linked list class in C#. It has a Node object, which (obviously) represents every node in the list.
我用 C# 编写了一个基本的链表类。它有一个 Node 对象,它(显然)代表列表中的每个节点。
The code does not use IEnumerable, however, can I implement a sorting function? The language I am using is C#. Is there an example of this in C#?
代码没有使用IEnumerable,但是可以实现排序功能吗?我使用的语言是 C#。C# 中有这样的例子吗?
I am working from this sample:
我正在从这个样本工作:
Thanks
谢谢
回答by unwind
Of course you can implement a sorting function using a plain linked list. Merge sortmight be a suitable algorithm to try, it's fairly simple.
当然,您可以使用普通链表来实现排序功能。合并排序可能是一种适合尝试的算法,它相当简单。
回答by Marc Gravell
The simplest option is probably to extract the data, sort it in a mechanism that already supports sorting (arrays, List<T>or IEnumerable<T>via LINQ), and re-build the linked list with the sorted data.
最简单的选择可能是提取数据,在已经支持排序(数组,List<T>或IEnumerable<T>通过 LINQ)的机制中对其进行排序,然后用排序后的数据重新构建链表。
If you want to write your own sort algorithm, then you may find Comparer<T>.Defaultuseful (assuming you are using generics). This should allow you to compare any items that are IComparable<T>or IComparable.
如果您想编写自己的排序算法,那么您可能会发现它Comparer<T>.Default很有用(假设您使用的是泛型)。这应该允许您比较任何项目IComparable<T>或IComparable。
As an aside - note that .NET already includes LinkedList<T>etc; if this is just for learning etc, then fine ;-p
顺便说一句 - 请注意,.NET 已经包含LinkedList<T>等;如果这只是为了学习等,那很好;-p
回答by Jules
Functional Quicksort and Mergesort
函数式快速排序和合并排序
Here's a linked list with quicksort and mergesort methods written in a functional style:
这是一个以函数式风格编写的带有快速排序和归并排序方法的链表:
class List
{
public int item;
public List rest;
public List(int item, List rest)
{
this.item = item;
this.rest = rest;
}
// helper methods for quicksort
public static List Append(List xs, List ys)
{
if (xs == null) return ys;
else return new List(xs.item, Append(xs.rest, ys));
}
public static List Filter(Func<int,bool> p, List xs)
{
if (xs == null) return null;
else if (p(xs.item)) return new List(xs.item, Filter(p, xs.rest));
else return Filter(p, xs.rest);
}
public static List QSort(List xs)
{
if (xs == null) return null;
else
{
int pivot = xs.item;
List less = QSort(Filter(x => x <= pivot, xs.rest));
List more = QSort(Filter(x => x > pivot, xs.rest));
return Append(less, new List(pivot, more));
}
}
// Helper methods for mergesort
public static int Length(List xs)
{
if (xs == null) return 0;
else return 1 + Length(xs.rest);
}
public static List Take(int n, List xs)
{
if (n == 0) return null;
else return new List(xs.item, Take(n - 1, xs.rest));
}
public static List Drop(int n, List xs)
{
if (n == 0) return xs;
else return Drop(n - 1, xs.rest);
}
public static List Merge(List xs, List ys)
{
if (xs == null) return ys;
else if (ys == null) return xs;
else if (xs.item <= ys.item) return new List(xs.item, Merge(xs.rest, ys));
else return new List(ys.item, Merge(xs, ys.rest));
}
public static List MSort(List xs)
{
if (Length(xs) <= 1) return xs;
else
{
int len = Length(xs) / 2;
List left = MSort(Take(len, xs));
List right = MSort(Drop(len, xs));
return Merge(left, right);
}
}
public static string Show(List xs)
{
if(xs == null) return "";
else return xs.item.ToString() + " " + Show(xs.rest);
}
}
Functional heapsort using a Pairing Heap
使用配对堆的函数式堆排序
Bonus: heapsort (using functional pairing heap).
奖励:堆排序(使用功能配对堆)。
class List
{
// ...
public static Heap List2Heap(List xs)
{
if (xs == null) return null;
else return Heap.Merge(new Heap(null, xs.item, null), List2Heap(xs.rest));
}
public static List HSort(List xs)
{
return Heap.Heap2List(List2Heap(xs));
}
}
class Heap
{
Heap left;
int min;
Heap right;
public Heap(Heap left, int min, Heap right)
{
this.left = left;
this.min = min;
this.right = right;
}
public static Heap Merge(Heap a, Heap b)
{
if (a == null) return b;
if (b == null) return a;
Heap smaller = a.min <= b.min ? a : b;
Heap larger = a.min <= b.min ? b : a;
return new Heap(smaller.left, smaller.min, Merge(smaller.right, larger));
}
public static Heap DeleteMin(Heap a)
{
return Merge(a.left, a.right);
}
public static List Heap2List(Heap a)
{
if (a == null) return null;
else return new List(a.min, Heap2List(DeleteMin(a)));
}
}
For actual use you want to rewrite the helper methods without using recursion, and maybe use a mutable list like the built-in one.
对于实际使用,您希望在不使用递归的情况下重写辅助方法,并且可能使用像内置列表那样的可变列表。
How to use:
如何使用:
List xs = new List(4, new List(2, new List(3, new List(1, null))));
Console.WriteLine(List.Show(List.QSort(xs)));
Console.WriteLine(List.Show(List.MSort(xs)));
Console.WriteLine(List.Show(List.HSort(xs)));
Imperative In-place Quicksort for linked lists
链接列表的命令式就地快速排序
An in-place version was requested. Here's a very quick implementation. I wrote this code top to bottom without looking for opportunities to make the code better, i.e. every line is the first line that came to mind. It's extremely ugly because I used null as the empty list :) The indentation is inconsistent, etc.
已请求就地版本。这是一个非常快速的实现。我从头到尾写了这段代码,没有寻找机会让代码变得更好,即每一行都是我想到的第一行。这非常难看,因为我使用 null 作为空列表 :) 缩进不一致等。
Additionally I tested this code on only one example:
此外,我仅在一个示例上测试了此代码:
MList ys = new MList(4, new MList(2, new MList(3, new MList(1, null))));
MList.QSortInPlace(ref ys);
Console.WriteLine(MList.Show(ys));
Magically it worked the first time! I'm pretty sure that this code contains bugs though. Don't hold me accountable.
神奇的是,它第一次就成功了!我很确定这段代码包含错误。不要追究我的责任。
class MList
{
public int item;
public MList rest;
public MList(int item, MList rest)
{
this.item = item;
this.rest = rest;
}
public static void QSortInPlace(ref MList xs)
{
if (xs == null) return;
int pivot = xs.item;
MList pivotNode = xs;
xs = xs.rest;
pivotNode.rest = null;
// partition the list into two parts
MList smaller = null; // items smaller than pivot
MList larger = null; // items larger than pivot
while (xs != null)
{
var rest = xs.rest;
if (xs.item < pivot) {
xs.rest = smaller;
smaller = xs;
} else {
xs.rest = larger;
larger = xs;
}
xs = rest;
}
// sort the smaller and larger lists
QSortInPlace(ref smaller);
QSortInPlace(ref larger);
// append smaller + [pivot] + larger
AppendInPlace(ref pivotNode, larger);
AppendInPlace(ref smaller, pivotNode);
xs = smaller;
}
public static void AppendInPlace(ref MList xs, MList ys)
{
if(xs == null){
xs = ys;
return;
}
// find the last node in xs
MList last = xs;
while (last.rest != null)
{
last = last.rest;
}
last.rest = ys;
}
public static string Show(MList xs)
{
if (xs == null) return "";
else return xs.item.ToString() + " " + Show(xs.rest);
}
}
回答by baash05
This might not be the best solution, but it's as simple as I can come up with. If anyone can think of something simpler but still fast, I'd love to hear it.
SORRY THAT IT'S C++ it should translate.
这可能不是最好的解决方案,但它就像我能想到的一样简单。如果有人能想到更简单但仍然很快的东西,我很乐意听到。
抱歉,它是 C++,它应该翻译。
List * SortList(List * p_list)
{
if(p_list == NULL || p_list->next == NULL)
return p_list;
List left, right;
List * piviot = p_list;
List * piviotEnd = piviot;
List * next = p_list->next;
do
{
p_list = next;
next = next->next;
//FIGURE OUT WHICH SIDE I'M ADDING TO.
if(p_list->data > piviot->data )
right.InsertNode(p_list);
else if(p_list->data < piviot->data)
left.InsertNode(p_list);
else
{ //we put this in it's own list because it doesn't need to be sorted
piviotEnd->next = p_list;
piviotEnd= p_list;
}
}while(next);
//now left contains values < piviot and more contains all the values more
left.next = SortList(left.next);
right.next = SortList(right.next);
//add the piviot to the list then add the rigth list to the full list
left.GetTail()->next = piviot;
piviotEnd->next = right.next;
return left.next;
}
回答by Aqib Saeed
for(int i=0; i<counter;i++)
{
while(current.next!=null)
{
if(current.elemen>current.next.element)
{
Swap(current.elment,current.next.element);
}
current=current.next;
}
}
increment counter when you add or insert elements to your linked lists
向链表添加或插入元素时增加计数器
回答by Dotan
If you want to really utilize the fact that you're using a linked list, as opposed to working around it, I would suggest insertion sort.
如果你想真正利用你正在使用链表的事实,而不是解决它,我会建议插入排序。
Normally an insertion sort is not very efficient - O(n^2)in the worst case, but with linked list this can be improved to O(n log n)
通常插入排序的效率不是很高——O(n^2)在最坏的情况下,但对于链表,这可以改进为O(n log n)
pseudo:
伪:
for i in range (1,n):
item = arr[i]
location = binary_search(l=root, r=i, value=item.val) // O(log i)
insert_item_before(arr[location], item) // O(1)
In the regular algorithm the insert part takes O(i)because we may need to shift all the items that are larger then item. because a linked list enables us to do the insertion without shifting, we can search for the location with a binary search and so the insertion part takes only O(log i)
在常规算法中,插入部分采用,O(i)因为我们可能需要移动所有比 大的项目item。因为链表使我们能够在不移位的情况下进行插入,所以我们可以使用二分查找来搜索位置,因此插入部分只需要O(log i)
note: usually an insertion sort has O(n)performance in the best case (if the array is sorted). Unfortunately this isn't the case here because binary search takes always O(log n)steps.
注意:通常插入排序O(n)在最好的情况下具有性能(如果数组已排序)。不幸的是,这里的情况并非如此,因为二进制搜索总是需要O(log n)步骤。
回答by Nikolai Nechai
public LinkedListNode<int> Sort2(LinkedListNode<int> head, int count)
{
var cur = head;
var prev = cur;
var min = cur;
var minprev = min;
LinkedListNode<int> newHead = null;
LinkedListNode<int> newTail = newHead;
for (int i = 0; i < count; i++)
{
cur = head;
min = cur;
minprev = min;
while (cur != null)
{
if (cur.Value < min.Value)
{
min = cur;
minprev = prev;
}
prev = cur;
cur = cur.Next;
}
if (min == head)
head = head.Next;
else if (min.Next == null)
minprev.Next = null;
else
minprev.Next = minprev.Next.Next;
if (newHead != null)
{
newTail.Next = min;
newTail = newTail.Next;
}
else
{
newHead = min;
newTail = newHead;
}
}
return newHead;
}
回答by M.kazem Akhgary
Some people (including me) may have wanted to sort LinkedList<T>from .net library.
有些人(包括我)可能想从 .net 库中排序LinkedList<T>。
The easy way is to use Linq, sort and finally create a new linked list. but this creates garbage. for small collections it would not be a problem, but for large collections it may not be so efficient.
简单的方法是使用 Linq,排序并最终创建一个新的链表。但这会产生垃圾。对于小型集合,这不是问题,但对于大型集合,它可能不那么有效。
for people who want some degree of optimization, here is generic In-place quick sort implementation for .net doubly linked list.
对于想要某种程度优化的人,这里是 .net 双向链表的通用就地快速排序实现。
this implementation does not split/merge, instead it checks nodes for boundaries of each recursion.
此实现不会拆分/合并,而是检查节点以查找每个递归的边界。
/// <summary>
/// in place linked list sort using quick sort.
/// </summary>
public static void QuickSort<T>(this LinkedList<T> linkedList, IComparer<T> comparer)
{
if (linkedList == null || linkedList.Count <= 1) return; // there is nothing to sort
SortImpl(linkedList.First, linkedList.Last, comparer);
}
private static void SortImpl<T>(LinkedListNode<T> head, LinkedListNode<T> tail, IComparer<T> comparer)
{
if (head == tail) return; // there is nothing to sort
void Swap(LinkedListNode<T> a, LinkedListNode<T> b)
{
var tmp = a.Value;
a.Value = b.Value;
b.Value = tmp;
}
var pivot = tail;
var node = head;
while (node.Next != pivot)
{
if (comparer.Compare(node.Value, pivot.Value) > 0)
{
Swap(pivot, pivot.Previous);
Swap(node, pivot);
pivot = pivot.Previous; // move pivot backward
}
else node = node.Next; // move node forward
}
if (comparer.Compare(node.Value, pivot.Value) > 0)
{
Swap(node, pivot);
pivot = node;
}
// pivot location is found, now sort nodes below and above pivot.
// if head or tail is equal to pivot we reached boundaries and we should stop recursion.
if (head != pivot) SortImpl(head, pivot.Previous, comparer);
if (tail != pivot) SortImpl(pivot.Next, tail, comparer);
}

