我一直在学习函数式编程,但我还没有读过有关使用函数式编程语言进行排序的内容。
我知道基于价值交换的排序算法很难用功能性的想法实现,但我想知道有没有用于函数式编程的排序算法?它们是什么?
谢谢。
答案 0 :(得分:21)
在函数式语言中,你编写一个函数,给定一个列表返回一个排序列表,而不是接触(当然)输入。
考虑例如合并排序...首先编写一个函数,给定两个已经排序的列表返回一个单独的排序列表,其中包含两个元素。例如:
def merge(a, b):
if len(a) == 0:
return b
elif len(b) == 0:
return a
elif a[0] < b[0]:
return [a[0]] + merge(a[1:], b)
else:
return [b[0]] + merge(a, b[1:])
然后你可以编写一个函数,通过合并列表的第一和第二半的结果来对列表进行排序。
def mergesort(x):
if len(x) < 2:
return x
else:
h = len(x) // 2
return merge(mergesort(x[:h]), mergesort(x[h:]))
关于Python语法:
L[0]
是列表L
L[1:]
是所有剩余元素的列表L[:n]
是第n个元素的列表,其余为L[n:]
A + B
如果A
和B
都是列表,则是通过连接获得的列表[x]
是一个仅包含单个元素x
答案 1 :(得分:11)
以下是Haskell中实现的排序算法的一些链接:
合并排序通常是排序链表的最佳选择。功能语言通常在列表上运行,尽管我对大多数函数式语言如何实现列表知之甚少。在Common Lisp中,它们被实现为链表,我认为大多数函数式语言也是如此。
虽然可以为链接列表编写快速排序,但由于随机访问,它将受到不良的透视选择的影响。虽然这对完全随机输入无关紧要,但在部分或完全分类的输入枢轴选择变得非常重要。其他排序算法也可能受到链表的慢随机访问性能的影响。
另一方面,合并排序适用于链表,并且可以实现该算法,使得它只需要链接列表的额外空间常量。
答案 2 :(得分:5)
这是Haskell中的经典(pseudo-?)快速排序:
sort [] = []
sort (p:xs) = sort [x | x<- xs, x <= p]
++ [p]
++ sort [x | x <- xs, x > p]
请参阅,例如c2.com或LiteratePrograms.org。 Merge sort写起来并不困难,在实践中更可靠。方案可以在以下方案中完成:
(define (sort xs)
(if (null? xs)
'()
(let* ((p (car xs)) (xs (cdr xs)))
(call-with-values (lambda () (partition (lambda (x) (<= x p)) xs))
(lambda (l r)
(append (sort l) (list p) (sort r)))))))
partition
from SRFI-1(未经测试的代码)。另请参阅chapter 4 of R6RS libraries。
答案 3 :(得分:1)
您当然可以在函数式语言中实现命令式,副作用排序算法。
我实现了一种排序算法,该算法在一种名为ATS的函数式编程语言中就地运行;所有突变都由线性类型处理。如果您对此类事情感兴趣,请给我留言。
答案 4 :(得分:0)
我可能正在从头开始提出这个问题,但我认为全局比较方法可能对某些人有用(例如,在我们不对数字进行排序的情况下)。这是使用ES6的TypeScript版本:
TL; DR
type Comparator<T> = (itemA: T, itemB: T) => number;
const mergeSort = <T>(list: T[], compare: Comparator<T>): T[] => {
if (list.length <= 1) return list;
const middleIndex = Math.floor(list.length / 2);
const listA = mergeSort(list.slice(0, middleIndex), compare);
const listB = mergeSort(list.slice(middleIndex), compare);
return merge(listA, listB, compare);
};
const merge = <T>(listA: T[], listB: T[], compare: Comparator<T>): T[] => {
if (listA.length === 0) return listB;
if (listB.length === 0) return listA;
return compare(listA[0], listB[0]) <= 0
? [listA[0], ...merge(listA.slice(1), listB, compare)]
: [listB[0], ...merge(listA, listB.slice(1), compare)];
};
说明
我们现在可以将一个额外的compare
函数传递给mergeSort
函数。 compare
函数的定义与JavaScript's Array.prototype.sort()
方法的参数中的定义相同。
例如,number
比较器将是:
const compareNumbers: Comparator<number> = (numberA, numberB) =>
numberA - numberB;
...而User
对象比较器可以是:
const compareUsersByAge: Comparator<User> = (userA, userB) =>
userA.age - userB.age;
...或更复杂(例如字符串比较)。