我使用的手机网络连接状况不佳,但情况依然如此。
tl;dr冒泡排序是插入排序,是对有序列表的幺半群进行合并的幺半群“粉碎”。
有序列表形成一个幺半群。
newtype OL x = OL [x]
instance Ord x => Monoid (OL x) where
mempty = OL []
mappend (OL xs) (OL ys) = OL (merge xs ys) where
merge [] ys = ys
merge xs [] = xs
merge xs@(x : xs') ys@(y : ys')
| x <= y = x : merge xs' ys
| otherwise = y : merge xs ys'
插入排序由下式给出
isort :: Ord x => [x] -> OL x
isort = foldMap (OL . pure)
因为插入正是将一个单例列表与另一个列表合并。 (合并排序是通过构建平衡树,然后执行相同的 FoldMap 来给出的。)
这与冒泡排序有什么关系?插入排序和冒泡排序具有完全相同的比较策略。如果将其绘制为由比较和交换框组成的排序网络,您可以看到这一点。在这里,数据向下流动,框 [n] 的较低输入向左移动:
| | | |
[1] | |
| [2] |
[3] [4]
| [5] |
[6] | |
| | | |
如果您按照上述编号给出的顺序执行比较,将图切割为 / 切片,您将得到插入排序:第一个插入不需要比较;第一个插入不需要比较;第二个插入不需要比较。第二个需要比较1;第三个2,3;最后4、5、6。
但如果相反,你切成\片......
| | | |
[1] | |
| [2] |
[4] [3]
| [5] |
[6] | |
| | | |
...你正在进行冒泡排序:第一次通过 1,2,3;第二遍4,5;最后一次通过 6.