数据结构与算法
1、算法
1)算法是用于解决特定问题的一系列的执行步骤
2)使用不同算法,解决同一个问题,效率可能相差非常大
3)一般从以下维度来评估算法的优劣
- 正确性、可读性、健壮性(对不合理输入的反应能力和处理能力)
- 时间复杂度(time complexity):估算程序指令的执行次数(执行时间)
- 空间复杂度(space complexity):估算所需占用的存储空间
1.1 时间复杂度
- 大O表示法:描述复杂度,表示的是数据规模n对应的复杂度;仅仅是一种粗略的分析模型,是一种估算,能简单了解一个算法的执行效率
- 忽略常数、系数、低阶、对数阶一般省略底数
- 常数 >> O(1);
- 2n + 3 >> O(n);
- n^2 + 2n + 6 >> O(n^2);
- 4n^3 + 3n^2 + 22n + 100 >> O(n^3)
- log2(n)、log9(n)>> O(logn)
- 常见的时间复杂度
- 时间工具类----TimeTool
import java.text.SimpleDateFormat;
import java.util.Date;
public class TimeTool {
private static final SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS");
public interface Task {
void execute();
}
public static void check(String title, Task task) {
if (task == null)
return;
title = (title == null) ? "" : ("【" + title + "】");
System.out.println(title);
System.out.println("开始:" + fmt.format(new Date()));
long begin = System.currentTimeMillis();
task.execute();
long end = System.currentTimeMillis();
System.out.println("结束:" + fmt.format(new Date()));
double delta = (end - begin) / 1000.0;
System.out.println("耗时:" + delta + "秒");
System.out.println("--------------------------------");
}
}
- 求第n个斐波纳契数(fibonacci number)
public class Test {
/**
* 斐波纳契数列:
* 0 1 1 2 3 5 8 13 ...
* 索引:
* 0 1 2 3 4 5 6 7 ...
*/
// 方法一:递归法
// 时间复杂度 O(2^n)
public static int fib1(int n) {
if (n <= 1)
return n;
return fib1(n - 1) + fib1(n - 2);
}
// 方法二
// 时间复杂度 O(n)
public static int fib2(int n) {
if (n <= 1)
return n;
int first = 0;
int second = 1;
for (int i = 0; i < n - 1; i++) {
int sum = first + second;
first = second;
second = sum;
}
return second;
}
// 方法三
// 时间复杂度 O(n)
public static int fib3(int n) {
if (n <= 1)
return n;
int first = 0;
int second = 1;
while (n-- > 1) {
second += first;
first = second - first;
}
return second;
}
public static void main(String[] args) {
// 递归法:存在性能问题,随着n的增大,效率会受影响
TimeTool.check("fib1", new Task() {
@Override
public void execute() {
System.out.println(fib1(30));
}
});
// 方法二的效率明显比递归法高
TimeTool.check("fib2", new Task() {
@Override
public void execute() {
System.out.println(fib2(30));
}
});
// 方法三的在变量的使用数量要比方法二少
TimeTool.check("fib3", new Task() {
@Override
public void execute() {
System.out.println(fib3(30));
}
});
}
}
- 斐波纳契数使用递归法的时间复杂度
1)以 fib(5) 为例分析
- 发现函数有重复调用
2)时间复杂度:O(n^2)
1.2 算法的优化方向
- 用尽量少的存储空间
- 用尽量少的执行步骤(执行时间)
- 根据情况,可以
1)空间换时间
2)时间换空间
1.3 多个数据规模的情况
2. 数据结构
- 数据结构是计算机存储、组织数据的方式
2.1 线性表
2.1.1 数组----Array
2.1.2 动态数组----Dynamin Array
2.1.2.1 接口设计
2.1.2.2 动态数组的设计
2.1.2.2.1 添加元素 ---- add(E element)
2.1.2.2.2 添加元素 ---- add(int index, E element)
2.1.2.2.3 删除元素 ---- remove(int index)
2.1.2.2.4 如何扩容
- 数组扩容,如果用new的方式创建出的数组,地址不可能连续,因此常用做法是申请更大的数组
2.1.2.2.5 对象数组
- clear()
- 1)如果基本类型数据,clear()清除元素,只需size=0即可,主要是控制访问和操作数据
- 2)如果是引用类型,clear()清除元素,①、size=0,对空间中的对象依然存在,这样做会造成内存的浪费,②、elements[i] = null,数组中对象就会被回收。