`
liuxinyu95
  • 浏览: 31047 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Natural merge sort

阅读更多
通常我们见到的merge sort的思路是典型的分而治之divide and conquer策略:
1. 如果待排序序列为空,或者只有1个元素,结束
2. 否则,将序列一分为二,将两个子序列分别merge sort,再将两个排好的子序列merge

我们也可以从另外一个角度出发,序列中存在一些已经排好的片段,我们可以把这些排好的片段merge起来,不断重复直到序列排好(只含有一个排好的片段,亦即整个序列)
这种思路叫做natural merge sort。

例如下面的Haskell代码:
mergesort' = foldl merge [] . groupBy' (<=)

其中merge的实现非常简单:
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) | x < y = x : merge xs (y:ys)
                    | otherwise = y : merge (x:xs) ys

早期的Haskell 标准库中的groupBy (<=) xs可以把xs分成若干已序的小片段,例如:
groupBy (<=) [1, 5, 2, 7, 8, 10] 的结果是 [[1, 5], [2, 7], [8, 10]]

但是最新的标准库这样不可以了,原因是groupBy 接受一个用于判断相等的函数,相等必须满足:自反性、传递性和对称性
亦即:
x = x
x = y, y = z 则 x = z
x = y 则 y = x

而小于等于显然不满足。故而我写了一个groupBy',用于切割已序片段:
                               
groupBy' :: (a->a->Bool) ->[a] ->[[a]]
groupBy' _ [] = [[]]
groupBy' _ [x] = [[x]]
groupBy' f (x:xs@(x':_)) | f x x' = (x:ys):yss
                         | otherwise = [x]:r
  where
    r@(ys:yss) = groupBy' f xs

注意,这个算法可以近一步提高。我们遍历已序序列,不断使用merge,其实我们可以针对已序序列,两两merge,然后对其结果在迭代地两两merge,
这就是典型的bottom up merge sort的思路,算法改进如下:

mergesort = concat . mergePairs . groupBy' (<=) where
  mergePairs (xs:ys:xss) = mergePairs ((merge xs ys) : (mergePairs xss))
  mergePairs xss = xss

D. Knuth在TAOCP(计算机程序设计艺术)中,给出的略有不同,是一种2-way natural merge sort,思路有些类似quick sort
我们同时从一个序列的头部和尾部向中间检查:
1.  从头部取出一个最长的升序子序列;
2.  从尾部取出一个最长的降序子序列;
3.  将结果merge到一个目标序列的头部,然后重复1, 2,下次将结果merge到目标序列的尾部
4.  重复1, 2, 3,直到待排序序列已序(从头部取出的最长升序序列,就是整个序列)

相应的python代码如下:
https://github.com/liuxinyu95/AlgoXY/blob/algoxy/sorting/merge-sort/src/n2_merge_sort.py

C代码:
https://github.com/liuxinyu95/AlgoXY/blob/algoxy/sorting/merge-sort/src/n2_merge_sort.c

全部源代码可以在github下载。
https://github.com/liuxinyu95/AlgoXY/blob/algoxy/sorting/merge-sort/src/NMergeSort.hs


PS: 我们不讨论merge sort的优劣或者和Quick sort PK, 具体讨论可参见wikipedia
http://en.wikipedia.org/wiki/Merge_sort
分享到:
评论
1 楼 maakey 2013-01-26  
[u]
引用
引用
  • [img][url][/url][/img]
[/u]

相关推荐

    排列问题再讨论

    注意前面有“Insert sort:”或“Natural merge sort:”或“Quick sort:”等输出前缀,格式以上文程序为准。 输入样例 9 3 5 2 1 7 8 1 5 9 8 5 2 1 7 3 1 5 9 5 9 2 1 7 8 1 3 5 输出样例 Insert sort: 1 1 2 ...

    带有不减序和降序子序列的外部自然合并排序的Work C ++算法

    外部排序(External Sort)是处理这类问题的关键技术,而自然合并排序(Natural Merge Sort)则是一种高效的外部排序方法。 自然合并排序是一种基于比较的排序算法,它利用了数据的局部有序性。在实际的数据集中,...

    Algorithms and Data Structures - Niklaus Wirth

    - **Polyphase Sort**: A variant of merge sort designed for external sorting. - **Distribution of Initial Runs**: Analysis of initial runs in sorting sequences. #### Recursive Algorithms **...

    grasshopper运算器名称总结.pdf

    * Natural logarithm: 自然对数 * Pi: 圆周率 * Interval: 区间 * Bounds: 界限 * Bounds 2D: 二维界限 * Divide Interval: 均分区间 * Divide Interval2: 均分二维区间 * Interval Components: 分解一维区间 * ...

    grasshopper中文版运算器名称对照翻译.pdf

    9. **Trees** 类运算器涉及到数据树的构建和操作,包括 `Clean Tree` 清理无效数据,`Create Branch` 创建分支路径,`Flatten Tree` 展平数据树,`Merge` 和 `Merge Multiple` 合并数据流,以及 `Simplify Tree` ...

    grasshopper运算器名称总结[汇编].pdf

    设计树(Trees)运算器则用于管理复杂的数据结构,如“Clean Tree”清理无效数据,“Create Branch”创建分支,“Decompose Branch”分解分支,“Flatten Tree”扁平化设计树,“Graft Tree”续接设计树,“Merge”...

    grasshopper中文版运算器名称对照页.pdf

    13. **Scalars** (标量) 和 **Constants** (常数):涉及基本的数学常量和运算,如**Epsilon** (四舍五入双精度浮点数)、**Golden Ratio** (黄金分割比)、**Natural logarithm** (自然对数) 和 **Pi** (圆周率)。...

    np-java8-tutorial:NaturalProgrammer.com的Java 8教程的源代码-java source code

    - **方法引用**:允许直接引用已有方法,如`list.sort(Comparator.naturalOrder());` - **构造器引用**:可以使用`ClassName::new`来直接引用类的构造器,简化对象创建。 3. **默认方法** - 接口中新增了默认...

    java8-examples

    例如,`Collections.sort(list, Comparator.naturalOrder())`。 5. **日期和时间 API**: Java 8 引入了 `java.time` 包,替换了旧的 `java.util.Date` 和 `java.util.Calendar`,提供了更直观、更强大的日期和...

    COVID19_pandemic_data

    world_map = world_map.merge(country_totals, left_on='name', right_on='Country') plt.figure(figsize=(12, 6)) sns.set(style="whitegrid") sns.scatterplot( x="longitude", y="latitude", hue="Confirmed",...

Global site tag (gtag.js) - Google Analytics