分治法
子程序直接调用自己或通过一系列条用语句间接调用自己。分治和递归经常同时应用于算法设计之中,并由此产生许多高校的算法。分解--》求解--》合并
时间复杂度:O(nlogn)
归并排序C版(偏伪代码)
#include "MergeSort.h" #include<stdio.h> void MergeSort(int A[],int p,int r) { int q; if(p<r){ q=(p+r)/2; MergeSort(A,p,q); MergeSort(A,q+1,r); Merge(A,p,q,r) } } void Merge(int A[],int p,int q,int r) { int n1=q-p+1;//一个数组的长度p到q int n2=r-q;//一个数组的长度从q+1到r int i,j,k; int L[50],R[50]; for(i=0; i<n1; i++) { L[i]=A[p+i];//把A数组左边放入新的数组 } for(j=0; j<n2; j++) { R[j]=A[q+1+j];////把A数组右边放入新的数组 } L[n1]=INT_MAX; R[n2]=INT_MAX; j=0; i=0; for(k=p; k<r+1; k++) { if(L[i]<R[j])// 当前元素小于左边的当前元素则取右半边的元素 { A[k]=L[i]; i++; } else { A[k]=R[j]; j++; } } }
归并排序C版本2(偏伪)
#include "Merge.h" #include<stdlib.h> #define MAX 65536 void merges(int arr[],int p,int q,int r) { int *left,*right; int n1,n2,i,j,k; n1=q-p+1; n2=r-q; if((left=(int*)malloc((n1+1)*sizeof(int)))==NULL) { perror("malloc error"); exit(1); } if((right=(int*)malloc((n2+1)*sizeof(int)))==NULL) { perror("malloc error"); exit(1); } //复制数组 for(i=0; i<n1; i++) { left[i]=arr[p+1]; } left[i]=MAX; for(i=0; i<n2; i++) { right[i]=arr[q+i+1]; } right[i]=MAX; //归并开始 i=0; j=0; for(k=p; k<=r; k++) //从头到尾遍历 { if(left[i]<right[j]) { arr[k]=right[j]; j++; } else { arr[k]=left[i]; i++; } } void mergesort(int arr[],int begin,int end) { int mid; if(begin<end) { mid=(begin+end)/2; mergesort(arr,begin,mid); mergesort(arr,mid+1,end); merges(arr,begin,end); } } }
最大子段和
注意是子段肯定是连续的不能跳跃,(-2,11,-4,13,-5,-2)时,子段{11,-4,13}为最大子段,和为20。
第一种情况: 计算 left 到 center 的最大和,记作 leftSum
第二种情况: 计算从 center+1 到 right的最大和,记作 rightSum
第三种情况: 跨边界的和。以center为中心分别向两边计算和。
a.从 center出发,每次向左边扩张一步,并且记录当前的值S1,如果当前的和比上次的和大,就更新S1,一 直向左扩张到 位置 Left。
b.从 center+1出发,每次扩张一步,计算当前的和 为S2,如果当前的值比上次的和 大,那么,就更新S2的 值,一直向右扩张到位置Right。
c.计算过center的连续值的和,S1+S2的值 Sum。 这个就是跨边界的和。
上面三种情况考虑计算完成后,最后一步就是,比较三个值中的最大值,取最大值就可以了。
---参考https://www.cnblogs.com/lixing-nlp/p/7629403.html
#include<stdlib.h> /*求解最大子段*/ int MaxSubSum(int *Array,int left,int right) { int sum=0; int i; if(left==right)//特殊情况 { if(Array[left]>0) { sum=Array[left]; } else { sum=0; } } else { int center = (left+right)/2; int leftsum=MaxSubSum(Array,left,center); int rightsum=MaxSubSum(Array,center+1,right); int s1=0; int lefts=0; for(i=center; i>=left; i--)//左边的数向左蔓延相加求和 { lefts=lefts+Array[i]; if(lefts>s1) { s1=lefts; } } int s2=0; int rights=0; for(i=center; i<=rights; i++)//右边的数向右蔓延相加求和 { rights=rights+Array[i]; if(rights>s2) { s2=rights; } } sum=s1+s2;//过center的值 if(sum<lefts) { sum=leftsum; } if(sum<rightsum) { sum=rightsum; } } return sum; }