第二章
算法基础
2.3.1 分治法
许多有用的算法在结构上是递归的,为了解决某个问题,算法依次或多次递归的
调用其自身已解决其紧密相关的若干子问题。这些算法典型遵循分治法的思想。
分治模式每层递归都有三个步骤:
分解 将原问题分解为若干子问题,这些子问题都是原问题较小的
实例。
实例:对
于给定输入序列成为问题的实例。
解决 递归的求解各子问题,如果子问题够小则可以直接求解。
合并 将子问题的解合并成原文题的解。
归并排序完全遵循分治模式。
分解 待排序的n个元素的序列成各具n/2个元素的两个子序列。
解决 递归的求解各个子问题,若子问题足够小,则直接求解
合并 合并两个已排序的子序列产生答案
原书伪代码(含哨兵 用于判断子序列元素是否用完)
排序部分
MERGE(A,p,q,r) //A待排数组,p起始项,q中间项,r末尾项
n1 = q - p + 1
n2 = r - q
//创建两个子序列L[1..n1+1],M[1..n2+1]
for i = 1 to n1
L[i] = A[q+j]
for j = 1 to n2
R[j] = A[q + j]
L[n1 + 1] = ∞ //哨兵
R[n2 + 1] = ∞
i = 1
j = 1
for k = p to r //两个已排列好子序列逐个个比较
if L[i] <= R[j]
A[k] = L[i]
i = i + 1
else A[k] = R[j]
j = j + 1
递归部分
MERGE-SORT(A,p,r)
if p < r
q = (p + r)/2
MERGE-SORT(A,p,q)//向下递推
MERGE-SORT(A,q+1,r)
MERGE(A,p,q,r) //调用排序
C语言实现(含哨兵)
#include<stdio.h>
void paixu(int a[],int p,int q,int r) //排序部分
{
int l[q-p+1+1],m[r-q+1]; //创建两个已排好的子序列
int k,i,j;
for(i = 0,k = p;i < q-p+1;i++,k++) //为子序列赋值
{
l[i]=a[k];
}
for(i = 0,k = q+1;i<r-q;i++,k++)
{
m[i]=a[k];
}
l[q-p+1]=999; //为哨兵赋值
m[r-q]=999;
k = 0;
i = 0;
j = 0;
for(k = p;k<r+1;k++) //子序列依次比较进行排序
{
if(l[i]<m[j])
{
a[k] = l[i];
i++;
}
else
{
a[k] = m[j];
j++;
}
}
}
void merge(int a[],int p,int r) //递归部分
{
int q;
q = (p+r)/2; //确定中间项
if(r>p)
{
merge(a,p,q); //分别递推
merge(a,q+1,r);
paixu(a,p,q,r); //排序当前两个经历过递推已排好序的子序列
}
}
int main()
{
int a[8], i = 0;
for(;i<8;i++)
scanf("%d",&a[i]);
merge(a,0,7); //调用递归进行排序
for(i = 0;i<8;i++)
printf("%d ",a[i]);
return 0;
}
C语言实现(不含哨兵)
#include<stdio.h>
void paixu(int a[],int p,int q,int r)
{
int l[q-p+1],m[r-q];
int k,i,j;
for(i = 0,k = p;i < q-p+1;i++,k++)
l[i]=a[k];
for(i = 0,k = q+1;i<r-q;i++,k++)
m[i]=a[k];
k = 0;
i = 0;
j = 0;
for(k = p;k<r+1;k++)
{
if(i != q-p+1&&j !=r-q)
{
if(l[i]<m[j])
{
a[k] = l[i];
i++;
}
else
{
a[k] = m[j];
j++;
}
}
else if(j == r-q)
{
a[k] = l[i];
i++;
}
else if(i == q-p+1)
{
a[k] = m[j];
j++;
}
}
}
void merge(int a[],int p,int r)
{
int q;
q = (p+r)/2;
if(r>p)
{
merge(a,p,q);
merge(a,q+1,r);
paixu(a,p,q,r);
}
}
int main()
{
int a[8],i = 0;
for(;i<8;i++) //read
scanf("%d",&a[i]);
merge(a,0,7);
for(i = 0;i<8;i++) //write
printf("%d ",a[i]);
return 0;
}