一、数学基础
二、算法分析
三、常见数据结构
四、常见排序算法
五、常见查找算法
六、栈相关算法
七、链表相关算法
八、双指针相关
九、二叉树相关
十、深度优先和广度优先算法
十一、贪心算法
十二、回溯算法
十三、动态规划
- 1. 归纳法
- 2. 反证法
- 1. 洛必达法则
- 1. 数组是具有相同类型的数据的集合,也就是说数组的所有元素的类型都是相同的,在所有的数据结构中, 数组算是最常见也是最简单的一种数据结构,我们最常见的也就是一维数组,当然还有二维,三维......, 数组需要先声明才能使用,数组的大小一旦确定就不可以在变了
- 2. 数组的查找是比较方便的,但对数组的增删就没那么方便了,因为数组是一块连续的内存空间, 如果在前面增加和删除,都会导致后面元素位置的变动。
- 3. ArrayList底层实现
- 4. CopyOnWriteArrayList底层实现
- 链表是一种物理存储单元上非连续的一种数据结构,看名字我们就知道他是一种链式的结构,就像一群人 手牵着手一样。链表有单向的,双向的,还有环形的。
- 1. 单向链表的定义
- 这个类非常简单,他只有两个变量,一个是data值,一个是指向下一个结点的指针。
- 2. 单向链表的增删
- 链表不像数组那样,可以通过索引来获取,单向链表查找的时候必须从头开始往后一个个找,而不能从中 间找,也不能从后往前找。
- 1. 添加到尾结点
- 2. 删除尾结点
- 3. 使用场景
- 1. LinkedHashMap底层实现
- 2. 使用场景
- 队列是一种特殊的线性表,他的特殊性在于我们只能操作他头部和尾部的元素,中间的元素我们操作不了,我们只能在他的头部进行删除,尾部进行添加。就像大家排队到银行取钱一样,先来的肯 定要排到前面,后来的只能排在队尾,所有元素都要遵守这个操作,没有VIP会员,所以走后门插 队的现象是不可能存在的,他是一种先进先出的数据结构。我们来看一下队列的数据结构是什么样 的
- 他只能从左边进,右边出,队列实现方式一般有两种,一种是基于数组的,还一种是基于链表的, 如果基于链表的倒还好说,因为链表的长度是随时都可以变的,这个实现起来比较简单。如果是基 于数组的,就会稍微有点不同,因为数组的大小在初始化的时候就已经固定了
- 双端队列也是有两个指针,front指向队首,tail指向队尾的下一个存储单元,并且双端队列的队首 和队尾都可以添加和删除元素
- 栈也是一种特殊的线性表,他只能对栈顶进行添加和删除元素。栈有入栈和出栈两种操作,他就好 像我们把书一本本的摞起来,最先放的书肯定是摞在下边,最后放的书肯定是摞在了最上面,摞的 时候不允许从中间放进去,拿书的时候也是先从最上面开始拿,不允许从下边或中间抽出来。
- 散列表也叫哈希表,是根据键值对(key,value)进行访问的一种数据结构。他是把一对(key, value)通过key的哈希值来映射到数组中的,也就是说,它通过把关键码值映射到表中一个位置 来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
- 1. 数组的长度必须是2的n次幂
- 2. entry 的个数不能大于数组长度的75%,如果大于就会触发扩容机制进行扩容
- 3. 在java中1.7及以前的版本如果以链表的形式存在,在插入的时候采用的是头插法。
在1.8是尾插法。并且在java1.8中如果链表的长度大于8的时候会转为红黑树。
- 4. 在HashMap中,数组的大小是2^n,无论你初始化的时候传的值是多少,他都会初始化为2^n,并 且这个2^n是大于等于你初始化值的最小值,比如初始化的时候传的值是17,他会计算得到32。
- 1. 实现原理
- ArrayMap的实现原理是使用两个数组,一个存放hash值,一个存放key和value,其中存放key和 value的数组长度是存放hash值数组长度的二倍,其中存放hash值的数组必须是排序的。如果 hash值出现了冲突,说明hash值最终的计算是一样的,那么在hash数组中肯定是挨着的,所以查 找的时候如果hash值有重复的就会把重复的也查找一遍。
- 2. 代码实现
- 在散列表中如果可以确定key值都是int类型,那么又可以简化,直接用key值当hash值存储即可, 和ArrayMap一样只需要两个数组即可,一个是存放key的,一个是存放value的,不同的是这两个 数组的长度都是一样的。这种情况下就不会出现hash值一样的问题了,因为这个时候如果hash值 一样的话,那么他们的key肯定是一样的,而在散列表中是不可能存在了,假如在插入数据的时候 有一样的key,那么他的value是要被替换掉的,所以不会出现两个完全一样的key。
- 在java语言中还有一个关于散列表的,那就是ThreadLocalMap,这个类是ThreadLocal的一个静 态内部类,一般我们用不到。如果出现hash冲突的时候他的实现原理和上面的几种也都不太一 样。存储的时候他首先会根据hash值映射到指定的数组,如果当前位置为空就直接存进去,如果 不为空就往后找,找他的下一个
- 树是一个有n个有限节点组成一个具有层次关系的集合,每个节点有0个或者多个子节 点,没有父节点的节点称为根节点,也就是说除了根节点以外每个节点都有父节点,并 且有且只有一个。
- 1. 二叉树
- 2. 红黑树
- 3. AVL树
- 4. B树
- 5. 哈夫曼树
- 带权路径最短的二叉树称为哈夫曼树或最优二叉树;
- 6. 字典树
- 1. 结点的度:一个结点含有的子结点的个数称为该结点的度;
- 2. 叶结点或终端结点:度为0的结点称为叶结点;
- 3. 非终端结点或分支结点:度不为0的结点;
- 4. 双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点;
- 5. 孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点;
- 6. 兄弟结点:具有相同父结点的结点互称为兄弟结点;
- 7. 树的度:一棵树中,最大的结点的度称为树的度;
- 8. 结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;
- 9. 树的高度或深度:树中结点的最大层次;
- 10. 堂兄弟结点:双亲在同一层的结点互为堂兄弟;
- 11. 结点的祖先:从根到该结点所经分支上的所有结点;
- 12. 子孙:以某结点为根的子树中任一结点都称为该结点的子孙。
- 13. 森林:由m(m>=0)棵互不相交的树的集合称为森林;
- 14. 无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树;
- 15. 有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;
- 16. 二叉树:每个节点最多含有两个子树的树称为二叉树;
- 17. 完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1)的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这 就是完全二叉树
- 18. 满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个 子结点的二叉树。
- 19. 哈夫曼树:带权路径最短的二叉树称为哈夫曼树或最优二叉树;
- 1. 他的访问顺序是:根节点→左子树→右子树
- 2. 代码实现
- 1. 他的访问顺序是:左子树→根节点→右子树
- 2. 代码实现
- 1. 他的访问顺序是:左子树→右子树→根节点
- 2. 代码实现
- 1. 他的访问顺序是:先访问上一层,在访问下一层,一层一层的往下访问
- 2. 代码实现
- 1. 他的访问顺序是:先访根节点,然后左结点,一直往下,直到最左结点没有子节点 的时候然后往上退一步到父节点,然后父节点的右子节点在重复上面步骤......
- 2. 代码实现
- 通常情况下我们把堆看成是一棵完全二叉树。堆一般分为两种,一种是最大堆,一 种是最小堆。最大堆要求根节点的值即大于左子树的值,又大于右子树的值。也就 是说最大堆根节点的值是堆中最大的。最小堆根节点的值是堆中最小的
- 把元素加入到堆中的时候,都要和父节点进行比对,在最小堆 中,如果比父节点小,就要和父节点交换,交换之后还要继续和再和新的父节点对 比......。同理在最大堆中,如果比父节点大,就要和父节点交换
- 堆的添加会往上调整,堆的删除不仅会往下调整而且还有可能往上调整。堆中元素 的删除我们可以从堆顶删除,也可以从中间某个位置删除,如果从堆顶删除的话我 们只需要往下调整即可,因为堆顶没有父节点,不需要往上调整。如果从中间删除 的话,我们先要往下调整,如果往下调整没有成功(比如在最小堆中,他比两个子 节点都小),我们还要进行往上的调整。调整的原理就是把数组最后一个元素放到 要删除的元素位置上,然后在删除元素的位置上进行上下调整,原理其实都差不 多,我们来看一下最小堆顶部元素删除之后的调整。
- 我们知道最大堆就是堆顶元素始终保持的是最大值,最小堆就是 堆顶元素始终保持的是最小值,假如在最小堆中我们把堆顶元素一个个给移除不就 相当于排序了吗。
- [数据结构和算法试题大全](
https://www.toutiao.com/i6903421300237353476)
- 《数据结构与算法分析Java语言描述 原书第3版 》