分治三步骤:
分解:将原问题分解为若干个模块较小,相互独立,与原问题形式相同的子问题。
解决:把规模较小容易被解决的直接解,否则递归解各个子问题。
合并:将子问题的解合并为原问题的解。
1 归并排序
数组排序任务可以如下完成:
1) 把前一半排序
2) 把后一半排序
3) 把两半归并到一个新的有序数组,然后再拷贝回原数组,排序完成。
// -------- 代码实现归并排序 ---------
#include<iostream>
using namespace std;
int a[10]={5,7,9,1,8,4,6,10,3,2}, b[10];
//将数组a的局部a[s,m]和a[m+1,e]合并到temp,并保证temp有序,然后再拷贝回a[s,m]
// 归并时间复杂度:O(e-m+1),即O(n)
void Merge(int a[], int s, int m, int e, int temp[]){
int pb=0; // 指向临时数组
int p1=s, p2=m+1; // 分别指向前一半和后一半数组
while(p1<=m && p2<=e){
if(a[p2] < a[p1])
temp[pb++] = a[p2++];
else
temp[pb++] = a[p1++];
}
while(p1<=m)
temp[pb++] = a[p1++];
while(p2<=e)
temp[pb++] = a[p2++];
for(int i=0; i<pb; i++){
a[s+i] = temp[i];
}
}
//对数组a,将a[s]到a[e]归并排序
void MergeSort(int a[], int s, int e, int temp[]){
if(s < e){
int m = s +(e-s)/2;
MergeSort(a,s,m,temp); // 前一半排序
MergeSort(a,m+1,e,temp);// 后一半排序
Merge(a,s,m,e,temp); // 合并
}
}
int main(){
int length = sizeof(a)/sizeof(int); // 需要排序的元素个数
MergeSort(a,0,length-1,b); // 归并函数
for(int i=0;i<length;i++)
cout<<a[i]<<' ';
return 0;
}
归并排序的时间复杂度
对n个元素进行排序的时间
T(n)=2∗T(n2)+a∗n=2∗(2∗T(n4)+a∗n2)+a∗n=4∗T(n4)+2a∗n=4∗(2∗T(n8)+a∗n4)+2a∗n=8∗T(n8)+3a∗n=⋯=2k∗T(n2k)+ka∗n
一直做到 n2k=1 , 此时 ( k=log2n ),
T(n)=2k∗T(1)+ka∗n=2k+ka∗n=n+a∗(log2n)∗n
复杂度 O(nlogn) 。
2 快速排序
数组排序任务可以如下:
1)设k = a[0],将k挪到适当位置,使得比k小的元素都在k左边,比k大的元素都在k右边。(O(n)时间完成)
2)把k左边的部分快速排序
3)把k右边的部分快速排序
#include<iostream>
using namespace std;
//对数组a,从a[s]到a[e]进行快排
void QuickSort(int a[], int s, int e){
if(s >= e) return;
int key = a[s];
int left = s, right = e;
while(left != right){
while(left<right && a[right]>=key) //从右往左找到比key小的
right--;
a[left] = a[right];
while(left<right && a[left]<=key) //从左到右找到比key大的
left++;
a[right] = a[left];
}
a[left] = key; //此时left和right相等
QuickSort(a,s,left-1);
QuickSort(a,left+1,e);
}
int main(){
int a[]={5,7,9,1,8,4,6,10,3,2};
int length = sizeof(a)/sizeof(int);
QuickSort(a,0,length-1);
for(int i=0;i<length;i++)
cout<<a[i]<<' ';
return 0;
}