说明,本文全文代码均用dart语言实现。
求一个集合S中m个元素的所有排列情况,并打印,非常适合用递归的思路实现。本文给出了两种实现方法,一种是给定的填充排列数组长度是固定的,一种是可变长度的。两种方法主要思路是一样的,只是实现细节上略有差异。具体代码如下:
1 void permute<E>(Set<E> s, int m) {
2 if (m < 0 || m > s.length) throw StateError('m is not in [0, ${s.length}]');
3
4 _fill(<E>[], s, m);
5 print('-------------------');
6 _fillFixed(List<E>(m), s, 0, m);
7 }
8
9 10
11 void _fill<E>(List<E> pm, Set<E> s, int m) {
12 if (pm.length < m) {
13 for (var e in s) {
14 pm.add(e);
15 _fill(pm, _rest(s, e), m);
16 }
17 } else {
18 print(pm);
19 }
20 if (pm.isNotEmpty) pm.removeLast();
21 }
22
23 void _fillFixed<E>(List<E> pm, Set<E> s, int i, int m) {
24 if (i < m) {
25 for (var e in s) {
26 pm[i] = e;
27 _fillFixed(pm, _rest(s, e), i + 1, m);
28 }
29 } else {
30 print(pm);
31 }
32 }
33
34 Set _rest<E>(Set<E> s, E e) {
35 var t = s.toSet();
36 t.remove(e);
37 return t;
38 }
如果求一个集合的全排列,如果是集合的话,其实在上面的函数permute,将m的值设为集合s的长度即可:
1 void permuteAll2<E>(Set<E> s) => permute(s, s.length);
如果求一个数组的全排列情况(假设数组中元素不重合),可以不像集合那样,还需要额外申请空间,直接利用数组本身即可完成:
1 void permuteAll(List a, int k) {
2 if (k < a.length - 1) {
3 for (int i = k; i < a.length; i++) {
4 if (i != k) _swap(a, k, i);
5 permuteAll(a, k + 1);
6 if (i != k) _swap(a, k, i);
7 }
8 } else {
9 print(a);
10 }
11 }
12
13 void _swap(List a, int i, int j) {
14 var t = a[i];
15 a[i] = a[j];
16 a[j] = t;
17 }
具体思路,比较简单,直接查看代码即可,或者参照网上的讲解,这里不再赘述了。有兴趣的也可以直接debug,可以看每一步的操作。
最后,验证代码如下:
1 void main() {
2 var s = {1, 2, 3};
3 permute(s, 3);
4 print('---------------------
');
5 permuteAll(s.toList(), 0);
6 print('---------------------
');
7 permuteAll2(s);
8 }