9.11-分治(//二分搜索//合并排序//快速排序//循环赛日程表)

       分治法:将一个规模为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;
}

 

 

5.求第k小数

暂时还没有更好的方法,暴力快排输出>-<

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值