分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。
分治法在每一层递归上都有三个步骤:
- 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
- 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;
- 合并:将各个子问题的解合并为原问题的解。
它的一般的算法设计模式如下:
Divide-and-conquer(P)
1. if |P|≤n0
2. then return(ADHOc(P))
3. 将P分解为较小的子问题 P1 ,P2 ,…,Pk
4. for i←1 to k
5. do yi ← Divide-and-conquer(Pi) △ 递归解决Pi
6. T ← MERGE(y1,y2,…,yk) △ 合并子问题
7. return(T)
其中|P|表示问题P的规模;n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。ADHOC(P)是该分治法中的基本子算法,用于直接解小规模的问题P。因此,当P的规模不超过n0时,直接用算法ADHOc(P)求解。算法MERGE(y1,y2,…,yk)是该分治法中的合并子算法,用于将P的子问题P1 ,P2 ,…,Pk的相应的解y1,y2,…,yk合并为P的解。
这里举两个算法的例子来看看递归和分治法的应用:
1. 输入一个整数和一棵二元树。
从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。
打印出和与输入整数相等的所有路径。
例如 输入整数22和如下二元树
10
/ /
5 12
/ /
4 7
则打印出两条路径:10, 12和10, 5, 7。
2.输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
10
/ /
6 14
/ / / /
4 8 12 16
转换成双向链表
4=6=8=10=12=14=16。
分析:对这两个题目,都可以用多种方法去求解,这里,我们对第一题用递归方法,对第二题用分治法。
struct BSTreeNode
{
int m_nValue;
BSTreeNode* m_leftchild;
BSTreeNode* m_rightchild;
}; //定义了树节点
/*
1.打印出所有路径和为total的路径
*/
List<BSTreeNode*> nodeList;
void printResult()
{
for (int i = 0; i < nodeList.size(); ++i)
{
if (nodeList.at(i))
cout << nodeList.at(i)->m_nValue << " " ;
}
cout<<endl;
}
void CalcPath(BSTreeNode* root,int total)
{
if(root)
{
if(root->m_nValue == total)
{
if(root->m_leftchild == NULL && root->m_rightchild == NULL)
{
nodeList.append(root);
printResult();
nodeList.pop_back();
}
}
else if(root->m_nValue < total)
{
nodeList.append(root);
CalcPath(root->m_leftchild,total - root->m_nValue);
CalcPath(root->m_rightchild,total - root->m_nValue);
nodeList.pop_back();
}
else
{
return;
}
}
return;
}
/**
2.将一棵2叉树转换成双向链表
不能创建任何新的结点,只调整指针的指向不能创建任何新的结点,只调整指针的指向
**/
BSTreeNode* convertTree2dblink(BSTreeNode* root)
{
if(root == NULL)
{
return NULL;
}
BSTreeNode* left = convertTree2dblink(root->m_leftchild);
BSTreeNode* right = convertTree2dblink(root->m_rightchild);
while(left && left->m_rightchild)
{
left = left->m_rightchild;
}
root->m_leftchild = left;
while(right && right->m_leftchild)
{
right = right->m_leftchild;
}
root->m_rightchild = right;
if(left)
left->m_rightchild = root;
if(right)
right->m_leftchild = root;
return root;
}
BSTreeNode* getdblink(BSTreeNode* root)
{
BSTreeNode* p = convertTree2dblink(root);
BSTreeNode* head = p;
while(head && head->m_leftchild) head = head->m_leftchild;
return head;
}