使用分治法实现的全排列算法
2007-08-29 11:06
218 查看
我们将使用分治法实现一个全排列算法。先来看一下算法实现后的效果:
['a','b','c'].permutation #=> [["a", "b", "c"],
# ["a", "c", "b"],
# ["b", "a", "c"],
# ["b", "c", "a"],
# ["c", "a", "b"],
# ["c", "b", "a"]]
算法描述
分治法求解问题分为三个步骤:
- 分解:将问题分为若干个子问题。
- 解决:递归地求解每个子问题。
- 合并:将每个子问题的解合并成为整个问题的解。
现在我们需要求具有n个元素的数组A的全排列。例如:大小为3的数组A=[a,b,c] (为方便起见,我把引号全都省略了,其实应该是A=['a','b','c']。下同),它的全排列为:
[[a,b,c],
[a,c,b],
[b,a,c],
[b,c,a],
[c,a,b],
[c,b,a]]
这是一个大小为 n!*n 的二维数组。
使用分治算法求解全排列的过程如下
- 分解:将数组分为子数组 A[1..k-1] 和一个元素 A[k]。 (1≤k≤n)
- 解决:递归地求解每个子数组 A[1..k-1] 的全排列,直至子数组A[1..k-1]为空时结束递归。
- 合并:将上一步的结果---A[1..k-1]的全排列(一个二维数组)与元素A[k]合并,得出A[1..k]的全排列。例如:
[[]] 与 a 合并得到 [[a]]
[[a]] 与 b 合并得到 [[a,b], [b,a]]
[[a,b],[b,a]] 与 c 合并得到 [[a,b,c],[a,c,b],[c,a,b],[b,c,a],[c,a,b],[c,b,a]]
看下面的图示会更直观一些
1. 分解过程
[a,b,c]
/ \
[a,b] c
/ \
[a] b
/ \
[] a
2. 合并过程
[] a
\ /
[[a]] b
\ /
[[a,b],[b,a]] c
\ /
[[a,b,c],
[a,c,b],
[c,a,b],
[b,a,c],
[b,c,a],
[c,b,a]]
源代码
下面是ruby的源代码(文件名“permutation.rb”)
class Array
# Returns permutation(a new two-dimentional array) of self.
# Example
# - [].permutation #=> [[]]
# - ['A'].permutation #=> [['A']]
# - ['A','B'].permutation #=> [['A','B'],['B','A']]
# - ['A','B','C'].permutation #=> [['A','B','C'],
# ['A','C','B'],
# ['B','A','C'],
# ['B','C','A'],
# ['C','A','B'],
# ['C','B','A']]
def permutation()
permutation_i(self.length-1).sort!
end
private
def permutation_i(i)
if i> 0
return Array.merge_permutation(permutation_i(i-1), self[i])
else
return Array.merge_permutation([[]], self[i])
end
end
# Example
# - Array.merge_permutation([[]], 'A') #=> [['A']]
# - Array.merge_permutation([['A']], 'B') #=> [['B','A'],['A','B']]
# - Array.merge_permutation([['B','A'],['A','B']], 'C') #=> [['C','B','A'],
# ['B','C','A'],
# ['B','A','C'],
# ['C','B','A'],
# ['A','C','B'],
# ['A','B','C']]
def Array.merge_permutation(src, item)
result = Array.new
src.each do |each_array|
result += Array.item_permutation(each_array, item)
end
return result
end
# Returns a new two-dimentional array. Inserts "item" in each pertential place in "src".
# Example
# - Array.item_permutation([], 'A') #=> [['A']]
# - Array.item_permutation(['A'], 'B') #=> [['B','A'], ['A','B']]
# - Array.item_permutation(['A','B'], 'C') #=> [['C','A','B'], ['A','C','B'], 'A','B','C']]
def Array.item_permutation(src, item)
result = Array.new
(0..src.length).each do |i|
new_array = src.collect
new_array.insert(i, item)
result << new_array
end
return result
end
end
require 'pp_extension'
pp(['a','b','c'].permutation)
源代码用于输出二维数组的“pp_extension”可以看我的这篇文章让ruby以矩阵的样式输出二维数组
源代码如下(文件名"pp_extension.rb")
require 'pp'
# Outputs two-dimension array like matrix
class Array
def pretty_print(q)
q.group(1, '[', ']') {
q.seplist(self) {|v|
q.current_group.break if v.is_a?(Array) && !q.current_group.first? # added by me
q.pp v
}
}
end
end
运行时间
算法运行时间 T(n) = T(n-1) + Θ(n2) = Θ(n3)
注 本文并不是从教科书上抄下来的,而是我闭门造车的结果,所以很可能有不正之处,请不吝赐教。
['a','b','c'].permutation #=> [["a", "b", "c"],
# ["a", "c", "b"],
# ["b", "a", "c"],
# ["b", "c", "a"],
# ["c", "a", "b"],
# ["c", "b", "a"]]
算法描述
分治法求解问题分为三个步骤:
- 分解:将问题分为若干个子问题。
- 解决:递归地求解每个子问题。
- 合并:将每个子问题的解合并成为整个问题的解。
现在我们需要求具有n个元素的数组A的全排列。例如:大小为3的数组A=[a,b,c] (为方便起见,我把引号全都省略了,其实应该是A=['a','b','c']。下同),它的全排列为:
[[a,b,c],
[a,c,b],
[b,a,c],
[b,c,a],
[c,a,b],
[c,b,a]]
这是一个大小为 n!*n 的二维数组。
使用分治算法求解全排列的过程如下
- 分解:将数组分为子数组 A[1..k-1] 和一个元素 A[k]。 (1≤k≤n)
- 解决:递归地求解每个子数组 A[1..k-1] 的全排列,直至子数组A[1..k-1]为空时结束递归。
- 合并:将上一步的结果---A[1..k-1]的全排列(一个二维数组)与元素A[k]合并,得出A[1..k]的全排列。例如:
[[]] 与 a 合并得到 [[a]]
[[a]] 与 b 合并得到 [[a,b], [b,a]]
[[a,b],[b,a]] 与 c 合并得到 [[a,b,c],[a,c,b],[c,a,b],[b,c,a],[c,a,b],[c,b,a]]
看下面的图示会更直观一些
1. 分解过程
[a,b,c]
/ \
[a,b] c
/ \
[a] b
/ \
[] a
2. 合并过程
[] a
\ /
[[a]] b
\ /
[[a,b],[b,a]] c
\ /
[[a,b,c],
[a,c,b],
[c,a,b],
[b,a,c],
[b,c,a],
[c,b,a]]
源代码
下面是ruby的源代码(文件名“permutation.rb”)
class Array
# Returns permutation(a new two-dimentional array) of self.
# Example
# - [].permutation #=> [[]]
# - ['A'].permutation #=> [['A']]
# - ['A','B'].permutation #=> [['A','B'],['B','A']]
# - ['A','B','C'].permutation #=> [['A','B','C'],
# ['A','C','B'],
# ['B','A','C'],
# ['B','C','A'],
# ['C','A','B'],
# ['C','B','A']]
def permutation()
permutation_i(self.length-1).sort!
end
private
def permutation_i(i)
if i> 0
return Array.merge_permutation(permutation_i(i-1), self[i])
else
return Array.merge_permutation([[]], self[i])
end
end
# Example
# - Array.merge_permutation([[]], 'A') #=> [['A']]
# - Array.merge_permutation([['A']], 'B') #=> [['B','A'],['A','B']]
# - Array.merge_permutation([['B','A'],['A','B']], 'C') #=> [['C','B','A'],
# ['B','C','A'],
# ['B','A','C'],
# ['C','B','A'],
# ['A','C','B'],
# ['A','B','C']]
def Array.merge_permutation(src, item)
result = Array.new
src.each do |each_array|
result += Array.item_permutation(each_array, item)
end
return result
end
# Returns a new two-dimentional array. Inserts "item" in each pertential place in "src".
# Example
# - Array.item_permutation([], 'A') #=> [['A']]
# - Array.item_permutation(['A'], 'B') #=> [['B','A'], ['A','B']]
# - Array.item_permutation(['A','B'], 'C') #=> [['C','A','B'], ['A','C','B'], 'A','B','C']]
def Array.item_permutation(src, item)
result = Array.new
(0..src.length).each do |i|
new_array = src.collect
new_array.insert(i, item)
result << new_array
end
return result
end
end
require 'pp_extension'
pp(['a','b','c'].permutation)
源代码用于输出二维数组的“pp_extension”可以看我的这篇文章让ruby以矩阵的样式输出二维数组
源代码如下(文件名"pp_extension.rb")
require 'pp'
# Outputs two-dimension array like matrix
class Array
def pretty_print(q)
q.group(1, '[', ']') {
q.seplist(self) {|v|
q.current_group.break if v.is_a?(Array) && !q.current_group.first? # added by me
q.pp v
}
}
end
end
运行时间
算法运行时间 T(n) = T(n-1) + Θ(n2) = Θ(n3)
注 本文并不是从教科书上抄下来的,而是我闭门造车的结果,所以很可能有不正之处,请不吝赐教。
相关文章推荐
- 使用set实现的一种简单的全排列算法(C++语言)
- 使用C++实现全排列算法的方法详解
- python使用分治法实现求解最大值的方法
- python使用分治法实现求解最大值的方法
- 使用 __new__ 实现 Python 的单例模式
- 使用js实现贪吃蛇的部分功能
- 134 编程实现:把十进制数(long 型)分别以二进制和十六进制形式输出,不能使用 printf系列
- PHP使用curl实现put请求
- 一,使用Storm实现实时大数据分析实例:用storm来监测车辆速度是否超过80 km/h
- 使用ArrayAdapter适配器来实现listview隔行换色的功能
- 使用Common.Logging 1.2实现Logging(一)Common.Logging、log4net
- 使用CSS实现间隔线|(竖线)
- Android使用StaticLayout实现文本绘制自动换行
- J2EE项目系列(四)--SSM框架构建积分系统和基本商品检索系统(Spring+SpringMVC+MyBatis)(3)Ajax使用详解(级联列表)以及企业级报表Excel导入导出实现
- 使用 Java 实现 Comet 风格的 Web 应用
- android中使用Preference API实现设置界面
- 免费使用函数计算,只有在阿里云能实现
- 通过使用Netty实现RPC
- 使用wxpython实现arcgis二次开发
- Android基于mAppWidget实现手绘地图(十四)–在一个应用中使用多个地图