目录
- 用Python解数独[0]
- 用Python解数独[1]:求每个单元格的行值域
- 用Python解数独[2]:求列值域和九宫格值域
- 用Python解数独[3]:求总值域
- 用Python解数独[4]:缩减值域
- 用Python解数独[5]:检测唯一值缩减值域
- 用Python解数独[6]:递归获得最终答案
- 用Python解数独[7]:递归(完结篇)
[2][2] 递归函数详解
这篇文章我们将详细讲一讲递归函数
# 检查值域列表是否合法:行检测,列检测,九宫格检测
def soduku_checkRepeat(s_value_range):
temp_col = list(zip(*s_value_range))
temp_matrix = matrix_invert(s_value_range)
return row_checkRepeat(s_value_range) and row_checkRepeat(temp_col) and row_checkRepeat(temp_matrix)
# 计算值域列表取值总的组合数(各单元格值域长度相乘)
def sodukuRate(s_row_vrange):
rate = 1
for i in s_row_vrange:
for j in i:
rate *= len(j)
return rate
# 主函数,输入值域列表,如遇到多个取值的单元格,依次尝试值域里的每个值,通过递归的方法检测值是否正确
def trial(total_value_range):
for i in range(9):
for j in range(9):
if len(total_value_range[i][j]) > 1:
for k in total_value_range[i][j]:
test_value = copy.deepcopy(total_value_range)
test_value[i][j] = [k]
test_value = reduce_totalValueRange(generator_soduku(test_value))
if soduku_checkRepeat(test_value):
if sodukuRate(test_value) == 1:
return test_value
else:
if trial(test_value):
return trial(test_value)
else:
continue
return False
我们先举几个简单的例子,看下什么是递归
#斐波那契数列通项公式
def f(n):
if n == 1:
return 1
elif n == 2:
return 1
else:
a = f(n-1) + f(n-2)
return a
斐波那契数列,用数学表达式就是:
f(1) = 1,f(2) = 1
若n>2,则f(n) = f(n-1)+f(n-2)
其实这里就已经应用了递归!若求f(5)的值,则必须求f(4)和f(3)的值,若求f(4)和f(3)的值,则需要求f(3),f(2)和f(2)和f(1)的值,f(2)和f(1)是我们已知的值,然后就可以依次求出f(3),f(4)直到f(5)的值。我们可以用数学表达式演示一下:
--> f(5) = f(4) + f(3)
--> f(4) = f(3) + f(2) , f(3) = f(2) + f(1)
--> f(3) = f(2) + f(1) , f(2) = 1 , f(2) = 1 , f(1) = 1
--> f(2) = 1 , f(1) = 1
--> f(3) = 2 , f(2) = 1 , f(2) = 1 , f(1) = 1
--> f(4) = 3 , f(3) = 2
--> f(5) = 5
我们举完例子再看一下“递归”的定义
程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。 [1]
这个斐波那契数列的例子,就用到了递归,当n > 2时,我们返回的不是一个常数,而是f(n-1)+f(n-2),即在f(n)中“直接或间接调用自身”。
我们再回到数独函数,在使用trial()递归函数之前,数独各个单元格的值域如下图