day3记录的是单向链表,这里想记录的是双向链表,双向链表可以提供链表的综合性能,双向链表如下图所示:
双向链表多个元素图 双向链表单个元素图双向链表的设计思路和单向链表的设计差不多,不同的在于一些方法的设计判断,废话不多用,上代码讲解:
类构造设计图类构造设计图:
清除清除clear()
只要first 和last都等于null之后,内存自动会销毁了
获取节点图获取节点node(int index)
至于为什么用移位运算而不用除法运算呢,是因为移位运算更加有效率,看图(https://juejin.im/post/5a5886bef265da3e38496fd5)
移位运算图可以看到乘法或者除法这些最终转化成机器代码的时候都是进行了移位运算,既然这样的话,那我直接移动位数,效率不是更高么
添加元素图添加元素add(int index, E element)
代码结合图分析:
Node oldLast=last; 保存一个临时变量是为了如果index == size 但是不等于0的时候,代表不是第一个插入,这个时候需要将原来的last指针指向新的一个结点,但是last又用来指向了新添加元素,所以需要一个临时变量,转成图片大概是:
添加第一个节点图1Node oldLast=last;
last=new Node<>(oldLast,element,null);
这两句代码执行后,布局变成
添加第一个节点图2这个时候很明显就还差一条first指向新节点箭头:所以代码first = last;first 和 last指向一样,布局图变成如下:
添加第一个节点图3如果从后面添加,但是不是第一个元素,那布局图应该是怎样呢?
非0元素往最后插入图1Node oldLast=last; last=new Node<>(oldLast,element,null); 这两句代码执行后,布局变成:
非0元素往最后插入图2因为oldLast == null 判断不成立,进入了oldLast.next = last,这个时候布局变成:
非0元素往最后插入图3往最后添加元素成功,这个时候再来看看
多个元素中间插入 疑惑代码图可能有人对这两句代码有疑惑,会说不会报空指针异常么,当然不会啦,因为进入到这说明nextNode这个肯定有值,如果是第一个元素走的是上面的方法,所以上面这几行代码指向完之后,布局图应该如下:
往index 等于0的情况插入这个时候应该是还差一条first的指向第一个节点,因为是往index等于0的位置插入,这个时候,prev = null,应该直接将first 直接指向插进来的node就可以了,也就是first = node,要是不是往0插入,走else语句,将prev.next 指向插进来的节点,也就是prev.next = node;如下图所示
往index不等于0的情况插入1和前面一样,执行完全面4句代码之后,进入if判断之前,布局图:
往index不等于0的情况插入2这个时候进入判断的else,更改指向,布局图变成
往index不等于0的情况插入3添加方法插入完毕,下面讲一下删除的
元素移除remove(int index)
代码图:
移除元素这里同样也是要和添加一样,要分几种情况处理
只有一个元素图1只有一个元素
这种情况只需要将first 和 last 都统一指向null就可以了
node = node(index) 获取到节点,然后prev = node.prev 和 next = node.next 都等于null,所以最终会执行first = next,last = prev;又因为两个都是null,所以删除成功
删除元素有多个元素删除index 等于0元素1有多个元素删除第0个元素
node = node(index) 获取到0节点,然后prev = node.prev 等于null, next = node.next = 1节点,因为prev == null,所以执行first = next ;也就是first指向1节点,因为next不为null,所以执行next.prev = prev;也就是1节点的prev = null;如下图:
有多个元素删除index 等于0元素2有多个元素删除最后一个元素1有多个元素删除最后一个元素
node = node(index),获取到1节点,prev = node.prev;获取到0节点,next = node.next;获取到null,进入判断prev.next = next;因为next为null,所以0节点的next指向null,然后在进入判断,last = prev;prev 指向0节点,所以最后last指向0节点,如图:
有多个元素删除最后一个元素2删除方法也介绍完毕,双向链表暂时到此,后续有其他,我再补充
网友评论