组合数学 1.4

组合数学 1.4

测试测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2018年3月
SPM支持 SPM

Albert MataCem Olcay 维护。



组合数学

组合数学 包含用于生成数组中 n 个元素的无重复 k-排列和无重复 k-组合的静态函数(两种情况都支持不重复或重复)。

兼容性

组合数学 需要 iOS 8+,并且与 Swift 2 项目兼容。

安装

传统方法

只需将文件 Combinatorics.swift 拖到您的项目中。这实际上就是您需要做的所有事情。或者如果您只需要一个或两个函数,将函数复制并粘贴到您的项目中即可。毕竟,组合数学 只是一组静态函数,也可以定义为全局函数。

一点理论

在自然英语中,组合一词用于指代从列表中取一些或所有元素的行为,有或没有重复,关心或不关心它们的顺序。但在数学中,有不同的概念用于这些事物,这取决于是否允许重复元素以及是否关心元素的顺序。组合数学,尤其是 计数组合数学,主要集中在某个组合对象的数量上,例如提供排列、组合和划分的统一框架。

组合数学(此库)包含用于四种不同场景的函数

  1. 如果元素的顺序很重要且不允许重复元素,则它是一个无重复排列。
  2. 如果元素的顺序很重要且允许重复元素,则它是一个重复排列。
  3. 如果元素顺序不重要且不允许重复元素,则它是一个无重复组合。
  4. 如果元素顺序不重要且允许重复元素,则它是一个重复组合。

排列

根据维基百科,排列的概念与将一个集合的所有成员按某种顺序进行排列的行为相关,或者如果集合已经有序,则重新排列其元素,这个过程称为排列。这些与组合不同,组合是指从集合中选择一些成员,而忽略了顺序。例如,以元组的形式写成,有六个排列的集合{1,2,3},即:(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),和(3,2,1)。这些都是这个三元素集合的所有可能排列。作为另一个例子,一个单词的所有字母都不同,它的排列就是该单词字母的排列。在这个例子中,字母在原始单词中已经有序,而排列是字母的重新排列。有限集合排列的研究是组合学领域的一个主题。

“排列”这个词有较弱的意义,有时在初等组合学文本中使用,指的是那些没有元素重复出现的有序排列,但不要求使用给定的集合中所有的元素。在特殊情况之外,这些不是排列,但是对有序排列概念的推广。事实上,这种用法常常涉及到对一个固定长度的元素k的排列,从给定的大小为n的集合中取出,换句话说,这些n排列k的元素是n集合中的一个k元素子集的不同有序排列(在旧文献中有时被称为排列。)这些对象也被称为部分排列或不重复序列,这些术语避免了与“排列”的其他更常见的意义混淆。

最后,我们有时会发现术语“无重复排列”或“有重复排列”。这些是组合学中的古词汇,但仍然被非英语作者广泛用于n中k排列(在此库中为无重复排列)和n元的排列(在此库中为重复排列)。

组合

根据维基百科,组合是从集合中选择项目的一种方式,与排列不同的是,选择顺序不影响。在较小的情况下,可以计算组合的数量。例如,给定三个水果,比如苹果、橙子和李子,可以从这个集合中抽取三种组合:苹果和李子;苹果和橙子;或李子和橙子。更正式地说,集合S的一个k组合是其k个不同元素的子集。如果一个集合有n个元素,那么k组合的数量等于由n和k指定的二项式系数。

用法

如前所述,组合学(本库)包括四种不同场景的函数。

  1. 如果元素的顺序很重要且不允许重复元素,则它是一个无重复排列。
  2. 如果元素的顺序很重要且允许重复元素,则它是一个重复排列。
  3. 如果元素顺序不重要且不允许重复元素,则它是一个无重复组合。
  4. 如果元素顺序不重要且允许重复元素,则它是一个重复组合。

所有函数都被定义为public static,并且不依赖于任何其他私有函数,因此实际上可以将特定函数复制粘贴到您的代码中。为了简洁和一致性的原因,所有函数都将元素集作为类型为T的元素数组,并将相应的子集作为类型为T的数组数组返回。然而,请注意,对于组合而言,仅关注数组中元素的存在,而不关注它们的顺序。

最后,所有函数都被定义为泛型,因此可以轻松计算任何元素的排列和组合。

无重复排列

permutationsWithoutRepetitionFrom<T>(elements: [T], taking: Int) -> [[T]]

给定一个以elements为元素的数组以及我们想要taking的元素数量,返回一个包含所有可能无重复排列的数组。请注意,由于不允许重复,taking必须始终小于或等于elements.count

按照惯例,如果taking为0,函数将返回[[]](一个仅包含一个可能排列的数组 - 即不包含任何元素的排列)。在另一种情况下,如果taking大于elements.count,函数将返回[](一个空数组,因此不包含任何排列)。

可重复排列

permutationsWithRepetitionFrom<T>(elements: [T], taking: Int) -> [[T]]   

