分治(Divide and Conquer)算法:问题能够分解为子问题,每一个问题是能够独立的解决的,从子问题的解能够构建原问题。

Divide:中间分、随机分、奇偶分等,将问题分解成独立的子问题

Conquer:子问题的解能够单独解决,从子问题的解构建原问题终于的解

Combine:每一步将子问题产生的解进行合并得到终于的解。合并的复杂度影响终于的算法时间复杂度

Karatsuba算法是在普通乘法算法的基础上进行的提升,使得终于的复杂度从O(n^2)变为了O(n^1.585)。基本思想是将原问题的规模每次减小一般。而且每次解决三个子问题:

X =  Xl*2n/2 + Xr    [Xl 左側n/2位数  Xr 右側n/2位数]
Y = Yl*2n/2 + Yr [Yl 左側n/2位数 Yr 右側n/2位数]
XY = (Xl*2n/2 + Xr)(Yl*2n/2 + Yr)
= 2n XlYl + 2n/2(XlYr + XrYl) + XrYr
XY = 2n XlYl + 2n/2 * [(Xl + Xr)(Yl + Yr) - XlYl - XrYr] + XrYr
XY = 22ceil(n/2) XlYl + 2ceil(n/2) * [(Xl + Xr)(Yl + Yr) - XlYl - XrYr] + XrYr

从而得到终于的算法时间复杂度为T(n) = 3T(n/2) + O(n)。得到T(n) = O(n^1.585)。算法的伪代码例如以下:

karatsuba(num1, num2)
if (num1 < 10) or (num2 < 10)
return num1*num2
/* calculates the size of the numbers */
m = max(size_base10(num1), size_base10(num2))
m2 = m/2
/* split the digit sequences about the middle */
high1, low1 = split_at(num1, m2)
high2, low2 = split_at(num2, m2)
/* 3 calls made to numbers approximately half the size */
z0 = karatsuba(low1,low2)
z1 = karatsuba((low1+high1),(low2+high2))
z2 = karatsuba(high1,high2)
return (z2*10^(2*m2))+((z1-z2-z0)*10^(m2))+(z0)

以下是使用C++详细实现的过程。假设直接使用整数类型实现。可能会发生溢出,因此使用输入的字符串表示。实际运算的过程将字符串转换为数组进行加、减、乘操作。先看终于的算法实现:

string Multiplicate(string x, string y)
{
int len = GetSameSize(x, y);
if (len == 0) return 0;
if (len == 1) return MultiplyString(x, y);
int p = len % 2 == 0 ? len / 2 : len / 2 + 1; string Xh = x.substr(0, len / 2);
string Yh = y.substr(0, len / 2);
string Xl = x.substr(len / 2);
string Yl = y.substr(len / 2); string P1 = Multiplicate(Xh, Yh);
string P2 = Multiplicate(Xl, Yl);
string P3 = Multiplicate(AddString(Xh, Xl), AddString(Yh, Yl)); return
AddString(
AddString(
MultiplyPower(P1, 2 * p),
MultiplyPower(MinusString(MinusString(P3, P1), P2), p)
), P2
);
}

上述就是依照伪代码进行实现,可是使用了字符串的数字运算操作。包含字符串与数组的转换,数组加、减、乘,详细实现例如以下:

