首先创建两个类,一个测试类,一个链表类,在链表类中先创建一个静态内部类Node,写上双向链表中的前指针(prev)、值(value)和后指针(next)写上有参构造器
static class Node { private Node prev; private Integer value; private Node next; public Node(Node prev, Integer value, Node next) { this.prev = prev; this.value = value; this.next = next; } }
在链表类中写上构造器,初始化两个哨兵,一个头哨兵,一个尾哨兵,他们的值分别是:头哨兵的值(666),尾哨兵的值(888)先将头哨兵的后指针指向尾哨兵,再将尾哨兵的前指针指向头哨兵
public DoubleLinkedList() { this.head = new Node(null,666,null); this.tail = new Node(null,888,null); head.next = tail; tail.prev = head; }
然后通过索引找到某个Node,因为要找Node所以返回值需要是Node类型,方法名就叫做findNode,参数应该写上要找到的Node索引(index),因为我们有头哨兵所以我们需要先设置 i 为 -1 这样我们的数据就从0开始,设置一个Node变量p(p变量就是之后找到的要返回的Node),p从head开始和 i 同步,之后我们循环链表找到index(index == i)返回index位置上的Node(p),如果循环完事后没有找到index则返回null
public Node findNode(Integer index) { int i = -1; for (Node p = head; p != null; p = p.next, i++) { if (i == index) { return p; } } return null; }
之后需要写上添加方法,方法的返回值就是void,方法名就写insert 方法的参数就是要在那个位置上添加(索引index)和值(value)得到索引(index)我需要通过该索引得到该索引位置上前一个Node值所以我调用刚才写的findNode方法方法的参数就是index - 1(因为如果我们要向双向链表中添加值得话需要得到添加位置上的前面一个Node和原本这个位置的Node),调用findNode方法有两种返回值,一个是返回一个Node这个时候直接使用,一个是返回一个null如果返回值是null那么就用throw来抛出一个异常(一般为IllegalArgumentException),如果返回的是Node那么就调用它的next属性,得到该Node的后一个位置上的Node,再新建一个Node它的前指针(prev)指向Node,它的后指针(next)指向Node的后一个位置上的Node,值(value)就是传入的value,再将Node的next属性设置成新建的Node,将Node的后一个位置上的Node的prev属性设置成新的Node
public void insert(Integer index, Integer value) { Node prev = findNode(index - 1); if (prev == null) { throw new IllegalArgumentException(String.format("index [%d] 已越界",index)); } Node next = prev.next; Node node = new Node(prev, value, prev.next); prev.next = node; next.prev = node; }
我们可以先把addFirst先写上返回值就是void,参数写值(value)就行,我们直接在方法中调用insert方法就行,因为是从头添加数据所以索引(index)就是0
public void addFirst(Integer value) { insert(0,value); }
为了方便快捷的遍历我们的双向链表我们可以实现Iterable接口,重写iterator方法(该方法需要返回一个重写的Iterator类,所以我们需要使用匿名内部类来实现Iterator类中的hasNext方法和next方法),我们需要指定一个Node类型的p变量,p指向的就是头哨兵的next属性,因为hasNext方法返回的是boolean所以如果是true的话就代表链表中还有值,如果是false的话就代表链表中没有值了,next方法返回的是Integer所以它返回的是循环的数据value再将p变量向后移一位,返回值是p的value属性
public class DoubleLinkedList implements Iterable<Integer>{ @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { Node p = head.next; @Override public boolean hasNext() { return p != tail; } @Override public Integer next() { Integer value = p.value; p = p.next; return value; } }; } }
测试类的代码就是创建链表类的对象,调用对象的insert方法来添加数据然后因为实现了Iterable接口重写了Iterator方法所以就直接用增强for来遍历链表就行
public class DoubleLinkedListTest { @Test public void test1() { DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); doubleLinkedList.insert(0,1); doubleLinkedList.insert(1,2); doubleLinkedList.insert(2,3); doubleLinkedList.insert(3,4); for (Integer integer : doubleLinkedList) { System.out.println(integer); } } }
双向链表(哨兵)删除方法:
删除方法名remove,方法参数需要一个要删除位置的索引值(value)返回值为空(void)先用findNode找到索引值前一个位置上的prevNode,判断prevNode是否为空(Null),然后通过next属性找到索引值位置上的nowNode,然后再通过索引值位置上的nowNode的next属性找到索引值后一个位置上的nextNode,判断nextNode是否与tail相等,将prevNode的next属性设置成nextNode,将nextNode的prev属性设置成prevNode,这样就删除了索引位置上的Node
public void remove(Integer index) { Node prev = findNode(index - 1); if (prev == null) { indexIllegal(index); } Node nowNode = prev.next; if (nowNode == tail) { indexIllegal(index); } Node next = nowNode.next; prev.next = next; next.prev = prev; }
头删除双向链表(哨兵):
方法名removeFirst,方法参数不用写,方法返回值为空(void),直接调用写过的remove方法参数的值为0
public void removeFirst() { remove(0); }
尾删除双向链表(哨兵)
方法名removeLast,方法参数不用写,方法返值为空(void),因为用的是哨兵模式所以直接找到尾哨兵的tail的前一个节点就是要删除的removeNode,判断removeNode是否是头哨兵(head),如果是判处一个异常,再通过prev属性找到尾节点removeNode的前一个prevNode,将prevNode的next属性直接指向尾哨兵(tail),再将尾哨兵的prev属性指向prevNode
public void removeLast() { Node removeNode = tail.prev; if (removeNode == head) { indexIllegal(0); } Node prevNode = removeNode.prev; prev.next = tail; tail.prev = prev; }
测试remove方法:
使用增强for来进行遍历
@Test public void test2() { DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); doubleLinkedList.insert(0, 1); doubleLinkedList.insert(1, 2); doubleLinkedList.insert(2, 3); doubleLinkedList.insert(3, 4); doubleLinkedList.remove(2); for (Integer integer : doubleLinkedList) { System.out.println(integer); } }
结果:
1 2 4
测试removeFirst方法:
@Test public void test2() { DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); doubleLinkedList.insert(0, 1); doubleLinkedList.insert(1, 2); doubleLinkedList.insert(2, 3); doubleLinkedList.insert(3, 4); doubleLinkedList.removeFirst(); for (Integer integer : doubleLinkedList) { System.out.println(integer); } }
结果:
2 3 4
测试removeLast方法:
@Test public void test2() { DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); doubleLinkedList.insert(0, 1); doubleLinkedList.insert(1, 2); doubleLinkedList.insert(2, 3); doubleLinkedList.insert(3, 4); doubleLinkedList.removeLast(); for (Integer integer : doubleLinkedList) { System.out.println(integer); } }
结果:
1 2 3