算法入门
算法特征特征
- 有穷性
- 确定性
- 可行性
- 有输入
- 有输出
算法设计原则
- 正确性
- 可读性
- 健壮性
- 高效率
- 低存储
示例
算法指标
- 时间复杂度(cpu占用)
- 空间复杂度(内存占用)
时间复杂度
一般用O来表示,例如O(1)代表一行常数计算的代码表示的时间复杂度,其中时间复杂度的计算具有4种性质,分别为常数性、线性性、对数性和平方性。
常数性O(1)
所有的常数计算的一行代码都可以看作是O(1)的时间复杂度,所以一般这种形式的代码不会计算在时间复杂度上
线性性O(m)
对数性nlog(n)
快速排序
平方性O(n^m)
总结
时间复杂度优化标准就是:尽量往低的优化,一般在程序中找for while 递归等就能大概算出时间复杂度。
以上几个性能对比:O(1)>O(n)>O(nlogn)>O(n^2)
空间复杂度
运行程序所需要的内存 OOM,一般就是找数组,容器等,基本数据类型可以不用去计算
void OOM() {
//空间复杂度 表示的是占用内存
int a[] = new int[n]; //O(n) 字典树
//Map<String, String>
//List<Integer> list = new ArrayList<>(); //
//缓存
}
基本数据结构
在这里只介绍两种,数组和链表
数组
元素可以快速的随机访问。
缺点是每个元素必须是连续的,当需要扩容时,就要将已经有数组的数据复制到新的存储空间中。
数组的经典应用
链表
链表结构如下所示,其链式结构注定了访问不能随机,就像火车一样你不能从火车头一下跳到火车尾而是要一节节车厢的去走。但是插入删除快
在中间插入一个数据最多只需要改变一个next的指向和插入数据的next的指向
其他数据结构
java基本数据结构
在java中比较常见的数据结构如下
- List
- Set
- Map
- Queue
List
- ArrayList是数组结构
- LinkedList是链表结构,不能随机访问
- Vector是数组结构,同步容器
Vector、ArrayList和LinkedList三者对比:
性能上来说ArrayList最好,也使用最多,但当集合内的元素需要频繁插入、删除就可以考虑用LinkedList。Vector是线程同步的。所以性能最差,但是安全性最高一般用于高并发系统。
- 如果能用数组的时候(元素类型固定,数组长度固定),请尽量使用数组来代替List;
- 如果没有频繁的删除插入操作,又不用考虑多线程问题,优先选择ArrayList;
- 如果在多线程条件下使用,考虑Vector;
- 如果需要频繁地删除插入,LinkedList;
- 如果不清楚的情况下,就用ArrayList。
Set
- HashSet就是用来去重的 而且去重后元素的顺序和插入的不一样的
- TreeSet是用来排序的,其底层数据结构为红黑树 元素的顺序和插入的不一样的
- LinkedHashSet维护了一个链表,记录了顺序,可以保持插入和输出后的顺序一致
Queue
-
ArrayBlockingQueue:基于数组的阻塞队列实现,也长度是需要定义的,可以指定先进先出或者先进后出,是有界队列,在多线程池中的等待队列就就用了这种。
-
LinkedBlockingQueue:基于链表的阻塞队列,(该队列由一个链表构成),其内部实现采用分离锁(读写分离两个锁),从而实现生产者和消费者操作的完全并行运行,是无界队列。
-
PriorityBlockingQueue:基于优先级的阻塞队列(排队场景比较适合,具体实现看代码例子)
-
DelayQueue:带有延迟时间的Queue,其中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。应用场景主要有:缓存超时的数据进行移除、空闲连接的关闭等等。