我被要求编写一个函数,它接受3个未排序的链表,并返回一个单一的已排序的链表,将所有三个链表组合起来。你能想到最好的方法是什么?
我没有内存限制,但在有/没有内存限制的情况下,你会怎么做?
我被要求编写一个函数,它接受3个未排序的链表,并返回一个单一的已排序的链表,将所有三个链表组合起来。你能想到最好的方法是什么?
我没有内存限制,但在有/没有内存限制的情况下,你会怎么做?
你可以在链表上实现的另一种O(n log n)排序算法是quicksort的修改版。虽然链表版本的快速排序很快(仍然期望为O(n log n)),但由于数组元素存储在连续位置上的局部性效应缺失,它并不像作用于数组的原地版本那样快。但是,对于列表来说,这是一个非常美丽的算法。
快速排序背后的直觉如下:
链表版本的快速排序的一个好处是,分区步骤比数组情况下要容易得多。在选择枢轴之后(稍后会详细介绍),您可以通过为小于、等于和大于列表创建三个空列表,然后在线性扫描原始链表时执行分区步骤。然后,您可以将每个链接列表节点附加/预先附加到对应于原始桶的链接列表。
在使这个算法工作时,最大的挑战是选择一个好的枢轴元素。众所周知,如果选择的枢轴不好,快速排序会退化为O(n^2)时间复杂度,但是如果随机选择枢轴元素,则运行时间具有高概率的O(nlogn)。在数组中,这很容易(只需选择一个随机的数组索引),但在链表情况下则更加棘手。最简单的方法是在0到列表长度之间选择一个随机数,然后在O(n)时间内选择该列表元素。此外,还有一些非常酷的方法可以从链表中随机选择一个元素;其中一个这样的算法在这里描述。另一个可用于链表的O(n2)排序算法是选择排序。如果你有一个双向链表,那么可以非常容易地实现这个算法:
这个算法的时间复杂度也是O(n2),但它只使用了O(1)的空间,但在实践中它比插入排序要慢;特别地,它总是需要Θ(n2)的时间。
这个算法在最好情况下以 O(n log n) 的时间复杂度运行,在最坏情况下以 O(n2) 的时间复杂度运行。就内存使用而言,前两步只需要 O(1) 的内存,因为我们正在重复利用旧指针的空间。最后一步也可以使用一些特别聪明的算法在 O(1) 的空间中完成。
你也可以考虑以这种方式实现 堆排序,不过有点棘手。
希望这有所帮助!
如果这三个列表是单独排序的,那么问题就很简单了,但是它们没有排序,因此会稍微麻烦一些。
我会编写一个函数,该函数接受一个已排序的列表和一个未排序的列表作为参数,逐个遍历未排序列表中的每个项目,并按顺序将其添加到排序列表中的正确位置,直到未排序列表中没有项目为止。
然后简单地创建第四个“空”列表,由于它是空的,因此自然是“排序”的,然后使用每个未排序列表依次调用您的方法三次。
将列表转换为数组可能会使事情更有效率,以便能够使用更高级的排序技术,但是必须考虑将其转换为数组的成本,并与原始列表的大小进行平衡。
我认为你可以应用快速排序。它与归并排序几乎相同,唯一的区别是你首先分割然后合并,在快速排序中,你首先“合并”,然后再进行分割。如果你看起来有点不同,就是归并排序和快速排序在相反的方向上。
归并排序:
分割 -> 递归 -> 合并
快速排序:
反合并(相对于合并) -> 递归 -> 反分割(相对于分割)
@templatetypedef所描述的归并排序算法不是O(n lg n)。因为链表不是随机访问的,步骤2.1 将列表拆分为大约相等大小的两个列表
实际上意味着一个O(n^2 log n)的整体算法来对列表进行排序。仔细想一想。
这里有一个链接,使用归并排序将链表排序,首先将元素读入数组中 -- http://www.geekviewpoint.com/java/singly_linked_list/sort。
对于链表来说,没有高效的排序算法。 可以先将链表转换为数组,进行排序,再重新链接成链表。
Data.List.sort
。它的时间复杂度为O(nlogn),运行效率高。 - Thomas Eding