Sorting 自然合并对链表进行排序

Sorting 自然合并对链表进行排序,sorting,linked-list,mergesort,Sorting,Linked List,Mergesort,我一直在寻找一个自然的合并排序实现(链接列表)已经有一段时间了,但是运气不好 这里我们有递归和迭代实现,但我不知道如何将其转化为自然的合并排序 如何在最佳情况下检查运行以获得O(n)复杂性?它不必是C/C++,可以是任何语言,甚至是伪代码 谢谢。以下是一个伪代码实现: #原始数据在输入磁带上;其他磁带是空白的 函数合并排序(输入磁带、输出磁带、暂存磁带、暂存磁带) 当任何记录保留在输入磁带上时 当任何记录保留在输入磁带上时 合并(输入磁带、输出磁带、暂存磁带) 合并(输入磁带、输出磁带、暂存磁

我一直在寻找一个自然的合并排序实现(链接列表)已经有一段时间了,但是运气不好

这里我们有递归和迭代实现,但我不知道如何将其转化为自然的合并排序

如何在最佳情况下检查运行以获得O(n)复杂性?它不必是C/C++,可以是任何语言,甚至是伪代码


谢谢。

以下是一个伪代码实现:

#原始数据在输入磁带上;其他磁带是空白的
函数合并排序(输入磁带、输出磁带、暂存磁带、暂存磁带)
当任何记录保留在输入磁带上时
当任何记录保留在输入磁带上时
合并(输入磁带、输出磁带、暂存磁带)
合并(输入磁带、输出磁带、暂存磁带)
当任何记录保留在C或D上时
合并(暂存磁带C、暂存磁带D、输出磁带)
合并(临时磁带C、临时磁带D、输入磁带)
#从输入磁带中取出下一个已排序的块,并合并到单个给定的输出磁带中。
#磁带是线性扫描的。
#磁带[next]给出当前在该磁带读取头下的记录。
#磁带[当前]在该磁带的读磁头下给出先前的记录。
#(通常磁带[当前]和磁带[以前]都缓冲在RAM中…)
函数合并(左[],右[],输出带[])
做
如果左[当前]≤ 右[当前]
将左[当前]追加到输出磁带
从左侧磁带读取下一条记录
其他的
将右[当前]追加到输出\u磁带
从正确的磁带读取下一条记录
而左[当前]<左[下一步]和右[当前]<右[下一步]
如果左[当前]<左[下一步]
将当前\u左\u记录追加到输出\u磁带
如果右[当前]<右[下一步]
将当前\u右\u记录追加到输出\u磁带
返回
这是我对F#的尝试。用于参考的常规合并排序的实现:

// Sorts a list containing elements of type T.  Takes a comparison
// function comp that takes two elements of type T and returns -1
// if the first element is less than the second, 0 if they are equal,
// and 1 if the first element is greater than the second.
let rec sort comp = function 
| []  -> []  // An empty list is sorted
| [x] -> [x] // A single element list is sorted
| xs  ->
    // Split the list in half, sort both halves,
    // and merge the sorted halves.
    let half = (List.length xs) / 2
    let left, right = split half xs
    merge comp (sort comp left) (sort comp right)
现在尝试自然版本。在最好的情况下,这将是O(n),但最好的情况是当输入列表按相反顺序排序时

let rec sort' comp ls =

    // Define a helper function.  Streaks are stored in an accumulator.
    let rec helper accu = function
    | [] -> accu 
    | x::xs -> 
        match accu with
        // If we are not in a streak, start a new one
        | [] -> helper [x] xs 

        // If we are in a streak, check if x continues
        // the streak.
        | y::ys -> 
            if comp y x > 0 

            // x continues the streak so we add it to accu
            then helper (x::y::ys) xs

            // The streak is over. Merge the streak with the rest
            // of the list, which is sorted by calling our helper function on it.
            else merge comp accu (helper [x] xs)

    helper [] ls
第二次尝试。在最佳情况下,这也将是O(n),此时最佳情况是输入列表已排序时。我否定了比较函数。排序后的列表将以相反的顺序建立,因此您需要在最后将其反转

