1.单链表的一个优点是结构简单,但是它也有一个缺点,即在单链表中只能通过一个结点的引用访问其后续结点,而无法直接访问其前驱结点,要在单链表中找到某个结点的前驱结点,必须从链表的首结点出发依次向后寻找,但是需要Ο (n)时间。为此我们可以扩展单链表的结点结构,使得通过一个结点的引用,不但能够访问其后续结点,也可以方便的访问其前驱结点。扩展单链表结点结构的方法是,在单链表结点结构中新增加一个域,该域用于指向结点的直接前驱结点。扩展后的结点结构是构成双向链表的结点结构。在双向链表中进行查找与在单链表中类似,只不过在双向链表中查找操作可以从链表的首结点开始,也可以从尾结点开始,但是需要的时间和在单链表中一样。
单链表的插入操作,除了首结点之外必须在某个结点的后面进行,而在双向链表中,在一个已知的结点之前或之后都可以。
1)s.prev
= p.prev;
2) p.prev.next = s;
3) s.next = p;
4) p.prev = s;
单链表的删除操作,除了首结点之外必须在知道待删结点的前驱结点的基础上才能进行,而在双向链表中在已知某个结点引用的前提下,可以完成该结点自身的删除。
p.prev.next = p.next;
p.next.prev = p.prev;
在具有头尾结点的双向链表中插入和删除结点,无论插入和删除的结点位置在何处,因为首尾结点的存在,插入、删除操作都可以被归结为上图介绍的在双向链表某个中间结点的插入和删除;并且因为首尾结点的存在,整个链表永远不会为空,因此在插入和删除结点之后,也不用考虑链表由空变为非空或由非空变为空的情况下 head 和 tail 的指向问题;从而简化了程序。
双向链表的缺点是每次插入或删除一个结点的时候,要处理四个链结点的引用,而不是两个;两个连接前一个一个链结点,两个连接后一个链结点。当然由于多了两个引用,链结点的占用空间也大了一些。
<strong>public class DoubleLink { public Link first; public Link last; public DoubleLink() { // 构造器初始化 this.last = null; this.first = null; } public boolean isEmpty() { // 判断是否为空 return first == null; } public void insertFirst(int data) { // 将元素插入链表头 Link link = new Link(data); if (isEmpty()) last = link; // 如果为空,last需要改变 else first.prev = link; link.next = first; first = link; } public void insertLast(int data) { // 将元素插入链表尾 Link link = new Link(data); if (isEmpty()) last = link; else last.prev = link; link.prev = last; last = link; } public boolean insertAfter(int key, int idata) { // 在某元素后插入 Link current = first; while (current.data != key) { current = current.next; } Link link = new Link(idata); if (current == last) { link.next = null; last = link; } else { link.next = current.next; current.next.prev = link; } link.prev = current; current.next = link; return true; } public Link deleteKey(int key) { // 删除某项元素 Link current = first; while (current.data != key) { current = current.next; } first = current.next; if (current == last) last = current.prev; else current.next.prev = current.prev; return current; } public Link deleteFirst() { // 删除表开头的元素 Link temp = first; if (first.next == null) last = null; else first.next.prev = null; // first结点的next字段引用的链结点的prev字段 first = first.next; return temp; } public Link deleteLast() { // 删除表末尾的元素 Link temp = last; if (first.next == null) first = null; else last.prev.next = null; last = last.prev; return temp; } public void showFirst() {// 前向展示 Link current = last; while (current != null) { current.show(); current = current.prev; } } public void showLast() {// 后向展示 Link current = first; while (current != null) { current.show(); current = current.next; } } public static void main(String[] args) { DoubleLink dlink = new DoubleLink(); dlink.insertFirst(1); dlink.insertFirst(3); dlink.insertFirst(2); dlink.insertAfter(2, 4); dlink.showFirst(); } } class Link { public int data; // 存放的数据 public Link prev;// 对前一项的引用,直接前驱 public Link next;// 对后一项的引用,直接后继 public Link(int data) { this.data = data; } public void show() { System.out.println(data + " "); } }</strong>