主要有几个衡量的指标:
- 时间复杂度:主要有
- 空间复杂度:有些排序算法需要额外的辅助空间,而有些则能实现“原地排序”;
- 稳定性:相同的元素在排序之前和排序之后相对位置是否有可能发生变化;
- 适用条件:算法是否有些额外的限制条件
在我的见解中,整数的线性排序,就需要一个hash计数数组就行,效率很高。缺点就是额外空间。
基数排序:应对数值很大的情况。“越重要的越在后面比较”。缺点是不呈现时空局部性,因为在按位对每个数进行排序的过程中,一个数的位置可能发生巨大的变化,所以不能充分利用现代机器缓存提供的优势。
求子数组最大和问题:
1.暴力枚举:
int maxSubArray(int *A,int n) { int maxium = -INF; //保存最大子数组之和 for i=0 to n-1 do sum = 0; //sum记录第i到j的元素之和 for j=i to n-1 do sum += A[j]; if sum>maxium do //更新最大值 maxium = sum; return maxium; }
复杂度为O(n2)。
2.分支界定法
复杂度为O(nlogn),如果把组分为一半,最大和可能在左子组或者右子组,或跨组(从中线向左向右找max求和)。
int maxSubArray(int *A,int l,int r) { if l<r do mid = (l+r)/2; ml = maxSubArray(A,l,mid); //分治 mr = maxSubArray(A,mid+1,r); for i=mid downto l do search maxleft; for i=mid+1 to r do search maxright; return max(ml,mr,maxleft+maxright); //归并 then //递归出口 return A[l]; }
3.动态规划
int maxSubArray(int *A,int n) { cursum = A[0]; maxsum = A[0]; for i=1 to n-1 do /*当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。*/ if cursum<0 do cursum = 0; cursum += A[i]; if cursum>maxsum do maxsum = cursum; return maxsum; }
复杂度只是O(n),必要扩展还可以记录最大和子组的起始终止位置。