文章目录
前言
- 这系列主要是学习一些基础的算法,算法是一个程序员的内功,内功的高低决定了我们的武功上限.
- 程序 = 数据结构 + 算法
我们设计的程序中,程序的"逻辑流程"就是由一个个算法组成,而算法是基于某个/某些数据结构的(数组,hashmap等).
评估算法优劣的核心指标
一般只考虑样本数据为最差的情况,比如我们要正序排序一个数组,就考虑它现在是逆序的情况.
- 1.时间复杂度(流程决定)
- 2.额外空间复杂度(流程决定)
- 3.常数项时间(实现细节决定)
一般值比较时间复杂度就够啦;
如果想精确比较,那么就由1到3一次比较,权重越来越小
一般情况下,认为解决一个问题的算法流程,在时间复杂度的指标上,一定要尽可能的低,先满足了时间复杂度最低这个指标之后,使用最少的空间的算法流程,叫这个问题的最优解。
一般说起最优解都是忽略掉常数项这个因素的,因为这个因素只决定了实现层次的优化和考虑,而和怎么解决整个问题的思想无关。
时间复杂度(流程决定)
时间复杂度就是总操作数量与样本数量之间的表达式关系,用来衡量一个算法(流程)中,发生了多少次常数操作.
我们只关心最高阶项的阶数,因为样本量足够大的时候,起决定性作用的就是它.
比如f(n1)=3n2,它的时间复杂度就是O(n2),
f(n2) = an + b,它的时间复杂度就是O(n),
我们就认为f(n2)是比f(n1)更优秀的算法
常数操作
如果一个操作的执行时间不以具体的样本量为转移,每次执行都是固定时间,这样的操作称作常数时间的操作.
常见的常数时间的操作
- 常见的算术运算(+、-、*、/、% 等)
- 常见的位运算(>>、>>>、<<、|、&、^等)
“>>” 带符号右移,正数用0补高位,负数用1补
">>>"不带符号右移,都用0补高位 - 赋值、比较、自增、自减操作等
- 数组的寻址操作.(相反,链表的寻址就不是常数操作)
如何确定算法流程的总操作数量与样本数量之间的表达式关系
- 想象该算法流程所处理的数据状况,要按照最差情况来。
- 把整个流程彻底拆分为一个个基本动作,保证每个动作都是常数时间的操作。
- 如果数据量为N,看看基本动作的数量和N是什么关系。
常见的时间复杂度
排名从好到差:
O(1)
O(logN)
O(N)
O(N*logN)
O(N^2) O(N^3) … O(N^K)
O(2^N) O(3^N) … O(K^N)
O(N!)
简单分析 选择排序,冒泡排序,插入排序的时间复杂度
其实都是O(n2),只不过选择排序和冒泡排序不受样本数据的影响,而插入排序可能会因为样本数据的局部有序而节约时间.
选择排序
有一个数组,长度为n,那么
第一次从0~n-1中找出最小的一个,让它和0位置上的数交换,n此的看+比,和1次交换,n*(2)+1
第二次从1~n-1中选择最小的一个,让它和1位置上的数交换,(n-1)*(2)+1;
…
第n次从n-1~n-1中选择最小的一个,让它和n-1位置上的数交换;(其实啥也不用做),1
时间复杂度为:2*(n+n-1+…+1) + n = x * n2 + y * n + n + c = O(n2)
等差数列可以写成aN2+bN+c,1+2+3+…+n = (n+1)n/2 = 1/2n2 + 1/2*n
public static void selectionSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
int minIndex;
for (int i = 0; i < arr.length - 1; i++) {
minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
if (arr[minIndex] < arr[i]) {
swap(arr, minIndex, i);
}
}
}
public static void swap(int[] arr, int i, int j) {
if (i == j) {
return;
}
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
冒泡排序
有一个数组arr,长度为n,
我们设一个操作为f(a):比较两个元素 如果arr[a]>arr[a+1],则把这两个位置的元素交换
那么
第一次在0到n-1之间,从0到n-2做f(a)操作,f(0),f(1),f(2)…f(n-1);
第二次从0到n-2之间,从0到n-3做f(a)操作;
…
第n-1次完事.
这也是个等差数列,所以时间复杂度也是O(n2)
public static void sort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
/*for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
}
}
}*/
for (int e = arr.length - 1; e > 0; e--) {
// 0 ~ e
for (int i = 0; i < e; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
}
}
}
}
插入排序
有一个数组arr,长度为n,
第一次,保持位置0到0上有序,啥也