void StringToArray(string a, int *arr)
{
int n = a.size();
for(int i = 0; i < n; i++)
arr[n - i - 1] = a.at(i) - '0';
}
void ArrayToString(int *arr, int len, string & a)
{
for(int i = 0; i < len; i++)
a += '0' + arr[len - i - 1];
}
string DelPreZero(string a)
{
int zeros = 0;
for (int i = 0; i < a.size(); i++)
if (a.at(i) == '0') zeros++;
else break;
if (zeros == a.size()) return "0";
return a.substr(zeros);
}
void MultiplyArray(int a[], int la, int b[], int lb, int *arr)
{
int i;
for (i = 0; i < la; i++)
for (int j = 0; j < lb; j++)
arr[i + j] += a[i] * b[j];
for (i = 0; i < la + lb - 1; i++)
{
arr[i + 1] += arr[i] / 10;
arr[i] = arr[i] % 10;
}
}
void AddArray(int a[], int la, int b[], int lb, int *arr)
{
int i;
int len = la > lb ? lb : la;
for (i = 0; i < len; i++)
arr[i] += a[i] + b[i];
if (la > lb)
{
for (i = lb; i < la; i++)
arr[i] = a[i];
for (i = 0; i < la; i++)
{
arr[i + 1] += arr[i] / 10;
arr[i] = arr[i] % 10;
}
}
else
{
for (i = la; i < lb; i++)
arr[i] = b[i];
for (i = 0; i < lb; i++)
{
arr[i + 1] += arr[i] / 10;
arr[i] = arr[i] % 10;
}
}
}
void MinusArray(int a[], int la, int b[], int lb, int *arr) //a must be bigger than b
{
int i;
for (i = 0; i < lb; i++)
arr[i] = a[i] - b[i];
for (i = lb; i < la; i++)
arr[i] = a[i];
for (i = 0; i < la - 1; i++)
{
if (arr[i] < 0)
{
arr[i + 1]--;
arr[i] = 10 + arr[i];
}
}
}
string MultiplyString(string a, string b)
{
int m = a.size(), n = b.size();
int *arrA = new int[m];
int *arrB = new int[n];
StringToArray(a, arrA);
StringToArray(b, arrB); int *arrC = new int[m + n];
for(int i = 0; i < n + m; i++) arrC[i] = 0; string rst;
MultiplyArray(arrA, m, arrB, n, arrC);
ArrayToString(arrC, m + n, rst); delete []arrA;
delete []arrB;
delete []arrC;
return DelPreZero(rst);
} string AddString(string a, string b)
{
int m = a.size(), n = b.size();
int *arrA = new int[m];
int *arrB = new int[n];
StringToArray(a, arrA);
StringToArray(b, arrB); int i, len = m > n ? m : n;
int *arrC = new int[len + 1];
for(i = 0; i < len + 1; i++) arrC[i] = 0;
AddArray(arrA, m, arrB, n, arrC); string rst;
ArrayToString(arrC, len + 1, rst); delete []arrA;
delete []arrB;
delete []arrC;
return DelPreZero(rst);
} string MultiplyPower(string a, int len)
{
for(int i = 0; i < len; i++)
a += '0'; return DelPreZero(a);
} string MinusString(string a, string b)
{
int m = a.size(), n = b.size();
int *arrA = new int[m];
int *arrB = new int[n];
StringToArray(a, arrA);
StringToArray(b, arrB); string rst;
int i, len = m > n ? m : n;
int *arrC = new int[len];
for(i = 0; i < len; i++) arrC[i] = 0; MinusArray(arrA, m, arrB, n, arrC);
ArrayToString(arrC, len, rst); delete []arrA;
delete []arrB;
delete []arrC;
return DelPreZero(rst);
}

主要是涉及到字符串与数组的转换中字符串在数字中是逆序的,进行数组运算时方便,同一时候对于数组间的减法。仅仅支持a 大于b的减法,假设是a 小于b能够用b减去a后再取反就可以。还有就是对数组的动态空间申请后,须要及时释放。

參考:

1.http://www.geeksforgeeks.org/divide-and-conquer-set-2-karatsuba-algorithm-for-fast-multiplication/

2.http://en.wikipedia.org/wiki/Karatsuba_algorithm#Pseudo_Code_Implementation


