分而治之算法篇(一)
分而治之算法
分治法的步骤主要包括以下四步:
- 分割子问题:将原问题分割成若干个子问题,这些子问题与原问题在结构上相同或相似,通常每个子问题的规模都比较小。
- 解决子问题:对每个子问题进行递归解决,即对每个子问题重复执行分割和解决的过程,直到子问题的规模足够小可以直接解决。
- 合并子问题解:将所有子问题的解合并为一个解,这个解就是原问题的解。
- 返回结果:返回合并后的解。
归并排序算法思路实现
重要代表之一就是大名鼎鼎的归并排序算法。
归并是什么意思呢?归并作为合并的算法,归并算法的思想是将两个或着两个以上已经排序的序列合并成一个新的排序序列。举一个例子如下:
假设有两个已经按升序排序的数列A和B,分别是:
A: [1, 3, 5, 7] B: [2, 4, 6, 8]
将这两个数列合并成一个新的排序数列C的过程如下:
C = [1, 2, 3, 4, 5, 6, 7, 8]
归并算法的基本思路是将两个有序序列“合并”成一个新的有序序列。它的基本思路是将两个列表的头部元素进行比较,将较小的元素放入新的列表中,然后将该元素所在的列表的下一个元素移动到空闲位置,再继续比较新的列表的头部元素和另一个列表的头部元素,以此类推,直到两个列表都空闲,合并完成。通俗来说,归并算法就像是拼接两个已经排序好的拼图块,先将两个拼图块的头部拼接在一起,然后继续拼接下一个部分,直到整个拼图完成。这个算法的关键在于每次比较两个列表的头部元素,并将较小的元素放入新的列表中,以确保新的列表仍然是有序的。
归并算法——————————时间复杂度:O(nlog(n))——————————空间复杂度:O(n)——————————————
温馨提示:要进行m路归并,需要对比关键字m-1次。
对于一个数组的归并排序,我们通常是由二路归并实现的。再强调一遍,归并排序的本质是什么呢?把两个有序的数组合并成一个有序的大数组。
归并排序算法代码实现
为了合并两个子序列,我们需要定义一个相同容量的数组B。
原数组A:
定义数组B:
对于原数组A中元素部分可以发现(low-mid)和(mid+1-high)这两部分都是有序数组,符合归并算法的要求。
第一步,将A数组的元素按照下标复制到B数组中。
第二步,定义int a b c, 其中a = B数组中low的位置,b = B数组中mid+1的位置,c = A数组中low的位置。
第三步,比较B[a]和B[b],看谁更小,将更小的赋值给A[c],然后把B数组元素更小的下标后移比如 a = a + 1 或者 b = b +1 ,
然后将A中执行c = c + 1 (温馨提示:当遇到元素相同的时候,为了保证代码的稳定性优先使用靠前的)
第四步,B数组中的a或者b已经超出规定界限大小,然后我们把剩下的未合并的代码全部合并进新序列即可。
代码如下:
int * B_array = (int *)malloc(N*sizeof(int));
//merge sort ———— core code
void merge(int array[],int low,int mid,int high) //原数组array
{
int a , b , c;
for(a = low ; a <= high ; a++) {B_array[a] = array[a];} //copy array to B_array
for(a = low , b = mid + 1 , c = low ; a <= mid && b <= high ; c++){
if(B_array[a]<=B_array[b]){
array[c] = B_array[a++];
}else{
array[c] = B_array[b++];
}
}
while(a <= mid){
array[c++] = B_array[a++];
}
while(b <= high){
array[c++] = B_array[b++];
}
}
上面代码完成了归并排序的本质,即将两个有序的数组合并成一个有序的数组
完整的代码如下所示:采用了递归的思路先将无序数组一直向下分治,最后逐个解决再合并,运用了分治法的思想。
#include<stdio.h>
#include<stdlib.h>
#define N 10
int * B_array = (int *)malloc(N*sizeof(int));
//merge sort ———— core code
void merge(int array[],int low,int mid,int high) //原数组array
{
int a , b , c;
for(a = low ; a <= high ; a++) {B_array[a] = array[a];} //copy array to B_array
for(a = low , b = mid + 1 , c = low ; a <= mid && b <= high ; c++){
if(B_array[a]<=B_array[b]){
array[c] = B_array[a++];
}else{
array[c] = B_array[b++];
}
}
while(a <= mid){
array[c++] = B_array[a++];
}
while(b <= high){
array[c++] = B_array[b++];
}
}
//merge sort ———— call (使用递归的方法进行原数组排序)
void mergeSort(int array[],int low ,int high) //原数组,以及范围值
{
if(low < high)
{
int mid = (low+high) / 2;
mergeSort(array,low,mid); //先对左半部分进行归并排序
mergeSort(array,mid+1,high); //右半部分归并
merge(array,low,mid,high);
}
}
int main()
{
int arr[] = {1,2,9,8,7,5,10,20,4,6};
mergeSort(arr,0,9);
for(int i = 0 ; i <= 9 ; i++)
{
printf("%d ",arr[i]);
}
return 0;
}