在函数式编程语言中排序

时间:2011-01-01 14:01:58

标签: sorting functional-programming

我一直在学习函数式编程,但我还没有读过有关使用函数式编程语言进行排序的内容。

我知道基于价值交换的排序算法很难用功能性的想法实现,但我想知道有没有用于函数式编程的排序算法?它们是什么?

谢谢。

5 个答案:

答案 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如果AB都是列表,则是通过连接获得的列表
  • [x]是一个仅包含单个元素x
  • 的列表
PS:请注意上面的python代码只是为了展示这个概念......在Python中,这不是一个合理的方法。我使用Python是因为我认为如果你知道任何其他常见的命令式语言,它是最容易阅读的。

答案 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.comLiteratePrograms.orgMerge 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;

...或更复杂(例如字符串比较)。