第二章
算法基础
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; }