线性查找:面对线性数据结构进行的查找算法(链表,数组)
同时,为了实现泛型,需要对类的 equals 方法进行重写
一、原理:
1.对于数组:
就是利用下标对数组进行遍历,然后直到获得目标值。
输入:数组, 目标元素
输出:目标元素所在索引;若不存在,返回 -1
2.对于链表:
利用 Node 节点的 next 指向,对 node 进行遍历,进行查找。
输入:目标元素
输出:boolean ( 是否存在该值 ),或者使用 index 记录所在顺序。
若不存在,返回 -1;
- 数组在内存中存储位置连续分布,而链表不行,所以链表无法使用 foreach 循环进行遍历
二、简单实现:
第一版
public class LinerFind {
public 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 = {1,23,4,56,66,780,546};
LinerFind lf = new LinerFind();
int res = lf.search(data, 1);
System.out.println(res);
}
}
// LinerFind 是一个动态词汇, 最好把 search 方法写成静态方法, 这样调用 就不需要创建对象
思考一下 Math 和 Integer.parseInt() 也没有创建对象后再进行使用,因为并不需要创建对象,只是想操作这个对象。
将 search 方法定义为 static 方法, 并将构造函数定义为 private ,这样用户就不会使用构造了。
第二版(应对不同的数据类型,避免重复)
复习一下泛型,泛型需要使用的为类对象,而不是基本数据类型,所以产生类对应的包装类。
- 泛型类型 不能适用于静态方法,使用其他类型区分,将静态方法的泛型类型和实例类型的泛型类型区分开。
// 使用泛型(java中的 map, list 等都是使用泛型类)
private LinearSearch2(){}
public static <T> int search(T[] data, T target){
for(int i = 0;i<data.length;i++){
if(data[i].equals(target)){ // 此时为两个类对象,使用 equals 不用 ==
return i;
}
}
return -1;
}
public static void main(String[] args) {
Integer[] data = {1,23,4,56,66,780,546};
int res = LinearSearch2.search(data, 1);
System.out.println(res);
}
作业:自己写一个类。重写 equals(),避免产生错误:
public class Student {
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge(){
return this.age;
}
public String getName(){
return this.name;
}
// 判断对象是否为空或者为统一类型
// 然后再比较值判断相等
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof Student)) {
return false;
}
Student o = (Student) obj;
return (this.age == o.getAge() && this.name.equals((o.getName()));
}
}
三、循环不变量:
四、复杂度分析:表示算法性能
通常看最差的情况:
n = data.length T = n O(n) 性能与数据规模 n 之间的关系
T1 = 1000n O(n) T2=2n^2 O(n^2)
1.常见复杂度(时间)):
while(n){
n%2;
n/=2;
}
O(logn)
长度为 n 的二进制数字 O(2^n)
长度为n的数组的所有排列 O(n!)