对链表进行排序

Gur*_*epS 10 c# algorithm linked-list data-structures

我在C#中编写了一个基本的链表类.它有一个Node对象,它(显然)代表列表中的每个节点.

代码不使用IEnumerable,但是,我可以实现排序功能吗?我使用的语言是C#.在C#中有这样的例子吗?

我正在使用这个样本:

谢谢

Jul*_*les 22

功能性Quicksort和Mergesort

这是一个链接列表,其中包含以函数样式编写的quicksort和mergesort方法:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用配对堆的功能性堆

奖励:heapsort(使用功能配对堆).

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)));
    }
}
Run Code Online (Sandbox Code Playgroud)

对于实际使用,您希望在不使用递归的情况下重写辅助方法,并且可能使用类似内置的可变列表.

如何使用:

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)));
Run Code Online (Sandbox Code Playgroud)

链表的势在必行的Quicksort

要求提供就地版本.这是一个非常快速的实现.我从上到下编写了这段代码而没有寻找使代码更好的机会,即每一行都是我想到的第一行.这非常难看,因为我使用null作为空列表:)缩进是​​不一致的等等.

另外,我只在一个例子中测试了这段代码:

        MList ys = new MList(4, new MList(2, new MList(3, new MList(1, null))));
        MList.QSortInPlace(ref ys);
        Console.WriteLine(MList.Show(ys));
Run Code Online (Sandbox Code Playgroud)

神奇地它第一次工作!我很确定这段代码包含错误.不要让我负责.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


unw*_*ind 10

当然,您可以使用纯链接列表实现排序功能.合并排序可能是一种合适的算法,它非常简单.


Mar*_*ell 5

最简单的选择可能是提取数据,在已经支持排序(数组List<T>IEnumerable<T>通过LINQ)的机制中对其进行排序,并使用排序数据重新构建链接列表.

如果你想编写自己的排序算法,那么你可能会觉得Comparer<T>.Default有用(假设你使用的是泛型).这应该允许您比较IComparable<T>或的任何项目IComparable.

另外请注意.NET已包含LinkedList<T>等; 如果这只是为了学习等,那么很好;-p

  • 我支持我对 baash05 的回复:回复你的评论“我怀疑说使用 STL 就足够了”——在面试时,我会质疑那些“没有”选择使用预装 BCL 而不具备良好的能力的人的理智。原因。OP 没有说明原因,因此 BCL 应该是默认值。 (2认同)

M.k*_*ary 5

有些人(包括我)可能想LinkedList<T>从 .net 库中进行排序。

最简单的方法是使用 Linq,排序并最终创建一个新的链表。但这会产生垃圾。对于小型集合,这不会是问题,但对于大型集合,它可能不会那么有效。

对于想要一定程度优化的人,这里是 .net 双向链表的通用就地快速排序实现。

此实现不会拆分/合并,而是检查节点的每个递归的边界。

/// <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);
}
Run Code Online (Sandbox Code Playgroud)