目录
1.初识数据结构
2.衡量算法的好坏
3.包装类和泛型
一,什么是数据结构
1.数据结构,就是电脑存放数据的「收纳整理方法」
2.数据结构 = 数据怎么摆 + 数据怎么拿
二,算法效率
1.算法效率分析分为两种:第⼀种是时间效率,第⼆种是空间效率。时间效率被称为时间复杂度,⽽空间效率被称作空间复杂度。
时间复杂度
时间复杂度:算法的时间复杂度是⼀个数学函数,算法中的基本操作的执⾏次数,为算法的时间复杂度。因为我们只需要一个大概的数字,所以引出了⼤O的渐进表⽰法,用O(N)来表示,O里面数字一般是N,并且我们通常比的是最坏的情况
大O的渐进表示法:
1、⽤常数1取代运⾏时间中的所有加法常数。
2、在修改后的运⾏次数函数中,只保留最⾼阶项。
3、如果最⾼阶项存在且不是1,则去除与这个项⽬相乘的常数。得到的结果就是⼤O阶。
接下来我举几个例子
例一:
// 计算func2的时间复杂度?
void func2(int N) {
int count = 0;
for (int k = 0; k < 2 * N ; k++) {
count++;
}
int M = 10;
while ((M--) > 0) {
count++;
}
System.out.println(count);
}
答:总执行次数为2N+10,根据计算的法则,只保留最高阶2N,系数2变为1,得到的结果为O(N)
例二:
// 计算func3的时间复杂度? void func3(int N, int M) {
int count = 0;
for (int k = 0; k < M; k++) {
count++;
}
for (int k = 0; k < N ; k++) {
count++;
}
System.out.println(count);
答:O(M+N)
我们现在来看常见的空间复杂度计算(冒泡排序,二分查找,递归,斐波那契)
一:冒泡排序
// 计算bubbleSort的时间复杂度?
void bubbleSort(int[] array) {
for (int end = array.length; end > 0; end--) {
boolean sorted = true;
for (int i = 1; i < end; i++) {
if (array[i - 1] > array[i]) {
Swap(array, i - 1, i);
sorted = false;
}
}
if (sorted == true) {
break;
}
}
}
答:假设数组长度是N,以最坏情况来考虑,数组完全是倒序的,第一次要换N-1次,到最后一次换1次,就是(N-1)+(N-2)+(N-3)........+1=(N-1+1)*(N-1)/2=(N^2-N)/2,根据法则就是O(N^2)
二:二分查找
int binarySearch(int[] array, int value) {
int begin = 0;
int end = array.length - 1;
while (begin <= end) {
int mid = begin + ((end-begin) / 2);
if (array[mid] < value)
begin = mid + 1;
else if (array[mid] > value)
end = mid - 1;
else
return mid;
}
return -1;
}
答:每一次查找的时候都缩小一半的空间,从1/2到1/4,最后的最后找到那一个,所以(1/2)^N=1,N=log2N,所以就是O(log2N),时间复杂度中,对数的底数可以忽略,所以可以简写为 O(logN)
三:普通递归
*公式:递归的时间复杂度=递归的次数*每次递归里面的次数
long factorial(int N) {
return N < 2 ? N : factorial(N-1) * N;
}
答:我们可以通过画图来解决问题

我们假设N=3来理解就行,所以递归的次数就是N-1,每次递归里面的执行次数是1,所以为O(N)
四:斐波那契暴力递归
int fibonacci(int N) {
return N < 2 ? N : fibonacci(N-1)+fibonacci(N-2);
}
答:
所以每次个数都是2^(N-1)个递归,所以通过等比公式加起来就是2^N-1,就是O(2^N)
空间的复杂度
空间复杂度是对⼀个算法在运⾏过程中临时占⽤存储空间⼤⼩的量度。空间复杂度不是程序占⽤了多 少bytes的空间,因为这个也没太⼤意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基 本跟时间复杂度类似,也使⽤⼤O渐进表⽰法。
*空间复杂度计算的核心是:统计算法在运行过程中,除了输入数据(参数数组)之外,额外申请的内存空间大小。
例一:冒泡排序
void bubbleSort(int[] array) {
for (int end = array.length; end > 0; end--) {
boolean sorted = true;
for (int i = 1; i < end; i++) {
if (array[i - 1] > array[i]) {
Swap(array, i - 1, i);
sorted = false;
}
}
if (sorted == true) {
break;
}
}
}
答:全程没有额外创建空间,变量就固定end,sorted和i,所以为O(1)
例二:斐波那契数列
int[] fibonacci(int n) {
long[] fibArray = new long[n + 1];
fibArray[0] = 0;
fibArray[1] = 1;
for (int i = 2; i <= n ; i++) {
fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
}
return fibArray;
}
答:主要的大头是long[] fibArray = new long[n + 1];因为for循环里没有创建新的,所以额外数量是N-1所以为O(N)
例三:
long factorial(int N) {
return N < 2 ? N : factorial(N-1)*N;
}
答:实例3递归调⽤了N次,开辟了N个栈帧,每个栈帧使⽤了常数个空间。空间复杂度为O(N)
三:包装类和泛型
(1)包装类
在Java中,由于基本类型不是继承⾃Object,为了在泛型代码中可以⽀持基本类型,Java给每个基本 类型都对应了⼀个包装类型,也就相当于包装类型范围更广一点

1. 装箱 (Boxing)
定义:将基本数据类型转换为对应的包装类对象。并且分为自动装箱和手动

第一种就是手动调用方法来进行装箱,称为手动装箱,第二种则是系统识别帮你调用了这个方法来实现装箱,称为自动装箱
2. 拆箱 (Unboxing)
定义:将包装类对象转换为对应的基本数据类型。并且也分为自动装箱和手动

1就是自动,2就是手动
泛型
理解:通俗讲,泛型:就是适⽤于许多许多类型。从代码上讲,就是对类 型实现了参数化。用于可以运用多种类型的数据
引出:在数组中,只能输入特定类型的数据,然后所有类都是Object的子类,那数组也可以写成Object类型的,并且通过一种写法就可以决定数组存放数据的类型,就得用到一个特别的符号<>,示例如下
public class Array <T> {
public Object[] array = new Object[10];
public T getPos(int pos) {
return (T) this.array[pos];
}
public void setVal(int pos, T val) {
this.array[pos] = val;
}
}
public class Test{
public static void main(String[] args) {
Array <Integer>array=new Array<>();
array.setVal(0,100);
array.setVal(1,200);
System.out.println(array.getPos(0));
}
图一将数组写成Object类型,通过set来放数据,get来拿数据,<>是代表要替换类型,T是常用的一个字母,可以自己换,图二测试类里面Array里面放了要放的类型,然后通过set和get方法来实现
734



被折叠的 条评论
为什么被折叠?



