【问题标题】:How to get O(n log(n)) from merge sort?如何从归并排序中获得 O(n log(n))?
【发布时间】:2016-02-15 10:14:21
【问题描述】:

如何知道我是否在链表上的合并排序实现中使用了 O(nlog(n))。我应该向 O(nlog(n)) 输入什么来知道我在合并排序上的实现时间。

public static LinkedListNode<T> MergeSortLL<T>(LinkedListNode<T> Head) where T : IComparable<T>
{

    if (Head?.Next == null)
    {
        return Head;
    }
    var middle = GetMiddle(Head);
    var half = middle.Next;
    middle.Next = null;

    Head = Merge(MergeSortLL(Head), MergeSortLL(half));
    return Head;
}

public static LinkedListNode<T> Merge<T>(LinkedListNode<T> Left, LinkedListNode<T> Right) where T : IComparable<T>
{

    var mHead = new LinkedListNode<T>(default(T));
    LinkedListNode<T> curr = mHead;

    while (Left != null && Right != null)
    {
        if (Left.Value.CompareTo(Right.Value) <= 0)
        {
            curr.Next = Left;
            Left = Left.Next;
        }
        else
        {
            curr.Next = Right;
            Right = Right.Next;
        }
        curr = curr.Next;
    }
    curr.Next = (Left == null) ? Right : Left;

    return mHead.Next;
}

public static LinkedListNode<T> GetMiddle<T>(LinkedListNode<T> Head) where T : IComparable<T>
{
    if (Head == null)
    {
        return Head;
    }

    LinkedListNode<T> slow, fast;
    slow = fast = Head;

    while (fast.Next?.Next != null)
    {
        slow = slow.Next;
        fast = fast.Next.Next;
    }
    return slow;
}

【问题讨论】:

  • 你需要分析你的算法。与 N=256 相比,您将循环遍历 N=16 的排序代码多少次?
  • 例如,我的列表中有 100 个元素,我需要知道它将通过 O(n*log(n)) 循环多少次。
  • O(n*log(n)) 是一个近似值,而不是计算您的方法将循环的 精确 次的函数。见:stackoverflow.com/questions/3255/…
  • Wiki 有一个自下而上的链表排序示例,它避免了扫描列表以找到列表的中间部分。 wiki linked list sort。 wiki 示例类似于 Microsoft C++ STL 如何实现 std::list::sort。

标签: c# algorithm sorting mergesort


【解决方案1】:

请注意,已知此算法执行 O(N*log(N))比较。如果您想确认这一点(因为它已被证明),您可以放置​​一个计数器并在每次比较时将其递增。

例如

public static int Comparisons;

public static LinkedListNode<T> Merge<T>(LinkedListNode<T> Left, LinkedListNode<T> Right) where T : IComparable<T>
{
    // ...
    Comparisons++;
    if (Left.Value.CompareTo(Right.Value) <= 0)
    // ...
}

检查一下

LinkedListNode<int> head = ...;
Comparisons = 0;
head = MergeSortLL(head);
Debug.Print(Comparisons);

但请注意,这种算法也有显着的隐藏成本(即使使用慢/快指针技术,也要找到中间)。

【讨论】:

  • 所以我需要增加 2 个 while 循环(在合并方法和 GetMiddle 中),然后,我需要比较 n*log(n) 的比较值和结果。我说的对吗?
  • 糟糕,我复制了错误的方法。我的意思是增加发生Compare 的方法中的计数。
【解决方案2】:

您可以做的是向您的排序方法添加一个计数器参数(引用),并在每次进入循环时递增它。然后将此计数器与您尝试排序的元素数量的复杂性进行比较(我们称该数量为 N)。然后你会看到你是在 O(NlogN) 中更多还是在 O(N²) 中更多。


例如,如果您的计数器在尝试对 N =10 个元素进行排序时为 30,则为 10*log(10) = 23,02... 和 10² = 100 你会发现你在 O(NlogN) 中比在 O(N²) 中更多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 2012-06-24
    • 2015-07-06
    • 1970-01-01
    相关资源
    最近更新 更多