1. 泛型
首先实现一下整型的线性查找
public class LinearSearch {
private LinearSearch() {}
public static int search(int[] data, int target) {
for(int i = 0; i < data.length; i++)
if (data[i] == target)
return i;
return -1;
}
public static void main(String[] args) {
int[] data = {24, 15, 12, 423, 23, 17, 46};
int res = search(data, 423);
System.out.println(res);
int res1 = search(data, 13);
System.out.println(res1);
}
}
但是我们不能够保证所有的调用这个方法的人都是用int,所以我们需要用泛型,使用泛型的时候不可以是基本数据类型,只能是类对象
- 基本数据类型:boolean, byte, char, short, int, long, float, double
- 对应的包装类:Boolean, Byte, Character, Short, Integer, Long, Float, Double
因此我们可以修改一下我们的代码成这样
public class LinearSearch {
private LinearSearch() {}
public static <E> int search(E[] data, E target) { // E是泛型类
for(int i = 0; i < data.length; i++)
if (data[i].equals(target)) // 需要调用equal方法来判断是否相等
return i;
return -1;
}
public static void main(String[] args) {
Integer[] data = {24, 15, 12, 423, 23, 17, 46}; //用包装类
int res = search(data, 423);
System.out.println(res);
int res1 = search(data, 13);
System.out.println(res1);
}
}
如果我们要调用自己的类,来做线性查找的话,下面是一个例子,我们覆盖了.equal(Object val)
这个方法
public class Student {
private String name;
public Student(String name){
this.name = name;
}
@Override
public boolean equals(Object student) {
if (this == student)
return true;
if (student == null)
return false;
if(this.getClass() != student.getClass())
return false;
Student stu = (Student)student;
return this.name.toLowerCase().equals(stu.name.toLowerCase());
}
}
调用LinearSearch查找
Student[] students = {new Student("Alice"),
new Student("Jack"),
new Student("Rose")};
Student jack = new Student("jack");
int res2 = LinearSearch.search(students, jack);
System.out.println(res2);
2. 循环不变量
循环不变量主要用来帮助我们理解算法的正确性。关于循环不变量,我们必须证明三条性质:
- 初始化:循环的第一次迭代之前,为真
- 保持:如果循环的某次迭代之前为真,那么下一次迭代之前仍为真
- 终止:在循环终止时,不变量为我们提供一个有用的性质,该性质有助于证明算法的正确性
以线性查找为例
- 初始化:子数组
data[0, -1]
是空集,空集中没有要找的target
。这证明第一次循环迭代之前循环不等式成立 - 保持:每一次for都判断了
data[i]
是不是要找到的target
,不是的话就证明了在下一次循环的时候data[0, 0]
之间没有target
。以此类推,如果一直没有找到target
,data[0, i-1]
之间没有target
,维护了循环不变量 - 终止:找到了target,返回对应索引值。
data[0, i-1]
也没有target
。因此,算法成立。
循环体在整个过程中维护了循环不变量
3. 常用复杂度比较
- 空间复杂度和时间复杂度同理
O ( 1 ) < O ( l g n ) < O ( n ) < O ( n ) < O ( n l g n ) < O ( n 2 ) < O ( 2 n ) < O ( n ! ) O(1)<O(lgn)<O(\sqrt n)<O(n)<O(nlgn)<O(n^2)<O(2^n)<O(n!) O(1)<O(lgn)<O(n)<O(n)<O(nlgn)<O(n2)<O(2n)<O(n!)