《算法导论》 2.3.1分治法

来源:互联网 发布:快牙软件 编辑:程序博客网 时间:2024/06/06 02:52

分治法

有很多算法在结构上是递归的:为了解决一个给定的问题,算法要一次或多次地递归地调用其自身来解决相关的问题。这些算法通常采用分治策略:将原问题划分为n个规模较小而结构与原问题相似的子总是;递归地解决这些子问题,然后再合并其结果,就得到原问题的解。

分治模式在每一层递归上都有三个步骤:

分解(Divide):将原问题分解成一系列子总是

解决(Conquer):递归地解各子问题,若子问题足够小,则直接求解;

合并排序(merge sort)算法完全依照了上述模式,直观地操作如下:

分解:将n个元素分成各含n/2个元素的子序列;

解决:用合并排序法对两个子序列以得到排序结果;

合并:合并两个己排序的子序列以得到排序结果。

在对子序列排序时,其长度为1时递归结束,单个元素被视为是己排好序的。即其规模是足够小的。

合并排序的关键步骤在于合并步骤中的合并两个己排序子序列。为做合并,引入一个辅助过程Merge(A, p, q, r)其中A是个数组,p、q和r是下标,满足p<=q<=r。该过程假设子数组A[p,q]和A[q+1,r]都己排好序,并将它们合并成一个己排好序的子数组代替当前子数组A[p,r]。

下列为合并算法伪代码

其中赋值无穷大,是作为一个“哨兵牌”。包含一个特殊值。如Int型中,如果要对其进行赋值无穷大,可以赋值一个最大值。#include<limits>。中的INT_MAX可以对其赋最大值。

而对其整个的排序,可以用伪代码Merge-sort(A,p,r)表示。

Merge-sort(A,p,r):

If(p<r)

      Thenq=(p+r)/2向下取整。

      Merge-sort(A,p,q);

      Merge-sort(A,q+1,r);

      Merge(A,p,q,r);



#include<iostream>
#include<limits>
#include<math.h>
using namespace std;
//合并排序算法,即数组A中,从p到q下标的元素已经排序了,从q到j的元素也已经排序了,则将p到j的元素进行排序操作,
//注意,是从小到大排序。。正确,则输出1;错误,则输出-1
int Merge(int *A,int p,int q,int j)
{
if(p<0||q<0||j<0)
return -1;
for(int i = p;i<q;i++)
{
if(A[i]>A[i+1])
{
cout<<"请输入己排序的数列才能进行运算";//在整个递归排序过程中,是不需要这个检测过程的。只不过为了统一安排罢了。
return -1;
}
}
for(int i = q+1;i<j;i++)
{
if(A[i]>A[i+1])
{
cout<<"请输入己排序的数列才能进行运算";
return -1;
}
}


if(p>q||q>j)
{
cout<<"请输入正确的己排序的数列下标";
return -1;
}
int n1 = q-p+2;
int n2 = j-q+1;
int *L = new int[n1];
int *R = new int[n2];
for(int k = 0;k<n1;k++)
{
L[k] = A[p+k];
}
for(int k = 0;k<n2;k++)
{
R[k] = A[q+1+k];
}
L[n1-1] = INT_MAX;
R[n2-1] = INT_MAX;
int i = 0;
int k = 0;
for(;p<j+1;p++)
{
if(L[i]<R[k])
{
A[p] = L[i];
i++;
}
else
{
A[p] = R[k];
k++;
}
}
delete L;
delete R;
return 1;
}


void Merge_sort(int *A,int p,int r)
{
int q;
if(p<r)
{
q = int(floor(double(p+r)/2));
Merge_sort(A,p,q);
Merge_sort(A,q+1,r);
Merge(A,p,q,r);
}
}
void main()
{
int A[10] = {5,13,7,11,9,10,1,2,8,4};
Merge_sort(A,0,9);
for(int i = 0;i<10;i++)
cout<<A[i]<<endl;