Algorithm 对单个链接列表排序
如何对单个链接列表进行排序。 (这里的问题是单一属性+使用LinkedList进行排序比数组更难) 我想看看伪代码 尽量使它在时间和空间上都尽可能有效Algorithm 对单个链接列表排序,algorithm,sorting,Algorithm,Sorting,如何对单个链接列表进行排序。 (这里的问题是单一属性+使用LinkedList进行排序比数组更难) 我想看看伪代码 尽量使它在时间和空间上都尽可能有效 谢谢 插入排序和快速排序都可以在单个链表上进行,其效率与在数组上相同。由于链表只是由其他项指向的多个项组成,所以您可以构造一个具有O(n)时间和O(n)空间的指针数组,使用任何具有O(n)空间的优秀排序算法进行排序(n logn)时间和O(1)空间,然后用O(n)时间和O(1)空间从头开始重建链表 总的来说,这就是O(n log n)时间和O(n
谢谢 插入排序和快速排序都可以在单个链表上进行,其效率与在数组上相同。由于链表只是由其他项指向的多个项组成,所以您可以构造一个具有O(n)时间和O(n)空间的指针数组,使用任何具有O(n)空间的优秀排序算法进行排序(n logn)时间和O(1)空间,然后用O(n)时间和O(1)空间从头开始重建链表
总的来说,这就是O(n log n)时间和O(n)空间。我相信通过就地快速排序可以做到这一点。
我错了。这对单链接列表不起作用,因为in需要能够在列表中后退。 因此,真正的问题是如何进行就地快速排序 我们走吧 1) 将指针指向链表的第一个、第二个和最后一个术语。
2) 用第二个指针在列表中单步移动,直到找到比第一个词大的词。
3) 在列表中向后移动第三个指针,直到找到一个小于第一个的项此步骤不适用于单链接列表。
4) 交换第二个和第三个指针的值。
5) 重复步骤2)到5),直到第二个指针和第三个指针相等。
6) 在第二个指针后插入第一个项 -此时,链接列表分为:
[小于x的条款]x[大于x的条款] 7) 对[terms小于x]和[terms大于x]重复步骤2)到7),直到[terms_______;小于x]块的大小为一 空间:每层3个指针。
O(对数(n)) 时间:与快速排序相同
O(n log(n))通常
O(n*n)在最坏的情况下(如果列表已经排序或顺序相反)
为格式化和愚蠢而编辑我一直在思考这个问题,我认为使用合并排序可以实现O(n log(n))时间和O(1)空间条件 让我们看看……
以列表为例:
3->2->1->5->6->4 第一关:
为第一个、第二个和第三个术语设置指针
将第一个指针和第二个指针之间的较小项设置为指向较大项。
将两个术语中的最后一个术语设置为指向原始列表的其余部分。
重复此操作直到列表结束。
2->3->1->5->4->6 此时,每对术语都是有序的 第n遍:
设置指向第1个、(2^(N-1))项和第(2^(N))项+1项的指针
取值较小的节点并增加其指针。
重复此过程,直到两个列表(长度为2^N)都用尽,每次都将较小值的节点追加到前一个较小值的节点。
将指针设置为原始列表的其余部分。
重复此操作,直到列表结束 第0次通过:3->2->1->5->6->4(1个术语的每个区块都是有序的)(平凡的)
第一次通过:2->3->1->5->4->6(每一块2个术语都被订购)
第二遍:1->2->3->5->4->6(每一块4个术语都被订购)
第三遍:1->2->3->4->5->6(每一块8个术语都已排序) 时间:记录(n)个过程,每个过程有n个比较。
O(n对数(n)) 空格:指针和整数变量
O(1)合并排序只涉及几个简单的步骤:
import Data.List(splitAt)
--Mergesorts a list by smallest element first.
sort :: Ord a => [a] -> [a]
sort = sortBy (<)
--Generic sort that can sort in any order.
sortBy :: (a -> a -> Bool) -> [a] -> [a]
sortBy _ [] = []
sortBy _ [x] = [x]
sortBy f xs = merge f (sortBy f first) (sortBy f second)
where
(first,second) = split xs
--Splits a list in half.
split :: [a] -> ([a],[a])
split xs = splitAt (halfLength xs) xs
--Returns a lists length divided by two as a whole number (rounded).
halfLength :: [a] -> Int
halfLength = round . (/2) . fromIntegral . length
--Merges two lists in the provided order.
merge :: (a -> a -> Bool) -> [a] -> [a] -> [a]
merge _ [] [] = []
merge _ [] (y:ys) = y:ys
merge _ (x:xs) [] = x:xs
merge f (x:xs) (y:ys) =
if f x y
then x : merge f xs (y:ys)
else y : merge f (x:xs) ys
导入数据列表(splitAt)
--merge首先按最小元素对列表排序。
排序::Ord a=>[a]->[a]
排序=排序方式(a->Bool)->[a]->[a]
sortBy[]=[]
排序比ux]=[x]
sortBy f xs=合并f(sortBy f first)(sortBy f second)
哪里
(第一,第二)=拆分X
--将列表一分为二。
拆分::[a]->([a],[a])
拆分xs=拆分(半长xs)xs
--返回列表长度除以2的整数(四舍五入)。
半长度::[a]->Int
半长=圆形。(/2) . 从积分。长度
--按提供的顺序合并两个列表。
合并::(a->a->Bool)->[a]->[a]->[a]->[a]
合并[][]=[]
合并[](y:ys)=y:ys
合并ux(x:xs)[]=x:xs
合并f(x:xs)(y:ys)=
如果f×y
然后x:merge f xs(y:ys)
else y:merge f(x:xs)ys
家庭作业?如果是这样的话,请说明你到目前为止已经走了多远。谢谢你的快速回答,你能解释一下吗?似乎这些排序使用随机访问属性以实现效率,例如在合并排序中,您将如何访问列表的中间部分?您必须运行n/2 stepsQuicksort,但不能以与数组相同的效率在单链表上运行。@incrediman:为什么不能?从列表中选取第一个作为轴心,然后遍历其余部分,构建两个新列表。将这两个列表排序。把它们拼接在一起。实际上,使用链表比使用数组更容易。(我承认mergesort是错的)不过拼接O(n)不是吗?如果没有,您必须跟踪列表中每个列表的长度,这当然也不会有效率。如果您可以用伪代码为单链接列表编写一个快速排序实现,演示其效率如何与数组上的快速排序相同,这将非常有用。*您必须跟踪