一、数据结构
数据结构是,其目的是为了。
按元素之间的关系又分为。
①、线性结构
线性结构是最简单的数据结构,包括,以及由它们衍生出来的。
②、树形结构
树是相对复杂的数据结构,其中比较有代表性的是,由它又衍生出了二叉堆之类的数据结构。
③、图状结构
图是更为复杂的数据结构,因为在图中会呈现出多对多的关联关系。
④、其他数据结构
它们由基本数据结构变形而来,用于解决某些特定问题,如调表、哈希链表、位图等。
Java常用数据结构
二、算法
在计算机领域里,算法是一系列程序指令,用于处理特定的运算和逻辑问题。
衡量算法优劣的主要标准是。
时间复杂度
如果用函数来表示完成一个操作所需要的时间,假设场景如下:
场景1:如果操作次数是常量的记为T(n) = 2,例如:
void eat1(int n){
System.out.println("hello world");
System.out.println("你好");
}
场景2:如果操作次数是线性的记为T(n) = 3n,例如
void eat2(int n){
for (int i=0;i<n;i++){
System.out.println("hello world");
System.out.println("你好");
System.out.println("算法真难");
}
}
场景3:如果操作次数是对数的记为T(n) = 2logn,例如
void eat3(int n){
for (int i=n;i>1;i/=2){
System.out.println("hello world");
System.out.println("你好");
}
}
场景4:如果操作次数是多项式的记为T(n) = 0.5n² + n,例如
void eat4(int n){
for (int i=0;i<n;i++){
for (int j=0;j<i;j++){
System.out.println("hahah");
}
System.out.println("hello world");
}
}
若存在函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同等量级函数。记作T(n)= O(f(n)),称为O(f(n)),O为算法的渐进时间复杂度,简称为时间复杂度。也称为大O表示法
时间复杂度的原则如下:
- 如果运行时间是常数级,则用常数1表示
- 只保留时间函数中的最高阶项
- 如果最高阶项存在,则省去最高阶项前面的系数
所以把上面场景转化为时间复杂度为:
场景1:T(n)= O(1)
场景2:T(n)= O(n)
场景3:T(n)= O(logn)
场景4:T(n)= O(n²)
当n的取值足够大时,谁的时间复杂度更大?
O(1)< O(logn)< O(n)< O(n²)
除了上面4种场景,还有其它时间复杂度,比如:O(nlogn)、O(n³)、O(mn)、O(2ⁿ)、O(n!)
空间复杂度
和时间复杂度类似,空间复杂度是对一个算法在运行过程中临时占用存储空间大小的度量,它同样使用了大O表示法。
程序占用空间大小的计算公式记作S(n)= O(f(n)),其中n为问题的规模,f(n)为算法所占存储空间的函数。
1、常量空间
当算法的存储空间大小固定,和输入规模没有直接的关系时,空间复杂度记作O(1)。例如:
void fun1(int n){
int var = 3;
...
}
2、线性空间
当算法分配的空间是一个线性的集合(如数组),并且集合大小和输入规模成正比时,空间复杂度记作O(n)。例如:
void fun2(int n){
int[] array = new int[n];
...
}
3、二维空间
当算法分配的空间是一个二维数组集合,并且数组的长度和宽度都与输入规模n成正比时,空间复杂度记作O(n²)。例如:
void fun3(int n){
int[][] array = new int[n][n];
...
}
4、递归空间
递归是一个比较特殊的场景。虽然递归代码中并没有显示地声明变量或集合,但是计算机在执行程序时,会专门分配一块内存,用来存储“方法调用栈”。执行递归操作所需要的内存空间和递归的深度成正比,如果递归的深度是n,那么空间复杂度就是O(n)。例如:
void fun4(int n){
if(n<=1){
return;
}
fun4(n-1);
...
}