简单的线性查找算法
/**
* 线性查找算法
*/
public class LinearSearch {
/**
* 获取target在数组中的下标
*/
public static int linearFind(int[] data,int target){
for (int i = 0; i < data.length; i++)
if (data[i] == target)
return i;
// 查询不到返回-1
return -1;
}
public static void main(String[] args) {
int[] data = {12,23,34,45,56,66,67,89,23};
int i = LinearSearch.linearFind(data, 66);
System.out.println("打印返回值:" + i); // 返回值为5
}
}
使用泛型优化代码
/**
* 线性查找算法
*/
public class LinearSearch {
/**
* 获取target在数组中的下标
*/
public static <E> int linearFind(E[] data,E target){
for (int i = 0; i < data.length; i++)
// 使用泛型,是对象类的比较
if (data[i].equals(target))
return i;
// 查询不到返回-1
return -1;
}
public static void main(String[] args) {
Integer[] data = {12,23,34,45,56,66,67,89,23};
int i = LinearSearch.linearFind(data, 66);
System.out.println("打印返回值:" + i); // 返回值为5
}
}
什么是循环不变量
循环不变量,是指让每次循环都成立的逻辑表达式,用于证明整个算法的正确性
要证明循环正确,必须在以下三个环节中,考虑循环不变量的真假。
循环初始状态:在所有循环体执行前,循环不变量成立。
循环进行时:如果在一个循环体开始执行之前,不变量成立,那么在下一个循环体执行之前,不变量仍然成立。
循环终结后:当整个循环结束时,不变量可以直接说明算法的正确性
在实际写算法的过程中,我们可以选择非形式化地通过分析循环不变式的真假来保证算法的正确性,也可以通过设置布尔值,并在每次循环前都利用某种判定规则得出布尔值并进行判断,来保证算法的正确性。
算法复杂度分析
一、时间复杂度
我们想要知道一个算法的「时间复杂度」,很多人首先想到的的方法就是把这个算法程序运行一遍,那么它所消耗的时间就自然而然知道了。
这种方式可以吗?当然可以,不过它也有很多弊端。
这种方式非常容易受运行环境的影响,在性能高的机器上跑出来的结果与在性能低的机器上跑的结果相差会很大。而且对测试时使用的数据规模也有很大关系。再者,并我们在写算法的时候,还没有办法完整的去运行呢。
因此,另一种更为通用的方法就出来了: 大O符号表示法 ,即 T(n) = O(f(n))
在 大O符号表示法中,时间复杂度的公式是: T(n) = O( f(n) ),其中f(n) 表示每行代码执行次数之和,而 O 表示正比例关系,这个公式的全称是:算法的渐进时间复杂度,数据越大,执行时间越长。
二、空间复杂度
既然时间复杂度不是用来计算程序具体耗时的,那么我也应该明白,空间复杂度也不是用来计算程序实际占用的空间的。
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样反映的是一个趋势,我们用 S(n) 来定义。
空间复杂度比较常用的有:O(1)、O(n)、O(n²)
/**
* 空间复杂度O(1)
*/
public static void spatial1(){
/**
* 1、O(1)算法执行所需要的临时空间不随着某个变量n的大小而变化
* 2、代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)
*/
int i = 1;
int j = 2;
++i;
j++;
int k = i + j;
System.out.println("打印值:" + k);
}
/**
* 空间复杂度O(n)
*/
public static void spatial2(int[] arr){
/**
* 虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)
*/
int[] spatialArr = new int[10];
for (int i = 0; i < 10;i++) {
spatialArr[i] = i;
}
for (int i = 0; i < arr.length;i++) {
++spatialArr[arr[i]];
}
int index = 0;
for (int i = 0 ;i < 10;i++) {
for (int j = 0;j < spatialArr[i];j++) {
arr[index] = i;
index++;
}
}
}
常见的时间复杂度量级有
名称 | 解释 |
常数阶O(1) | 无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1) |
线性阶O(n) | 循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化 |
对数阶O(logn) | 当循环 log2^n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(logn) |
平方阶O(n²) | 把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²) 了。 |
平方阶O(n³) | O(n³)相当于三层n循环 |