分治法与大整数Karatsuba乘法算法
分治法是算法设计的常用思想之一,也是Karatsuba乘法算法的基础,笔者练习用python编程语言进行实现。
分治法
分治法(divide and conquer),其设计思想是将无法着手解决的大问题分解成一系列规模较小的相同问题,然后逐个解决小问题。分治法产生的子问题与原始问题相同,只是规模减小,反复使用分治方法,可以使得子问题得规模不断减小,直到能够被直接求解为止。
分治法是算法设计中的一个古老策略,在很多问题中得到了广泛的应用,比如最大、最小问题,矩阵乘法、大整数乘法以及排序。除此之外,这个技巧也是许多高效算法的基础,比如快速傅里叶变换算法和Karatsuba算法。
应用分治法,一般出于两个目的:一是通过分解问题,使无法着手解决的大问题变成容易解决的小问题;二是通过减小问题的规模,降低解决问题的复杂度。
分治法通常使用递归的方式对问题逐级分解,在每个子问题的层面上,分治法基本上可以归纳为以下三个步骤:
(1)分解:将问题分解为若干个规模较小,相互独立且与原问题形式相同的子问题,确保各个子问题的解具有相同的子结构。
(2)解决:如果上一步分解得到的子问题可以解决,则解决这些子问题,否则,对每个子问题使用和上一步相同的方法再次分解,然后求解分解后的子问题,这个过程可能是一个递归的过程。
(3)合并:将上一步解决的各个子问题的解通过某种规则合并起来,得到原问题的解。
分治法的实现模式可以是递归方式,也可以是非递归方式。
分治法的难点是如何将子问题分解,并且将子问题的解合并出原始问题的解。
递归作为一种算法的实现方式,与分治法的思想十分契合。问题的分解不是一步到位的,需要反复使用分治手段,在多个层次上层层分解,这种分解的方法很自然地导致了递归方式的使用。从算法实现的角度看,分治法得到的子问题和原问题是相同的,当然可以用相同的函数来解决,区别只在于问题的规模和范围不同。通过特定的函数参数安排,使得同一个函数可以解决不同规模的问题,这就是递归方法的基础。
大整数Karatsuba乘法算法
两个n位大整数相乘,普通乘法算法的时间复杂度一般是 O ( n 2 ) O(n^2) O(n2)。但是Anatolii Alexeevitch Karatsuba博士在1960年提出了一种时间复杂度为 O ( 3 n 1.585 ) O(3n^{1.585}) O(3n1.585)( 1.585 = l o g 2 3 1.585=log_{2}3 1.585=log23)的快速乘法算法,这就是Karatsuba算法。该算法就是利用了分治法的思想,将 n n n位大整数分解成两个接近 n / 2 n/2 n/2位的大整数,通过3次 n / 2 n/2 n/2位大整数的乘法和少量加法操作,避免了直接进行 n n n位大整数乘法计算,有效地降低了乘法计算的计算量。
计算原理
假设有两个 n n n位的 M M M进制大整数 x x x, y y y利用一个小于 n n n的正数 k k k(通常 k k k的取值位 n / 2 n/2 n/2左右),将 x x x和 y y y分解为两个部分: x = x 1 M k + x 0 x=x_1M^k+x_0 x=x1Mk+x0 y = y 1 m k + y 0 y=y_1m^k+y_0 y=