一 时间和空间复杂度
1.时间复杂度:算法中的基本操作的执行次数,为算法的时间复杂度
1)一个算法的运行时间和这个算法中的语句执行次数有关系,成正比
2)大O的渐进表示法:计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么我们使用大O的渐进表示法,大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数
a、用常数1取代运行时间中的所有加法常数。
b、在修改后的运行次数函数中,只保留最高阶项。
c、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶
3)法的时间复杂度存在最好、平均和最坏情况,一般我们默认的是最坏情况
4)递归的时间复杂度 = 递归的次数 * 每次递归后的执行次数
2.空间复杂度:是对一个算法在运行过程中临时占用存储空间大小的量度,算的是变量的个数
ps:要结合代码的实现去计算
O(1)<O(logN)<<O(N)O(N*logN)<O(N^2)
二 包装类
1,除了 Integer 和 Character, 其余基本类型的包装类都是首字母大写。
2.装箱:把一个基本类型转变为包装类型
拆箱:把一个包装类型转变为基本类型
int i = 10;
Integer ii = i; // 自动装箱
Integer ij = (Integer)i; // 自动装箱
Integer ii = Integer.valueOf(i); //手动装箱
int j = ii; // 自动拆箱
int k = (int)ii; // 自动拆箱
Integer ii2 =new Integer(10);
int b = ii2.intvalue(); //手动拆箱
double d = ii2.doubleValue;
3.缓存数组:可存256个数, -127~128
三 泛型
意义:编译时检查数据类型是否正确,帮助进行数据转换
class 泛型类名称<类型形参列表> {
// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
}
1.不能实例化一个泛型类型的数组
T[] ts = new T[5]; //出错
2.<>中不能是基本数据类型,只能是引用类型
3.类名后的 <T> 代表占位符,表示当前类是一个泛型类,常用类型形参如下:
E 表示 Element
K 表示 Key
V 表示 Value
N 表示 Number
T 表示 Type
S, U, V 等等 - 第二、第三、第四个类型
4.泛型是编译时期的一种机制,意味着运行时没有泛型这个概念,即JVM中没有泛型的概念
5.擦除机制:在编译的过程当中,将所有的T替换为Object的机制
6.使用
MyArray<Integer> list = new MyArray<Integer>();
MyArray<Integer> list = new MyArray<>(); // 可以推导出实例化需要的类型实参为 Integer
7.数组是一种单独的数据类型,数组之间不具备继承关系
8.泛型的上届:定义泛型类时有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束
class 泛型类名称<类型形参 extends 类型边界> {
...
}
public class MyArray<E extends Number> {
...
}
MyArray<Integer> l1; // 正确,因为 Integer 是 Number 的子类型
MyArray<String> l2; // 编译错误, String 不是 Number 的子类型
public class MyArray<E extends Comparable<E>> {
...
} //E实现Comparable接口
9.泛型方法
方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { ... }
public class Util {
//静态的泛型方法 需要在static后用<>声明泛型类型参数
public static <E> void swap(E[] array, int i, int j) {
E t = array[i];
array[i] = array[j];
array[j] = t;
}
Integer[] a = { ... };
swap(a, 0, 9);
String[] b = { ... };
swap(b, 0, 9); //通过参数的类型推导出E的类型
Integer[] a = { ... };
Util.<Integer>swap(a, 0, 9);
String[] b = { ... };
Util.<String>swap(b, 0, 9); //调用方法时在前面声明类型