给定一个元素数组elements和要从中取出的元素数量,返回一个包含所有可能可重复排列的数组。请注意,由于允许重复,taking无需小于或等于elements.count

按照惯例,如果taking为0,函数将返回[[]](一个仅包含一个可能排列的数组 - 即不包含任何元素的排列)。在另一种情况下,如果taking大于0但elements不包含任何元素,函数将返回[](一个空数组,因此不包含任何排列)。

不重复组合

combinationsWithoutRepetitionFrom<T>(elements: [T], taking: Int) -> [[T]]

给定一个元素数组elements和要从中取出的元素数量,返回一个包含所有可能的不重复组合的数组。请注意,由于不允许重复,taking必须始终小于或等于elements.count

按照惯例,如果taking为0,函数将返回[[]](一个仅包含一个可能组合的数组 - 即不包含任何元素的组合)。在另一种情况下,如果taking大于elements.count,函数将返回[](一个空数组,因此不包含任何组合)。

记住,由于组合不考虑顺序,这两个组合表示完全相同的元素集合:[1,2,3]和[3,2,1]。

可重复组合

combinationsWithRepetitionFrom<T>(elements: [T], taking: Int) -> [[T]]

给定一个元素数组elements和要从中取出的元素数量,返回一个包含所有可能可重复组合的数组。请注意,由于允许重复,taking无需小于或等于elements.count

按照惯例,如果taking为0,函数将返回[[]](一个仅包含一个可能组合的数组 - 即不包含任何元素的组合)。在另一种情况下,如果taking大于0但elements不包含任何元素,函数将返回[](一个空数组,因此不包含任何组合)。

记住,由于组合不考虑顺序,这两个组合表示完全相同的元素集合:[1,2,2,3]和[3,2,1,2]。

一些示例

示例1

// All possible ways to arrange letters [abc].
let ps = Combinatorics.permutationsWithoutRepetitionFrom(["a", "b", "c"], taking: 3)
for p in ps { 
    print(p.joinWithSeparator("")) 
}

输出

abc
acb
bac
bca
cab
cba

示例2

// All possible numbers created by picking 5 different digits (accepting 0 as the first digit).
let ps = Combinatorics.permutationsWithoutRepetitionFrom(Array(0...9), taking: 5)
for p in ps {
    var exp = 100000
    print(p.reduce(0) { exp /= 10; return $0 + $1 * exp })
}

输出

1234
1235
1236
1237
[many more numbers]
98762
98763
98764
98765

示例3

// All possible binary numbers using exactly 3 bits.
let prs = Combinatorics.permutationsWithRepetitionFrom(["0", "1"], taking: 3)
for pr in prs {
    print(pr.joinWithSeparator(""))
}

输出

000
001
010
011
100
101
110
111

示例4

// All possible pizzas you can order with 3 extra ingredients.
let cs = Combinatorics.combinationsWithoutRepetitionFrom(["bacon", "cheese", "tomato", "olives", "onion"], taking: 3)
for c in cs {
    print(c)
}

输出

["bacon", "cheese", "tomato"]
["bacon", "cheese", "olives"]
["bacon", "cheese", "onion"]
["bacon", "tomato", "olives"]
["bacon", "tomato", "onion"]
["bacon", "olives", "onion"]
["cheese", "tomato", "olives"]
["cheese", "tomato", "onion"]
["cheese", "olives", "onion"]
["tomato", "olives", "onion"]

示例5

// All possible ways you can pick 6 numbers out of 6 available.
let cs = Combinatorics.combinationsWithoutRepetitionFrom([4, 8, 15, 16, 23, 42], taking: 6)
for c in cs { 
    print(c) 
}

输出:在这里不要迷失,显然只有一个解决方案 - 选择所有元素,因为顺序无关紧要!

[4, 8, 15, 16, 23, 42]

示例 6

// All possible ways 4 people can order some drinks in a bar serving only soda and beer.
let crs = Combinatorics.combinationsWithRepetitionFrom(["soda", "beer"], taking: 4)
for cr in crs {
    let grouped = NSCountedSet(array: cr)
    grouped.forEach({ print("\(grouped.countForObject($0)) × \($0)") })
    print("")
}

输出

4 × soda

3 × soda
1 × beer

2 × soda
2 × beer

1 × soda
3 × beer

4 × beer

作者

Albert Mata (@almata on Twitter). 请在以下网站上查看更多关于我及我的工作的信息:albertmata.net.

雇佣我

我目前位于巴塞罗那,接受全欧洲的永久或合同项目。只要你对总工作或部分远程工作(比如说如果我需要的话,每月可以在现场一到两周)没有异议。更多信息请查看我的项目:albertmata.net/apps 或通过以下邮箱联系我:[email protected]

许可

组合数学 可在 MIT 许可证下获取。查看 LICENSE 文件获取更多信息。如果你有任何问题或想分享你是如何使用本工具的,请提交问题。