分治法:将一个规模为n 的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些子问题,然后将各子问题的解合并得到原问题的解。
大量实践表明,将问题分成大小相等的两个子问题的方法是行之有效的,它几乎总比子问题规模不等的的做法要好。
例1:二分搜索
将n个元素分成大致相同的两半,取a[n/2]与x进行比较。如果x=a[n/2],则找到x,算法中止。如果x<a[n/2],则只要在数组a的左半部分继续搜索x。如果x>a[n/2],则只要在数组a的右半部分继续搜索x。
#include<iostream>
using namespace std;
int search(int left, int right);
int arr[100];
int cnt, aim;
int main(){
cin >> cnt;
for(int i = 0; i < cnt; i++)
cin>>arr[i];
cin>>aim;
cout<< search(0, cnt-1) <<endl;
}
int search(int left, int right){ //本例按照输入序列升序搜索
if(left < 0 || right >= cnt || left > right) //若不符合搜索条件,报错
return -1;
int middle = (left + right) / 2;
if(arr[middle] == aim) //搜索到目标值,返回目标值地址
return middle;
else if(arr[middle] > aim) //中值大于目标值,向左搜索
return(search(left, middle-1));
else //中值小于目标值,向右搜索
return(search(middle+1, right));
}
例2:合并排序
将待排序元素分成大小大致相同的2个子集,分别对2个子集合进行排序,最终将排好序的子集集合合并成为所要求的排好序的集合。
#include<iostream>
#define MAX 10000
using namespace std;
void merge(int left,int middle, int right);
void merge_sort(int a, int b);
void output();
int arr[100];
int len;
int main(){
cin>>len;
for(int i = 0; i < len; i++)
cin>>arr[i];
merge_sort(0, len-1);
output();
}
//将序列两等分
void merge_sort(int a, int b){
if(a < b){
int mid = (a + b) / 2;
merge_sort(a, mid);
merge_sort(mid+1, b);
merge(a, mid, b);
}
}
//合并序列
void merge(int left, int middle, int right){
int l = middle-left+1, r = right-middle;
int L[50], R[50];
for(int i = 0; i < l; i++){ //前一半包括中点放在L[]
L[i] = arr[left+i];
}
for(int i = 0; i < r; i++){ //后一半放在R[]
R[i] = arr[middle+i+1];
}
L[l] = MAX, R[r] = MAX;
l = 0, r = 0;
for(int i = 0; i < right-left+1; i++){ //找出L[],R[]中的最小值放入arr[],使按升序排列
if(L[l] < R[r]){
arr[left+i] = L[l];
l++;
}
else{
arr[left+i] = R[r];
r++;
}
}
}
void output(){
for(int i = 0; i < len; i++){
cout<<arr[i]<<" ";
}
cout<<endl;
}
例3:快速排序
对于输入的子数组a[p:r],按以下三个步骤进行排序:
(1)分解(divide):以a[p]为基准元素将a[p:r]划分为3du'a段a[p : q-1], a[q]和a[q+1 : r], 使得a[p : q-1]中任何元素小于de等于a[q], a[q+1 : r]中任何元素小于等于a[q], a[q+1, r]中任何元素大于等于a[q]。
(2)递归求解(conquer):通过递归调用快速排序算法,分别对a[p : q-1]和a[q+1 : r]进行排序。
(3)合并(merge):由于du对a[p : q-1]和a[q+1 : r]的排序使就地进行的,所以在a[p : q-1]和a[q+1 : r]都已经排好的序后不需要执行ren'任何计算,a[p : r]就已pai排好序。
#include<iostream>
using namespace std;
void swap(int *a, int *b);
void quick_sort(int left, int right);
void output();
int arr[100];
int len;
int main(){
cin>>len;
for(int i = 0; i < len; i++)
cin>>arr[i];
quick_sort(0, len-1);
output();
}
//快排函数
void quick_sort(int left, int right){
int i, j;
if(left < right && arr[left] != arr[right]){
i = left+1;//选第一个数字作为基数
j = right;
while(i < j){
if(arr[i] > arr[left]){
swap(&arr[i], &arr[j]);
j--;
}
else{
i++;
}
}
if(arr[i] > arr[left]){
i--;
}
swap(&arr[i], &arr[left]);
quick_sort(left, i);
quick_sort(i+1, right);
}
}
//交换函数
void swap(int *a, int *b){
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
return ;
}
void output(){
for(int i = 0; i < len; i++){
cout<<arr[i]<<" ";
}
cout<<endl;
}
4.循环赛日程表
安排运动员的比赛时间,使两两之间比赛一场,每天赛一场。
#include<iostream>
using namespace std;
void table(int l, int r, int k);
void copy(int tox, int toy,int fromx, int fromy,int r);
void output();
int arr[200][200];
int n;
int main(){
cin >> n;
for(int i = 0; i < n; i++){
arr[i][0] = i+1;
}
table(0 , 0, n);
output();
}
void table(int l, int r, int k){
if(k == 1){
arr[l][r+1] = arr[l+1][r];
arr[l+1][r+1] = arr[l][r];
}
else{
table(l, r, k/2);
table(l+k/2, r, k/2);
copy(l, r+k/2, l+k/2, r, k/2); //左下复制到右上
copy(l+k/2, r+k/2, l, r, k/2); //左上复制到右下
}
}
void copy(int tox, int toy, int fromx, int fromy, int r){
for(int i = 0; i < r; i++){
for(int j = 0; j < r; j++){
arr[tox+i][toy+j] = arr[fromx+i][fromy+j];
}
}
}
void output(){
int i, j;
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
cout << arr[i][j] << " ";
}
cout << endl;
}
cout << endl;
}