分治解决归并排序

101 阅读2分钟

分治基本概念

把一个任务分成形式和原任务相同,但规模更小的几个部分子任务,分别完成,或只需要选一部分完成。然后再处理完成后的这一个或几个部分的结果,实现整个任务的完成。

动态规划基本概念

通常许多子问题非常相似,为此动态规划试图仅仅解决每个子问题一次,从而减少计算量,算出子问题的解之后,则将其记忆化存储。

归并排序的解题思路: 数组排序任务可以按如下步骤完成:

(1)把前一半排序

(2)把后一半排序

(3)把两半归并到一个新的有序数组,然后再拷贝回原数组,排序完成

QQ截图20220323214655.jpg 类似这样的,可以用两个指针p1,p2分别指向两个数组的起始位置,在前面做题的时候也遇到过链表的,链表思想类似,然后比较,小的那个存入临时数组tmp且指针往后移,tmp的指针pb在存放数据之后也跟随往后移指向下一个空的存储位置,最后别忘了处理长度一样的情况,其中有一个数组已经走到了头,则把剩下的元素存入后面。

代码如下:

`#include using namespace std;

int a[10] = { 13,27,19,2,8,12,2,8,30,89 };

int b[10];

void Merge(int a[], int s, int m,int e, int tmp[]) // a待排序的数组 tmp存放结果的临时数组 sm为起点和终点下标

{ //将数组a的局部a[s,m]和a[m+1,e]合并到tmp,并保证tmp有序, //然后再拷贝回a[s,m]

int pb = 0; // tmp数组初始指针指向起始位置
int p1=s, p2=m+1; //分开比较的两个数组指针
while (p1 <= m && p2 <= e) {
	if (a[p1] < a[p2])
		tmp[pb++] = a[p1++];  // 小的存入并往后移  tmp数组存完也往后一个位置
	else
		tmp[pb++] = a[p2++];
}
//其中有一个已经走到了头
while (p1 <= m)  //p2走完了  p1还没走完
	tmp[pb++] = a[p1++];  //把后面剩下的存入tmp
while (p2 <= e)
	tmp[pb++] = a[p2++];

//拷贝回a数组
for (int i = 0; i < (e - s) + 1; i++)
	a[s + i] = tmp[i];

}

void MergeSort(int a[],int s,int e,int tmp[])

{ int m;

m = s + (e - s) / 2;
    
if (s < e)
{
	MergeSort(a, s, m, tmp);
	MergeSort(a, m + 1, e, tmp);
	Merge(a, s, m, e, tmp);
}

} int main() {

int size = sizeof(a) / sizeof(int);
    
MergeSort(a, 0, size - 1, b);
    
for (int i = 0; i < size; i++)
{
	cout << a[i] << ",";
}
cout <<endl;
return 0;

} `

QQ截图20220323215146.jpg 时间复杂度为O(nlongn),当比较到数组中只剩下一个元素是算法终止,即
T(n/2^k), 也就是n/2^k=1时成立,具体推导如下:

QQ截图20220323215223.jpg