分治算法——Karastsuba算法的更多相关文章

  1. 最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)(转)

    一,问题描述 在英文单词表中,有一些单词非常相似,它们可以通过只变换一个字符而得到另一个单词.比如:hive-->five:wine-->line:line-->nine:nine- ...

  2. GMM算法k-means算法的比较

    1.EM算法 GMM算法是EM算法族的一个具体例子. EM算法解决的问题是:要对数据进行聚类,假定数据服从杂合的几个概率分布,分布的具体参数未知,涉及到的随机变量有两组,其中一组可观测另一组不可观测. ...

  3. 简单易学的机器学习算法——EM算法

    简单易学的机器学习算法——EM算法 一.机器学习中的参数估计问题 在前面的博文中,如“简单易学的机器学习算法——Logistic回归”中,采用了极大似然函数对其模型中的参数进行估计,简单来讲即对于一系 ...

  4. 重新想象 Windows 8 Store Apps (31) - 加密解密: 哈希算法, 对称算法

    原文:重新想象 Windows 8 Store Apps (31) - 加密解密: 哈希算法, 对称算法 [源码下载] 重新想象 Windows 8 Store Apps (31) - 加密解密: 哈 ...

  5. Hash散列算法 Time33算法

    hash在开发由频繁使用.今天time33也许最流行的哈希算法. 算法: 对字符串的每一个字符,迭代的乘以33 原型: hash(i) = hash(i-1)*33 + str[i] ; 在使用时.存 ...

  6. 变易算法 - STL算法

    欢迎访问我的新博客:http://www.milkcu.com/blog/ 原文地址:http://www.milkcu.com/blog/archives/mutating-algorithms.h ...

  7. STL非变易算法 - STL算法

    欢迎访问我的新博客:http://www.milkcu.com/blog/ 原文地址:http://www.milkcu.com/blog/archives/1394600460.html 原创:ST ...

  8. 【啊哈!算法】算法7:Dijkstra最短路算法

    上周我们介绍了神奇的只有五行的Floyd最短路算法,它可以方便的求得任意两点的最短路径,这称为“多源最短路”.本周来来介绍指定一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径”.例如求下图 ...

  9. 【啊哈!算法】算法6:只有五行的Floyd最短路算法

            暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程.         上图中有 ...

随机推荐

  1. CodeForces 811B Vladik and Complicated Book

    离线,树状数组. 数据范围好像有点小,直接暴力可以过的. 我直接上了$n,Q≤100000$的做法:只需要判断区间上比$x$小的数字有几个即可,可以对询问进行离线操作,从左到右一个一个数字插入到树状数 ...

  2. 洛谷P2296 寻找道路 [拓扑排序,最短路]

    题目传送门 寻找道路 题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点 ...

  3. 洛谷P3052 [USACO12MAR]摩天大楼里的奶牛 [迭代加深搜索]

    题目传送门 摩天大楼里的奶牛 题目描述 A little known fact about Bessie and friends is that they love stair climbing ra ...

  4. docker chown: changing ownership of '/var/lib/XXX': Permission denied

    Links: 1.entos7下docker Permission denied 2.查看 SELinux状态及关闭SELinux 方法: 1.查看SELinux状态sestatus -vgetenf ...

  5. Node.js后台开发初体验

    Node.js是什么 Node.js是一个Javascript运行环境(runtime),发布于2009年5月,由Ryan Dahl开发,实质时对Chrome V8引擎进行了封装 Node.js安装 ...

  6. Python 正则表达式中级

    首先是?:   在括号中用?:用在findall和split之中,去除括号优先级. 如果不用只输出括号内匹配的值 r   的作用是转义python里面换行符等,像是\n 不用加\来转义 1.子表达式 ...

  7. Hibernate 对象的生命周期及CRUD操作

    对象状态及生命周期 1.Transient(瞬时状态):new的对象为瞬时态 session中没有数据,数据库中没有数据. 2.Persistent(持久状态):被session管理的对象为持久状态, ...

  8. BZOJ 4566 JZYZOJ 1547 [haoi2016T5]找相同子串 后缀数组 并查集

    http://172.20.6.3/Problem_Show.asp?id=1547 http://www.lydsy.com/JudgeOnline/problem.php?id=4566 单纯后缀 ...

  9. [POI2012]Squarks

    [POI2012]Squarks 题目大意: 设有\(n\)个互不相同的正整数\(\{X_1,X_2,...,X_n\}\),任取两个\(X_i,X_j(i\ne j)\),能算出\(X_i+X_j\ ...

  10. [POJ1205]Water Treatment Plants

    题目大意: 有一排n个格子,要在它们上面装管道. 每个格子上的管道都是T形的,但是可以有三种流动的方向. 每种都是把两个方向的水往另一个方向排出. 如果方向是向左或向右,就是排到相邻的格子里. 特别地 ...