1.估计递归算法复杂度
N:样本总量
a:递归分支数
b:子过程数
2.归并排序
应用
- 小和问题
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组
的小和。
例子:
[1,3,4,2,5]
1左边比1小的数,没有;
3左边比3小的数,1;
4左边比4小的数,1、3;
2左边比2小的数,1;
5左边比5小的数,1、3、4、2;
所以小和为1+1+3+1+1+3+4+2=16
int smallSum(int *arr, int length)
{
int ret = __mergeSort(arr, 0, length-1);
return ret;
}
int __mergeSort(int *arr, int l, int r)
{
if(!arr || l==r)
return;
int mid = l + (r-l)/2;
int lsum = __mergeSort(arr, l, mid);
int rsum = __mergeSort(arr, mid+1, r);
return lsum+rsum+__merge(arr, l, mid, r);
}
int __merge(int *arr, int l, int mid, int r)
{
int *help = new int[r-l+1];
int i = 0;
int p1 = l;
int p2 = mid+1;
int ret = 0;
while(p1<=mid && p2<=r)
{
res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;
help[i++] = arr[p1]<arr[p2]?arr[p1++]:arr[p2++];
}
while(p1<=mid)
help[i++] = arr[p1++];
while(p2<=r)
help[i++] = arr[p2++];
for(int i=0; i<r-l+1; i++)
arr[i+l] = help[i];
return ret;
}
- 逆序对
逆序对
3. 堆排序
void heapSort(int[] arr, int len)
{
if(!arr || len<2) return ;
for(int i=0; i<len; i++)
heapInsert(arr, i);
int size = len;
swap(arr[0], arr[--size]);
while(size > 0)
{
heapify(arr, 0, len);
swap(arr[0], arr[--size]);
}
}
void heapInsert(int[] arr, int index)
{
while(arr[index] > arr[(index-1)/2])
{
swap(arr[index], arr[(index-1)/2]);
index = (index-1)/2;
}
}
void heapify(int[] arr, int index, int len)
{
int left = index*2+1;
while(left < len)
{
int largest = left+1<len && arr[left+1]>arr[left]?left+1:left;
largest = arr[largest]>arr[index]?largest:index;
if(largest == index)
break;
swap(arr[largest], arr[index]);
index = largest;
left = index*2+1;
}
}
例子
求中位数
一个大根堆,一个小根堆。
一个数<=大根堆堆顶元素,插入到大根堆
否则插入到小根堆。
当两堆元素差值>1,从多的一堆拿出堆顶元素放入到另一个堆中。
4. 算法稳定性
- 意义:
希望排序之前前后相对信息保存下来
姓名 | 班级 | 分数 |
---|---|---|
张 | 1班 | 60 |
王 | 2班 | 30 |
李 | 1班 | 70 |
首先通过分数进行排序,然后通过班级进行排序,需要采用稳定的排序算法,因为想在相同班级里的学生分数从低到高排序。
-
O(N^2)
冒泡:可以
插入:可以
选择:不行
例:5 5 5 5 0 1 选择一个最小的与最前面交换 -
O(nlgn)
归并:可以
快排:不行
堆排:不行
例:将 4 4 4 5 建堆 -
工程中的综合排序算法:
样本量小于60时,插入排序
样本量大,
数据类型是基础类型用快排,自定义类型用归并(稳定性) -
桶排序
计数排序
基数排序
例子:
给定一个数组,求排序之后相邻两数的最大差值。时间复杂度O(N),且用非基于比较的排序。
int maxGap(int *arr, int len)
{
if(!arr || len<2) return 0;
int _min = INT_MAX;
int _max = INT_MIN;
for(int i=0; i<len; i++)
{
_min = min(_min, arr[i]);
_max = max(_max, arr[i]);
}
if(_min == _max) return 0;
bool *hasNum = new bool[len+1]; //生成 len+1 个桶
int *minNum = new int[len+1]; //每个桶保存三种信息
int *maxNum = new int[len+1];
for(int i=0; i<len; i++)
{
int index = bucket(arr[i], len, _min, _max); //将每个数放入到相应桶中
minNum[index] = hasNum[index]?min(arr[i],minNum[index]):arr[i];
maxNum[index] = hasNum[index]?max(arr[i],maxNum[index]):arr[i];
hasNum[index] = true;
}
int ret = 0;
int lastMax = maxNum[0];
for(int i=1; i<len; i++)
{
if(hasNum[i])
{
ret = max(ret, minNum[i]-lastMax);
lastMax = maxNum[i];
}
}
return ret;
}
int bucket(long num, long len, long min, long max)
{
return (int) ((num - min) * len / (max - min));
}