算法复杂度
- O(1):常量阶,运行时间为常量
- O(logn):对数阶,如二分搜索算法
- O(n):线性阶,如n个数内找最大值
- O(nlogn):对数阶,如快速排序算法
- O(n^2):平方阶,如选择排序,冒泡排序
- O(n^3):立方阶,如两个n阶矩阵的乘法运算
- O(2^n):指数阶,如n个元素集合的所有子集的算法
- O(n!):阶乘阶,如n个元素全部排列的算法
排序
冒泡
-
基本思想:遍历数组,每次从头开始两两比较。
-
过程:
- 第一趟从头到尾,两两比较,大的遇到小的进行交换,直到数组结尾;
- 第二趟从头到数组长度减一(沉底数不去比较),两两比较,大的遇到小的进行交换;
- ....
private static int[] myBubbleSort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1 - i; j++) {
int tmp;
if (a[j] > a[j + 1]) {
tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
}
}
}
return a;
}
//注意边界情况
选择
基本思想:在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;如此向后遍历
private static int[] myChooseSort(int[] a) {
for (int i = 0; i < a.length; i++) {
//首先假定当前是最小的数
int minindex = i;
for (int j = i+1; j < a.length; j++) {
//如果假设的最小的数大于正在遍历的数则交换
if(a[minindex] > a[j] ){
minindex = j;
}
}
int tmp = a[i];
a[i] = a[minindex];
a[minindex] = tmp;
}
return a;
}
插入
基本思想:从第一位开始认为第一位已经排好序;滑到第二位和第一位比较,如果第一位大,交换,则认为第一二位已经排好序;滑到第三位和前面比较,如果第二位大,交换,如果第一位小,不交换;.... 以此类推直到最后一位。
private static int[] myInsertSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
// int tmp = arr[j];
// arr[j] = arr[j + 1];
// arr[j + 1] = tmp;
arr[j] = arr[j] ^ arr[j+1];
arr[j+1] = arr[j] ^ arr[j+1];
arr[j] = arr[j] ^ arr[j+1];
}
}
return arr;
}
最差 需要从小到大 得到从大到小 O(n^2) 最好 需要从小到大 得到从小到大 O(n)
复杂度一律按最差复杂度
归并
基本思想:主要采用分治(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)策略;先将数组分成左右两大部分,再继续递归实现左右的排序完成,最后从左右数组头部开始同时移动比较,将数据放入新的数组。
public static void myMergeSort(int[] arr , int L ,int R) {
if(L==R){
return ;
}
int mid = (L+R)/2;
myMergeSort(arr, 0, mid);
myMergeSort(arr, mid+1, R);
merge(arr, L, mid , R);
}
public static void merge(int[] arr, int l, int m, int r) {
int[] help = new int[r - l + 1];
int i = 0;
int p1 = l;
int p2 = m + 1;
while (p1 <= m && p2 <= r) {
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= m) {
help[i++] = arr[p1++];
}
while (p2 <= r) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[l + i] = help[i];
}
}
对数器的概念和使用
- 有一个你想要测的方法a,
- 实现一个绝对正确但是复杂度不好的方法b,
- 实现一个随机样本产生器
- 实现比对的方法
- 把方法a和方法b比对很多次来验证方法a是否正确。
- 如果有一个样本使得比对出错,打印样本分析是哪个方法出错
- 当样本数量很多时比对测试依然正确,可以确定方法a已经正确。
剖析递归行为和递归行为时间复杂度的估算
一个递归行为的例子 master公式的使用
T(N) = a*T(N/b) + O(N^d)
1) log(b,a) > d -> 复杂度为O(N^log(b,a))
2) log(b,a) = d -> 复杂度为O(N^d * logN)
3) log(b,a) < d -> 复杂度为O(N^d)