![f3555bb5b21ad64931e5431bf408789c.png](https://i-blog.csdnimg.cn/blog_migrate/6e9585151f6b373f20274ce67c436ee5.jpeg)
面试官:你能说说 LinedList 吗?
Python 小星:LinedList 数据结构是链表,查询慢,增删快。
面试官:那 LinkedList 是单向链表还是双向链表?
Python 小星:双向链表
面试官:那 LinkedList 是双向循环链表吗?
Python 小星:......
面试官:没事,那我问你 LinkedList 为什么不用单链表,而是用双链表?
Python 小星:......
面试官:那 LinkedList 删除元素,默认是删除最后一个还是第一个元素?
Python 小星:最后一个
面试官:回去等消息吧
如果你对链表不是很熟悉,可以先看看 @Python大星 之前的文章
Python 算法 02--数组和链表(上)
这里用图简单带过:
1、单链表
![74ad9eef82c28c03224908d0f284bd58.png](https://i-blog.csdnimg.cn/blog_migrate/c774e42c01ea2e0d562c8e661c577d7a.jpeg)
2、双向链表
![9a1f27bc9e00eac3cc628b51db9fe9ec.png](https://i-blog.csdnimg.cn/blog_migrate/d3a9931fdca09f2755b570d3b7a76537.jpeg)
3、循环链表
![e9e3aaf338b4d779d1ed61743448efa2.png](https://i-blog.csdnimg.cn/blog_migrate/48e471c02c941f40066d8a6a526db590.jpeg)
单链表 和 双向链表的区别???
① 删除单链表中的某个结点时,一定要得到待删除结点的前驱,得到该前驱有两种方法,第一种方法是在定位待删除结点的同时一路保存当前结点的前驱。第二种方法是在定位到待删除结点之后,重新从单链表表头开始来定位前驱。尽管通常会采用方法一。但其实这两种方法的效率是一样的,指针的总的移动操作都会有 2*i 次。而如果用双向链表,则不需要定位前驱结点。因此指针总的移动操作为 i 次。
② 查找时也一样,我们可以借用二分法的思路,从 head(首节点)向后查找操作和 last(尾节点)向前查找操作同步进行,这样双链表的效率可以提高一倍。
相信不少小伙伴在浏览其他博客时,会看到有的地方说 LinkedList 是双向链表,有的地方说是双向循环链表。这个各有其道理,jdk 1.6 ,LinkedList 是双向循环链表,从 jdk 1.7 后,LinkedList 是简单的双向链表。下面我们主要以 jdk 1.8 的 LinkedList 说起。
LinkedList 源码解析
1、类的属性
实际元素个数,首节点,尾节点
![eed70906cb7678c7f4d520405cef27e4.png](https://i-blog.csdnimg.cn/blog_migrate/ec993bdb9af5a218cbff79a6a8179fa3.jpeg)
2、 Node 的静态内部类
![74db6ad1b1513de65732489f2d9bf101.png](https://i-blog.csdnimg.cn/blog_migrate/0bbef1a63a41c618f990fb170c71ef30.jpeg)
3、构造函数
![b453c39461e1463c986ace4e7b143b6c.png](https://i-blog.csdnimg.cn/blog_migrate/01caad83b0ab6440898eabdad1785073.jpeg)
4、查找 - get
先校验 index 的有效性
在查找时,先比较 index 与 (size >> 1),即 index 与 size 中间值比较。
如果 index 较小,则从 first 开始往 last 方向遍历;
如果 index 较大,则从 last 开始往 first 方向遍历。
![054a48c55d70079c2456e2c177cb0d8d.png](https://i-blog.csdnimg.cn/blog_migrate/e9882b24b7d64c5c737e2290f41fb993.jpeg)
5、添加 - add
注意:当从指定位置添加元素,其中可能会使用 node 方法,从查找中我们可以知道,查找当前 index 对应的 node 元素,需要遍历链表,如果增加的元素在中间,在大数据量下,花费时间可能比 ArrayList 要多。
![cc4a09a7092aea6d4c5fb82dc5106e96.png](https://i-blog.csdnimg.cn/blog_migrate/ba8063b6b1998c7b9ed7a45dd7213459.jpeg)
① 插入到第一个元素中 - linkFirst
新添加的元素,前节点 pre 为 null,后节点 next 为原 first 节点。
新的 first 节点为当前添加的 new。
判断 first 是否为空,即添加的 new 是否是第一个元素,
如果为空,则 last 节点 为 当前节点 new;
如果不为空,last 节点不变,原 first 的前节点 pre 变更为 new,后节点 next 不变。
![cd8d9555daa33f8bc9d1937361fcf5f8.png](https://i-blog.csdnimg.cn/blog_migrate/dfb3be62df652b403aac003b5eed35c6.jpeg)
![b19b3f6c24f5b50b1dca0b150bdfe00e.png](https://i-blog.csdnimg.cn/blog_migrate/e95c0dec4d61904137c17ea29bff9fe9.jpeg)
② 插入到最后一个元素中 - linkLast
新添加的元素后节点 next 为 null,前节点 pre 为原 last 节点。
新的 last 节点为当前添加的 new。
判断 last 是否为空,即添加的 new 是否是第一个元素,
如果为空,则 first 节点为当前节点 new ;
如果不为空,则原 last 节点的后节点 next 为当前节点 new
![77f641a21b34902450f47e953c6f9d81.png](https://i-blog.csdnimg.cn/blog_migrate/be73da61dfcc6a119a9ce555530340de.jpeg)
![9ddca9ce012934a478304d1075d07d84.png](https://i-blog.csdnimg.cn/blog_migrate/c7fb4ca034a1809315759b496a085679.jpeg)
③ 在非空节点前插入元素 - linkBefore
和 linkFirst 原理一样
![defc64943e49eff4b104f3a8191eafe8.png](https://i-blog.csdnimg.cn/blog_migrate/7df113309daf1458ef744d6812a84bdb.jpeg)
6、修改
先校验 index 的有效性
然后 node 方法返回当前 index 对应的 node 值
最后给原 node 值赋予新的 element
![e87e456d654ac8c2146d4b56057fd758.png](https://i-blog.csdnimg.cn/blog_migrate/d9d7e633db9729edb5435b67c2571c8b.jpeg)
7、删除
我们可以看到 LinkedList 默认是从 first 节点开始删除数据的
![0a843379411a46aae382e8101f7932cf.png](https://i-blog.csdnimg.cn/blog_migrate/bfbea8eece330f4fc9fe8b9c9f325e3e.jpeg)
@Python大星 | 文