LinkedList是一个双向链表,长啥样呢
如图所示:
- 前驱为了指向当前节点的上一个节点
- 后驱为了指向当前节点的下一个节点
- 中间item 存数据
数据结构是啥样子呢,代码如下:
public class LinkedList<E> {
/**
* 结点
* @param <E>
*/
private static class Node<E> {
// 数据域
E item;
// 后驱指针
Node<E> next;
// 前驱指针
Node<E> prev;
// 构造方法 前驱 数据 后驱
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
}
了解了它的数据结构之后,看看它可以干啥,使用过他的小伙伴都知道,它有add方法,还可以在任意位置插入一个元素,可以get,可以remove 可以addAll 可以removeAll 等等
看下咋实现的嘞
add的实现
- 向最尾元素插入数据,咋搞,看下实现代码
-
/** * 对外需要调用的方法 * @param e 需要插入的原色 */ public void add (E e) { // 从后面插入 linkLast(e); } /** * 在最后添加 * @param e */ private void linkLast(E e) { // 首先你需要new 一个存放你数据的节点吧 // 构造方法 入参咋填 // 1.往最后面插入的 肯定是需要拿到最后的节点的last 后面说last从哪里来的 先理解它就 是最后一个 // 2.构造方法内,因为是要放在最后,所以呢 原来的last就变成了存放的e的前驱,然后中间 // 就是它的值域 最后呢,就是它的后驱,很显然现在放的就是最后,它的最后没东西,所以 // 放null Node<E> newNode = new Node<E>(last, e, null); // 用一个临时指针 先指向最后的值, Node<E> l = last; // 因为是要往最后添加的,所以newNode就是新的最后 我这描述的绝对白话文 // 把last移动一下,移动到newNode的位置 下次在添加的时候 last就是这次的newNode了 以 此类推 last = newNode; // 然后你会发现这里有个问题,万一我链表里,连个屁都没有咋办 // 一个都没有说明什么,说明first都是空的 所以只需要把first 赋值给newNode就可以了 if (l == null) { first = newNode; }else { // 如果不是空 就要把它的后驱指针 指向新插入的节点 l.next = newNode; } size ++; }
get方法实现
-
/** * 获取第index位置上的节点的值域 * @param index * @return */ public E get(int index) { // 首先判断一下 输入的index 不能超过范围 if(index < 0 || index >size) { return null; } return node(index).item; } /** * 获取第index位置上的节点 * @param index * @return */ private Node<E> node(int index) { //index在前半部份 if (index < (size / 2)) { Node<E> node = first; for(int i = 0; i < index; i++) { node = node.next; } return node; } else { //index在后半部份 Node<E> node = last; for(int i = size - 1; i > index; i--) { node = node.prev; } return node; } }
add(int index, E e)实现
-
/** * �在index的位置上添加一个元素 * @param index * @param e */ public void add (int index, E e) { // 判断输入合法性 if(index < 0 || index >size) { return; } // 如果输入的和大小一样 说明是往最后插入的 直接调用 if (index == size) { linkLast(e); } else { // 先取目标的节点 Node<E> target = node(index); // 找到它的上一个节点 Node<E> pre = target.prev; // 前一个节点 当前存放的值 后一个节点就是找到的目标 Node<E> newNode = new Node<E>(pre, e, target); //要考虑index=0时的情况 if(pre == null) { // 如果链表里只有1个 那么它的前驱一定是null 所以只需要把first移动到 新节点上就可以了 first = newNode; } else { // 否则 找到前驱的下个节点赋值 pre.next = newNode; } pre = newNode; size++; } }
Remove实现
-
public void remove(int index){ Node<E> target = node(index); unlinkNode(target); } private void unlinkNode(Node<E> p) { // 找头 Node<E> pre = p.prev; // 找尾 Node<E> next = p.next; // 头是空的 if (pre == null) { // 直接移动到 当前节点的下一个 那么当前节点就没有了 first = p.next;//删除头节点 } else { // 否则 头的下一个 执行当前节点的下一个 忽略掉自己 也就删除了 pre.next = p.next; } // 同理 if (next == null) { last = p.prev;//删除尾结节 } else { next.prev = p.prev; } size--; }
一看就会,一写就错