排序优化,如何实现一个通用的高效的排序算法
比如linux系统最底层的api几乎其他所有库都会依赖glibc,下面讲一下glibc中c语言实现的qsort()方法实现
1.qsort()优先使用归并算法
虽然空间o(n)但在所需大小很小时,问题不大,空间换时间,实现快速
2.如果超过100mb,qsort()使用快排
分界点使用三数取中,防止递归深度导致栈溢出,递归实现通过手动模拟递归实现
3.当快排区间元素小于等于4时,qsort()退化为插入排序
因为小规模数据,o(n^2)不一定比o(nlogn)慢,时间复杂度不一定等于实际运行时间
比如java中Arrays.sort()采用TimSort方法
1.元素个数<32
二分查找插入排序
2.元素个数>=32
归并算法,归并算法核心是分区,以连续升序或降序为分区,最终调为升序入栈,如果分区太小采用二分查找插入排序扩充分区长度到最小值
补:二分查找上,针对有序的数列,思想是分治思想,类似数学中的特值法猜测答案,每次都给中间元素比,省掉一半区间,可以实现o(logn)对数级别非常恐怖的时间复杂度,有时比o(1)还更有效(常量可以是10000,但对数就是100),下面以不存在重复元素举例
1.非递归实现
public int bsearch(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (a[mid] == value) {
return mid;
} else if (a[mid] < value) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
注:
i.循环退出条件low<=high要取等
ii.在low,high比较大的时候,mid会溢出,可用low+(high-low)/2,还可以优化为low+((high-low)>>1)(因为运算优先级)
iii.high,low更新
2.递归实现
// 二分查找的递归实现
public int bsearch(int[] a, int n, int val) {
return bsearchInternally(a, 0, n - 1, val);
}
private int bsearchInternally(int[] a, int low, int high, int value) {
if (low > high) return -1;
int mid = low + ((high - low) >> 1);
if (a[mid] == value) {
return mid;
} else if (a[mid] < value) {
return bsearchInternally(a, mid+1, high, value);
} else {
return bsearchInternally(a, low, mid-1, value);
}
}
注:分治递归,必须写明数组对象和对象的具体区间
3.限定条件
二分查找只能用于数组储存和数据有序,且数据量不能太小(直接顺序遍历就好了)也不能太大(毕竟用数组存储,消耗太大)
4.课后题
实现一个数平方根,精确小数后6位数
解:二分法思想核心循环区间二分,通过中点来精确查找目标数值的区间,最后实现近似值和准确值,特别类似数学方法中的近似值
i*i=x,比如[0,x],找到区间中点m,检查m*m与x大小比较,若m*m>x取[0,m]反之则取[m,x],直到区间长度小于10(^-6)