考虑到单向链表的缺点,所有节点的遍历都是从头结点开始,若一条记录居于整个链表的结尾,当要查询该记录效率就会比较低,采用双向链表,会更具有扩展性;
在实现过程的整体思路,定义一个链表类,在其中定义一个节点类,在链表类定义头和尾结点的构造方法中创建结点对象,使其头节点的next指向尾结点,尾结点的prenode 指向head,进行链表的初始化。接着就相对简单,定义增加,删除,修改,查询等方法。
注意的细节问题:无论是增加一个节点,还是删除一个节点都应该注意考虑prenode 的指向,否则在从后向前遍历的过程中,JVM会抛出空指针异常,在根据内容相同删除节点时,若两个数据处于相邻的情况,考虑删除数据的正确性,节点的遍历与索引的自增并不同步,会造成删除的数据有误,每次在删除节点后,遍历节点的变量应该减1。
public class DoubleLinkedDemo { static class DoubleLinked<T>{ private class Node<T>{ Node<T> prenode ; T value; Node<T> next; public Node(){}; public Node(T value){ this.value = value; } } private Node<T> head; private Node<T> end; private int size; public DoubleLinked(){ this.head = new Node<>(); this.end = new Node<>(); head.next = end; end.prenode= head; this.size = 0; } //从前往后追加一个节点 public void preadd(T value){ Node<T> newnode = new Node<>(value); int i =0; Node<T> lastnode = head; while (i<size){ lastnode = lastnode.next; i++; } //设置新创建节点的前一个指向 newnode.prenode=lastnode; //设置新创建节点的后一个指向 newnode.next = lastnode.next; //设置尾结点的前指向 lastnode.next.prenode = newnode; //追加新节点到最后一个节点上 lastnode.next = newnode; size++; } //在正确的索引下添加一个元素 public void preadd(int index,T value){ if(index==size){ preadd(value); }else { checkIndex(index); int i =0; Node<T> newnode = new Node<>(value); Node<T> indexnode = head; while (i<index){ indexnode = indexnode.next; i++; } newnode.prenode = indexnode; newnode.next = indexnode.next; indexnode.next.prenode = newnode; indexnode.next = newnode; size++; } } //删除指定索引的元素 public void remove(int index){ checkIndex(index); int i = 0; Node<T> removenode = head; while(i<=index){ removenode = removenode.next; i++; } removenode.prenode.next = removenode.next; removenode.next.prenode = removenode.prenode; size--; } //修改指定索引节点的值 public void set(int index,T value){ checkIndex(index); int i =0; Node<T> setNode = head; while (i<=index){ setNode = setNode.next; i++; } setNode.value = value; } //删除值为value的节点 public void remove(T value){ int i =0; Node<T> removenode = head; int flag = 0; while (i<size){ removenode = removenode.next; if(removenode.value.equals(value)){ remove(i); System.out.println("成功删除值为"+value+"的数据"); //每次成功删除之后,后面的节点位置前移,判断的依旧是根据节点的next,但是删除的是i索引的值,若不进行减1,则会误删元素 i--; flag++; } i++; } if(flag==0){ System.out.println("未查找到要删除的数据"); } } public void show (){ Node<T> shownode = head; for (int i =0;i<size;i++){ shownode = shownode.next; System.out.print(shownode.value+" "); } System.out.println(); } public void show1 (){ Node<T> shownode = end; for (int i =0;i<size;i++){ shownode = shownode.prenode; System.out.print(shownode.value+" "); } System.out.println(); } public void checkIndex(int index){ if (index<0||index>=size){ throw new IndexOutOfBoundsException("下标越界"+index); } } } public static void main(String[] args) { DoubleLinked<Integer> link1 = new DoubleLinked<Integer>(); link1.preadd(4); link1.preadd(10); link1.preadd(6); link1.preadd(2,7); link1.preadd(3,9); link1.set(2,10); //link1.remove(1); link1.show(); link1.show1(); link1.remove((Integer) 10); link1.show1(); } }