let rec sort'' comp ls =
    // Flip the comparison function
    let comp' = fun x y -> -1 * (comp x y)
    let rec helper accu = function
    | [] -> accu
    | x::xs -> 
        match accu with
        | [] -> helper [x] xs
        | y::ys -> 
            if comp' y x > 0 
            then helper (x::y::ys) xs
            else merge comp' accu (helper [x] xs)

    // The list is in reverse sorted order so reverse it.
    List.rev (helper [] ls)

我不确定什么是自然合并排序,但对于链表的合并排序,我这样写:

[Java代码]

//合并对链接列表进行排序。
//从最小到最大。
//时间复杂度=O(nlgn)。
公共静态节点mergeSortLLFromMinToMax(节点头){
if(head==null | | head.next==null)返回head;//无需排序。
//获取此链接列表的中点。
节点=头;
节点慢=头;
节点速度=头部;
while(更快!=null&&faster.next!=null){
速度较慢=较慢;
较慢=较慢。下一步;
更快=更快。下一步。下一步;
}
//主链接列表的剪切。
prev.next=null;
//执行递归。
节点左=mergeSortLLFromMinToMax(头部);
节点右侧=mergeSortLLFromMinToMax(较慢);
//将左右部分从最小值合并到最大值。
节点currHead=新节点();
节点tempCurrHead=currHead;
while(左!=null和右!=null){

if(left.data我的算法的原始实现使用C#

公共静态类LinkedListSort
{
公共静态DataStructures.Linear.LinkedListNode排序(DataStructures.Linear.LinkedListNode firstNode),其中T:IComparable
{
if(firstNode==null)
抛出新ArgumentNullException();
if(firstNode.Next==null)
返回第一个节点;
var头=第一个节点;
var leftNode=头部;
int iterNum=0;
while(leftNode!=null)
{
//让我们从头再来
leftNode=头部;
iterNum=0;
DataStructures.Linear.LinkedListNode tailNode=null;
while(leftNode!=null)
{
//让我们得到左边的子列表
//让我们找到将子列表划分为两个有序子列表的节点
var sentinelNode=GetSentinelNode(leftNode);
var rightNode=sentinelNode.Next;
//如果右节点为空,则表示没有两个子列表,左子列表已经排序
//所以我们只需将rest子列表添加到尾部
if(rightNode==null)
{
if(tailNode==null)
打破
tailNode.Next=leftNode;
打破
}
sentinelNode.Next=null;
//让我们找到右子列表结束的节点
sentinelNode=GetSentinelNode(右节点);
var restNode=sentinelNode.Next;
sentinelNode.Next=null;
DataStructures.Linear.LinkedListNode newTailNode=null;
//两个有序子列表的合并
var mergedList=Merge(leftNode、righnode、ref newTailNode);
//如果我们位于列表的开头,则合并子列表的开头将成为列表的开头
如果(iterNum==0)
head=合并列表;
else//添加
tailNode.Next=mergedList;
tailNode=newTailNode;
leftNode=restNode;
iterNum++;
}
如果(iterNum==0)
打破
}
回流头;
}
/// 
///合并两个有序子列表
/// 
/// 
///子列表的左部分
/
let rec sort'' comp ls =
    // Flip the comparison function
    let comp' = fun x y -> -1 * (comp x y)
    let rec helper accu = function
    | [] -> accu
    | x::xs -> 
        match accu with
        | [] -> helper [x] xs
        | y::ys -> 
            if comp' y x > 0 
            then helper (x::y::ys) xs
            else merge comp' accu (helper [x] xs)

    // The list is in reverse sorted order so reverse it.
    List.rev (helper [] ls)
// Merge sort the linked list.
// From min to max.
// Time complexity = O(nlgn).
public static Node mergeSortLLFromMinToMax (Node head) {
    if (head == null || head.next == null) return head; // No need to sort.
    // Get the mid point of this linked list.
    Node prevSlower = head;
    Node slower = head;
    Node faster = head;
    while (faster != null && faster.next != null) {
        prevSlower = slower;
        slower = slower.next;
        faster = faster.next.next;
    }
    // Cut of the main linked list.
    prevSlower.next = null;

    // Do recursion.
    Node left = mergeSortLLFromMinToMax (head);
    Node right = mergeSortLLFromMinToMax (slower);

    // Merge the left and right part from min to max.
    Node currHead = new Node ();
    Node tempCurrHead = currHead;
    while (left != null && right != null) {
        if (left.data <= right.data) {
            // Add the elem of the left part into main linked list.
            tempCurrHead.next = left;
            left = left.next;
        } else {
            // Add the elem of the right part into main linked list.
            tempCurrHead.next = right;
            right = right.next;
        }
        tempCurrHead = tempCurrHead.next;
    }
    if (left != null) {
        // Add the remaining part of left part into main linked list.
        tempCurrHead.next = left;
        left = left.next;
        tempCurrHead = tempCurrHead.next;
    } else if (right != null) {
        // Add the remaining part of right part into main linked list.
        tempCurrHead.next = right;
        right = right.next;
        tempCurrHead = tempCurrHead.next;
    }

    return currHead.next;
}
public static class LinkedListSort
{
    public static DataStructures.Linear.LinkedListNode<T> Sort<T>(DataStructures.Linear.LinkedListNode<T> firstNode) where T : IComparable<T>
    {
        if (firstNode == null)
            throw new ArgumentNullException();

        if (firstNode.Next == null)
            return firstNode;

        var head = firstNode;
        var leftNode = head;
        int iterNum = 0;

        while (leftNode != null)
        {
            //Let's start again from the begining
            leftNode = head;
            iterNum = 0;
            DataStructures.Linear.LinkedListNode<T> tailNode = null;

            while (leftNode != null)
            {
                //Let's get the left sublist

                //Let's find the node which devides sublist into two ordered sublists
                var sentinelNode = GetSentinelNode(leftNode);
                var rightNode = sentinelNode.Next;

                //If the right node is null it means that we don't have two sublist and the left sublist is ordered already
                //so we just add the rest sublist to the tail
                if (rightNode == null)
                {
                    if (tailNode == null)
                        break;
                    tailNode.Next = leftNode;
                    break;
                }

                sentinelNode.Next = null;

                //Let's find the node where the right sublist ends
                sentinelNode = GetSentinelNode(rightNode);
                var restNode = sentinelNode.Next;
                sentinelNode.Next = null;

                DataStructures.Linear.LinkedListNode<T> newTailNode = null;

                //Merging of two ordered sublists   
                var mergedList = Merge(leftNode, rightNode, ref newTailNode);
                //If we're at the beginning of the list the head of the merged sublist becomes the head of the list
                if (iterNum == 0)                   
                    head = mergedList;                  
                else //add the                  
                    tailNode.Next = mergedList;                     

                tailNode = newTailNode;
                leftNode = restNode;
                iterNum++;
            }
            if (iterNum == 0)
                break;
        }
        return head;
    }

    /// <summary>
    /// Merges two ordered sublists   
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="aNode">Left part of sublist</param>
    /// <param name="bNode">Right part of sublist</param>
    /// <param name="tailNode">Tail node of the merged list</param>
    /// <returns>The result of merging</returns>
    private static DataStructures.Linear.LinkedListNode<T> Merge<T>(DataStructures.Linear.LinkedListNode<T> leftNode,                                                                       
                                                                    DataStructures.Linear.LinkedListNode<T> rightNode,
                                                                    ref DataStructures.Linear.LinkedListNode<T> tailNode) where T : IComparable<T>
    {
        var dummyHead = new DataStructures.Linear.LinkedListNode<T>();
        var curNode = dummyHead;

        while (leftNode != null || rightNode != null)
        {
            if (rightNode == null)
            {
                curNode.Next = leftNode;
                leftNode = leftNode.Next;
            }
            else if (leftNode == null)
            {
                curNode.Next = rightNode;
                rightNode = rightNode.Next;
            }
            else if (leftNode.Value.CompareTo(rightNode.Value) <= 0)
            {
                curNode.Next = leftNode;
                leftNode = leftNode.Next;
            }
            else
            {
                curNode.Next = rightNode;
                rightNode = rightNode.Next;
            }
            curNode = curNode.Next;
        }
        tailNode = curNode;
        return dummyHead.Next;
    }

    /// <summary>
    /// Returns the sentinel node
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="firstNode"></param>
    /// <returns></returns>
    private static DataStructures.Linear.LinkedListNode<T> GetSentinelNode<T>(DataStructures.Linear.LinkedListNode<T> firstNode) where T : IComparable<T>
    {
        var curNode = firstNode;

        while (curNode != null && curNode.Next != null && curNode.Value.CompareTo(curNode.Next.Value) <= 0)             
            curNode = curNode.Next;

        return curNode;
    }
}