【问题标题】:Implementing natural mergesort on a linked list in situ and only interchanging items from nodes在原位链表上实现自然归并排序,并且只交换来自节点的项目
【发布时间】:2019-09-26 14:13:49
【问题描述】:

我必须在链表上实现自然归并排序(这很容易),但我不能更改节点的“下一个”属性,只能交换它们的值。我也不能倒退,因为节点没有“prev”属性。 (链表没有随机访问)而且我无法创建新节点。

我只需要一些关于合并功能应该如何的提示。

我知道在合并之前保持两个子列表有序是关键,但我找不到方法。

这是 Node 类。他们保存了一个通用的 Item 和下一个节点的地址

private class Node {
    Item item;
    Node next;

    public String toString() {
        if (next == null) return "[" + item + "]" + "->" + "null";
        return "[" + item + "]" + "->" + next.item + ", ";
    }
}

【问题讨论】:

  • @user3386109 原位合并排序实现非常简单,而且非常漂亮。再速度,算是值得成为STL的一部分了。
  • @user3386109 inplace_merge
  • @user58697 嗯,好的,谢谢,我想是时候再看看了。
  • @user3386109 看我的回答

标签: java algorithm sorting linked-list mergesort


【解决方案1】:

要获得灵感,请查看 STL 的 inplace_sort 实现。该算法的核心部分是巧妙的旋转。当然它需要向后遍历,你可以通过递归来实现。

简而言之,合并部分是沿线

    merge (begin, mid, end)
        left_mid = middle(begin, mid)
        right_mid = lower_bound(left_mid.value, mid, end)
        pivot = rotate(left_mid, mid, right_mid)
        merge(left, left_mid, pivot)
        merge(pivot, right_mid, end)

pivot 上面是初始begin 登陆的节点。为简洁起见,省略了递归。

【讨论】:

  • 有一个 std::inplace_merge,但它使用缓冲区。就地只是意味着合并的结果将与输入参数在同一个容器中。
  • 如果通过递归完成反向旋转,将需要 O(n) 堆栈空间,此时,代码还不如使用指向节点的指针数组并通过指针数组进行排序。
  • @rcgldr 恐怕你弄错了。如果可用,它可以使用缓冲区,但这不是必需的。但是需要对数堆栈空间。通过反转实现的旋转很容易实现,但同样,经典的 Dijkstra 旋转根本不需要额外的空间。
  • 我查看了 Visual Studio 的 std::inplace_merge 实现中的代码,如果它未能分配缓冲区,它会继续尝试更小的大小。一旦获得缓冲区,它就会根据最终分配的缓冲区大小将合并拆分为更小的部分。
  • 查看c++ std::inplace_merge,在异常下它声明“如果算法分配内存失败,则抛出std::bad_alloc。”
【解决方案2】:

这需要某种类型的就地排序,此时它不再是自然合并排序,充其量是某种混合类型。除非代码计划通过 | 实现交换。 A = A xor B | B = A xor B | A = A xor B |,代码将需要一个临时节点来实现交换。如果不使用临时节点,旋转将是一个问题。

如果您需要稳定性,块合并排序将起作用,但需要扫描列表以找到用作工作区的唯一值,这是一种相当复杂的算法,最近对该算法进行了改进,例如圣杯排序。

https://en.wikipedia.org/wiki/Block_sort

https://github.com/Mrrl/GrailSort

如果不需要稳定性,可以使用更简单的递归算法

How to sort in-place using the merge sort algorithm?

自然合并排序如何适应这一点尚不清楚。通常自然归并排序是使用自然游程长度的自下而上归并。高效的就地合并排序算法需要根据运行大小将列表的一部分用作工作区,这需要在扫描列表时使用计数器来确定运行大小或设置工作区的边界。

【讨论】:

    猜你喜欢
    • 2016-09-11
    • 2012-05-03
    • 2016-06-07
    • 2021-09-26
    • 2015-06-10
    • 2019-07-29
    • 1970-01-01
    • 2018-04-07
    • 1970-01-01
    相关资源
    最近更新 更多