文章目录
- 1. 分治算法思想
- 2. 应用举例
- 2.1 逆序度
- 3. 分治思想处理海量数据
1. 分治算法思想
- 分治算法的核心思想就是,分而治之,将原问题划分成n个规模较小,并且结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解。
- 分治算法一般都比较适合用递归来实现。分治算法的递归实现中,每一层递归都会涉及这样三个操作:
-1- 分解:将原问题分解成一系列子问题;
-2- 解决:递归地求解各个子问题,若子问题足够小,则直接求解;
-3- 合并:将子问题的结果合并成原问题。
分治算法能解决的问题,一般需要满足下面这几个条件:
- 原问题与子问题具有相同的模式;
- 子问题可以独立求解,子问题之间没有相关性,这一点是分治算法跟动态规划的明显区别;
- 具有分解终止条件,也就是说,当问题足够小时,可以直接求解;
- 可以将子问题合并成原问题,这个合并操作的复杂度不能太高。
2. 应用举例
2.1 逆序度
假如需要从小到大排序,大的数在小的数前面则记逆序数+1
- 暴力的方法:分别对每个数,看后面有几个比它小的,双重循环,复杂度O(n2)
- 归并排序法:
将原序列分成A1,A2两个序列,分别计算它两的逆序度K1,K2,再计算A1,A2之间的逆序度K3,原序列逆序度就是 K1+K2+K3
/*** @description: 分治法求逆序数(归并排序法)* @author: michael ming* @date: 2019/7/3 23:27* @modified by: */
#include <iostream>
class ReverseOrderCount
{int sum;void divide(int *a, int left, int right){if(left >= right)return;int mid = (left+right)/2;divide(a,left,mid);divide(a,mid+1,right);merge(a,left,mid,right);}void merge(int *a, int left, int mid, int right){int i = left, j = mid+1, len = right-left+1, idx = 0;int *temp = new int [len];while(i <= mid && j <= right){if(a[i] <= a[j])temp[idx++] = a[i++];else{sum += mid-i+1;//左边i后面的都比a[j]大temp[idx++] = a[j++];}}while(i <= mid)//剩余的半边temp[idx++] = a[i++];while(j <= right)//剩余的半边temp[idx++] = a[j++];for(idx = 0; idx < len; ++idx){a[left++]= temp[idx]; //把有序的临时数组写入原来数组的起始位置}delete [] temp; //释放空间temp = NULL; //指针置空}
public:int count(int *a, int n){sum = 0;divide(a,0,n-1);return sum;}
};int main()
{ReverseOrderCount roc;int arr[6] = {2,4,3,1,5,6};std::cout << "arr数组的逆序数是:" << roc.count(arr,6);return 0;
}
- 练习题 http://poj.org/problem?id=2299
Accepted代码如下
https://github.com/hitskyer/course/blob/master/c/chenmingming/algorithm/POJ/poj2299_B.cpp
3. 分治思想处理海量数据
比如,给10GB的订单文件按照金额排序,看似是一个简单的排序问题,但是因为数据量大,有10GB,机器的内存可能只有2、3GB这样子,无法一次性加载到内存,也就无法通过单纯地使用快排、归并等基础算法来解决。
- 利用分治思想。将海量的数据集合划分为n个小的数据集合,每个小的数据集合单独加载到内存来解决,然后再将小数据集合并成大数据集合。
- 利用分治,不仅仅能克服内存的限制,还能利用多线程或者多机处理,加快处理的速度。海量的数据利用集群并行处理是大势所趋。