什么是算法
定义:一系列解决问题的,清晰,可执行的计算机指令。
- 有限性
- 确定性:无二义性
- 可行性
- 输入
- 输出
线性查找法
基础创建
输入: 数组,目标元素
输出: 目标元素所在的索引( 若不存在,返回 -1 )
// linear search
public class LinearSearch {
//输入: 数组,目标元素
public int Search(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 = {4, 35, 45, 42, 63, 23, 6, 77};
// 存在的情况
// 创建linearSearch类的对象
LinearSearch ls = new LinearSearch();
int res1 = ls.Search(data, 6);
System.out.println(res1);
// 不存在的情况
int res2 = ls.Search(data, 7);
System.out.println(res2);
}
}
修改1:私有化
- LinearSearch是一个动词,对于动作而言,创建一个对象很奇怪,所以修改为类似Math方法的直接调用
- 不希望用户创建对象,将LinearSearch创建为私有的
文件1 :LinearSearch.java
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;
}
}
文件2:Main.java
public class Main {
public static void main(String[] args){
int[] data = {4, 35, 45, 42, 63, 23, 6, 77};
// LinearSearch ls = new LinearSearch();
int res1 = LinearSearch.Search(data, 6);
System.out.println(res1);
int res2 = LinearSearch.Search(data, 7);
System.out.println(res2);
}
}
修改2:泛型
不是只有int类型的变量,若是学生姓名的查找,换了类型之后,就会重复代码,因此需要修改 – 泛型
(目的:向Java的标准库看齐)
泛型复习
- 泛型只能接受类对象,不能接受基本数据类型
- 基本数据类型:
boolean, byte, char, short, int, long, float, double- 每个基本数据类型有对应的包装类: Boolean, Byte, Character, Short, Integer, Long, Float, Double
文件1 :LinearSearch.java
public class LinearSearch {
private LinearSearch(){}
public static <E> int Search(E[] data, E target){
for(int i = 0; i < data.length; i ++) {
// 类对象之间的判断,要使用equals方法
if (data[i].equals(target)) {
return i;
}
}
return -1;
}
}
文件2:Main.java
public class Main {
public static void main(String[] args){
Integer[] data = {4, 35, 45, 42, 63, 23, 6, 77};
int res1 = LinearSearch.Search(data, 6);
System.out.println(res1);
int res2 = LinearSearch.Search(data, 7);
System.out.println(res2);
}
}
提升:自定义Student类测试算法
文件1 :LinearSearch.java
public class LinearSearch {
private LinearSearch(){}
public static <E> int Search(E[] data, E target){
for(int i = 0; i < data.length; i ++) {
if (data[i].equals(target)) {
return i;
}
}
return -1;
}
}
文件2:Main.java
public class Main {
public static void main(String[] args){
Integer[] data = {4, 35, 45, 42, 63, 23, 6, 77};
int res1 = LinearSearch.Search(data, 6);
System.out.println(res1);
int res2 = LinearSearch.Search(data, 7);
System.out.println(res2);
Student[] students = {new Student("ccq"),
new Student("cq"),
new Student("cc")};
Student ccq = new Student("Ccq");
int res3 = LinearSearch.Search(students, ccq);
System.out.println(res3);
}
}
文件3:Student.java
public class Student {
private String name;
public Student(String name){
this.name = name;
}
// 设计者自己去定义什么叫两个人相等的含义
// 将两个学生类的比较,变为学生姓名字符串的比较
public boolean equals(Object student){
// 地址是否是一样(即地址是否一样)
if(this == student)
return true;
if(student == null)
return false;
// 判断类对象是否相等
if(this.getClass() != student.getClass())
return false;
// 强制将Object 转化为 Student
Student another = (Student)student;
return this.name.toLowerCase().equals(another.name.toLowerCase());
}
}
复杂度分析:表示算法的性能
- 复杂度分析通常看最差的情况
- 数据规模:n = data.length
- 算法性能:T = ?
若 T = c1 * n + c2 → O(n)
常数不重要
复杂度描述的是随着数据规模N的增大,算法性能的变化趋势
常见算法的复杂度
[一定要明确n到底是谁]
O ( n ) = ( n 2 ) O(n) = (n^2) O(n)=(n2)
1.
for(int i=0;i<data.length;i++)
for(int j=1;j<data.length;j++)
//获得数据对(data[i],data[j])
2. 遍历一个n*n的二位数组
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
//遍历到A[i][j]
O ( n ) = ( l o g n ) O(n) = (logn) O(n)=(logn)
//数字n的二进制位数
while(n){
n % 2 // n;
n /= 2;
}
O ( n ) = ( n ) O(n) = (\sqrt{n}) O(n)=(n)
//数字n的所有约数
for(int i=1;i*i<=n;i++){
if(n%i==0)
//i和n/i是n的两个约数
}
O ( n ) = ( 2 n ) O(n) = (2^n) O(n)=(2n)
长度为n的二进制数字
O ( n ) = ( n ! ) O(n) = (n!) O(n)=(n!)
长度为n的数组的所有排列
O ( 1 ) O(1) O(1) < O ( l o g n ) O(logn) O(logn) < O ( n ) O(\sqrt{n}) O(n) < O ( n ) O(n) O(n) < O ( n l o g n ) O(nlogn) O(nlogn) < O ( n 2 ) O(n^2) O(n2) < O ( 2 n ) O(2^n) O(2n) < O ( n ! ) O(n!) O(n!)
测试算法性能
文件1 :LinearSearch.java
public class LinearSearch {
private LinearSearch(){}
public static <E> int Search(E[] data, E target){
for(int i = 0; i < data.length; i ++) {
if (data[i].equals(target)) {
return i;
}
}
return -1;
}
}
文件2:Main.java
public class Main {
public static void main(String[] args){
// int n = 10000000;
// Integer[] data = ArrayGenerator.generateOrderedArray(n);
//
// long startTime = System.nanoTime(); //返回当前以纳秒对应的时间戳
// for(int k = 0 ; k < 100 ; k ++)
// LinearSearch.Search(data, n);
// long endTime = System.nanoTime();
//
// double time = (endTime - startTime) / 1000000000.0;
// //线性查找法对于100000这个数据总共花费多少秒
// System.out.println(time + " s");
int [] dataSize = {1000000, 10000000};
for(int n: dataSize) {
Integer[] data = ArrayGenerator.generateOrderedArray(n);
long startTime = System.nanoTime(); //返回当前以纳秒对应的时间戳
for (int k = 0; k < 100; k++)
LinearSearch.Search(data, n);
long endTime = System.nanoTime();
double time = (endTime - startTime) / 1000000000.0;
//线性查找法对于100000这个数据总共花费多少秒
System.out.println("n = " + n + ", 100 runs : " + time + " s");
}
}
}
文件3:ArrayGenerator.java
public class ArrayGenerator {
private ArrayGenerator(){}
public static Integer[] generateOrderedArray(int n){
Integer[] arr = new Integer[n];
for(int i = 0 ; i < n ; i ++){
arr[i] = i;
}
return arr;
}
}