写这篇文章的时候不知道是30天内的第几天了,原本打算开始的数据结构学习也被搁浅了。业余时间主要还是在学习最短路径问题,没办法这是工作中最常遇到的问题,必须要搞清楚,可能后面就会轻松点了。
在使用穷举法解最短路径问题的时候,我看到一种使用全排列算法的实现方式,于是开始了对全排列算法的研究。这里给出全排列的定义
从n个元素中取出m个元素进行排列,当n=m时,这个排列被称为全排列
举个例子,比方说我要求数组[1,2,3]
的全排列形式。那么最后的输出结果应该是
1 2 3 4 5 6
| [1,2,3] [1,3,2] [2,1,3] [2,3,1] [3,2,1] [3,1,2]
|
换句话说,对于一个拥有m
个不重复元素的数组,它的全排列一共有m!
种形式。
那么如何使用计算机来实现全排列的算法呢?这里只考虑使用递归的方式实现。我是根据代码结果来反验证递归的正确性,下面来看看代码先
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| var fullyArranged = function (array, cursor) { if (cursor == array.length) { console.log(array) } else { for (var i = cursor; i < array.length; i++) { console.log("cursor = " + cursor + ", i = " + i); swap(array, cursor, i); fullyArranged(array, cursor + 1); swap(array, cursor, i); } } }
var swap = function (array, i, j) { if (i == j) return; var temp = array[i]; array[i] = array[j]; array[j] = temp; console.log("i = " + i + ", j = " + j); }
fullyArranged([1, 2, 3], 0);
|
我大致解释一下这个递归算法的执行步骤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| cursor = 0, i = 0 cursor = 1, i = 1 cursor = 2, i = 2
cursor = 1, i = 2
cursor = 2, i = 2
cursor = 0, i = 1
cursor = 1, i = 1 cursor = 2, i = 2
cursor = 1, i = 2
cursor = 2, i = 2
cursor = 0, i = 2
cursor = 1, i = 1 cursor = 2, i = 2
cursor = 1, i = 2
cursor = 2, i = 2
|
简单点来说,先把第一个元素的所有排列遍历,然后交换第二个元素到第一位将所有排列遍历,最后交换第三个元素到第一位将所有排列遍历。
这个算法中最重要的一点在于,对于交换过的元素,在结束完一次递归后要将元素交换回来,不然输出的结果会有重复。
我一直没弄明白一件事,递归算法的本质是什么。虽然我知道是栈操作,但短短几句代码,就实现了全排列效果,不得不佩服递归的神奇。如何把一句简简单单的描述用递归来实现,确实是一个不小的文章。
如果要排列四个元素以及更多,可以参考抽象成看三个元素的情况。