1. 双向链表:在单链表的每个结点中,再设置一个指向其前驱结点的指针域,那么在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。
2. 单链表和双向链表比较:
单链表:总是要从头到尾找结点,只能正遍历,不能反遍历。
双向链表: 可以从头找到尾,也可以从尾找到头,即正反遍历都可以,可以有效提高算法的时间性能,但由于每个结点需要记录两份指针,所以在空间占用上略多一点,这就是通过空间来换时间。
3. Java实现双向链表:
// 双向链表 public class DoubleLinkedList<E> { private Node<E> head; // 头结点 private int size; // 链表长度 // 建立一个空链表 public DoubleLinkedList() { head = null; size = 0; } // 在头结点前插入 public boolean addBeforeHead(E data){ Node<E> newNode = new Node<E>(data); if(isEmpty()){ head = newNode; }else{ head.setPrev(newNode); newNode.setNext(head); head = newNode; } size++; return true; } // 在链表尾部插入 public boolean addAfterTail(E data){ Node<E> newNode = new Node<E>(data); if(isEmpty()){ head = newNode; }else{ Node<E> tail = get(size); tail.setNext(newNode); newNode.setPrev(tail); // 设置新结点的上一结点 } size++; return true; } // 插入指定位置的结点 public boolean insert(int position, E data) { if(position >= 1 && (position <= size + 1)){ Node<E> newNode = new Node<E>(data); if(isEmpty() || position == 1){ // 链表为空或在头结点前插入 addBeforeHead(data); }else if(position == size + 1){ // 在尾结点后插入 Node<E> preNode = get(position - 1); newNode.setPrev(preNode); preNode.setNext(newNode); }else{ // 在其他位置插入 Node<E> preNode = get(position - 1); // 获取position的前一结点 Node<E> afterNode = preNode.getNext(); // 获取未插入结点时position位置对应结点 newNode.setPrev(preNode); // ① newNode.setNext(afterNode); // ② afterNode.setPrev(newNode); // ③ preNode.setNext(newNode); // ④ } size++; return true; } return false; } // 删除指定位置的结点 public E delete(int position) { E result = null; if(position >= 1 && position <= size){ if(position == 1){ // 删除头结点 result = head.getData(); Node<E> afterHead = head.getNext(); afterHead.setPrev(null); head.setNext(null); head = afterHead; }else if(position == size){ // 删除尾结点 Node<E> preNode = get(position - 1); // 获取待删除结点的前一结点 Node<E> delNode = preNode.getNext(); // 获取待删除结点 result = delNode.getData(); preNode.setNext(null); }else{ // 删除其他结点 Node<E> preNode = get(position - 1); // 获取待删除结点的前一结点 Node<E> delNode = preNode.getNext(); // 获取待删除结点 result = delNode.getData(); Node<E> nextNode = delNode.getNext();// 获取待删除结点的下一结点 preNode.setNext(nextNode); // ① nextNode.setPrev(preNode); // ② } size--; } return result; } // 获取某个位置的结点(正序遍历) public Node<E> get(int position){ Node<E> targetNode = null; if(!isEmpty() && position >= 1 && position <= size){ targetNode = head; for(int i = 1; i < position ; i++){ targetNode = targetNode.getNext(); // 循环获取对应位置的结点 } } return targetNode; } // 获取链表的长度 public int getSize(){ return size; } // 判断链表是否为空 public boolean isEmpty(){ return size == 0; } // 打印链表数据 public void display(){ Node<E> node = head; System.out.print("双向链表: "); for(int i = 0; i < size; i++){ System.out.print(" " + node.getData()); node = node.getNext(); } System.out.println(""); } }
//结点类,包含结点的数据和指向下一个节点的引用 public class Node<E> { private E data; // 数据域 private Node<E> next; // 指针域保存着下一节点的引用 private Node<E> prev; // 指针域保存着上一节点的引用 (相比单链表,双向链表多了这个指针) public Node() { } public Node(E data) { this.data = data; } public Node(E data, Node<E> next, Node<E> prev) { this.data = data; this.next = next; this.prev = prev; } public E getData() { return data; } public void setData(E data) { this.data = data; } public Node<E> getNext() { return next; } public void setNext(Node<E> next) { this.next = next; } public Node<E> getPrev() { return prev; } public void setPrev(Node<E> prev) { this.prev = prev; } }
public class Main { public static void main(String[] args) { DoubleLinkedList<Integer> dll = new DoubleLinkedList<Integer>(); dll.addBeforeHead(2); dll.addAfterTail(3); dll.addBeforeHead(1); dll.display(); dll.insert(4,4); dll.insert(5,5); dll.insert(6,6); dll.display(); dll.delete(6); dll.delete(3); dll.delete(1); dll.display(); System.out.println("双向链表的长度为: " + dll.getSize()); } }