双向(循环)链表是线性表的链式存储结构的又一种形式。
在之前已经讲述了单向链表和循环链表。相比于单向链表只能从头结点出发遍历整个链表的局限性,循环链表使得可以从任意一个结点遍历整个链表。
但是,不管单向链表也好,循环链表也罢,都只能从一个方向遍历链表,即只能查找结点的下一个结点(后继结点),而不能查找结点的上一个结点(前驱结点)。鉴于上述问题,引入了双向链表。由于双向循环链表包含双向链表的所有功能操作。因此,我们只讲述双向循环链表。
与单向链表不同,双向链表的结点构造如下图所示。即一个结点由三个部分组成,数据域DATA,左指针域llink和右指针域rlink。其中,数据域用来存放结点数据信息,左指针域用来指向前驱结点,右指针域用来指向后继结点。双向循环链表有一个特性:p->llink->rlink = p->rlink->llink = p。
用来表示双向链表结点的代码如下:
public class Node { private Object data; private Node lLink, rLink; //构造函数 public Node() { this.data = null; this.lLink = null; this.rLink = null; } //构造函数重载 public Node(Object data) { this.data = data; this.lLink = null; this.rLink = null; } public Node(Object data, Node lLink, Node rLink) { this.data = data; this.lLink = lLink; this.rLink = rLink; } //读结点数据 public Object getData() { return data; } //写结点数据 public void setData(Object data) { this.data = data; } //获取结点的前驱结点 public Node getLeftLink() { return lLink; } //获取结点的后继结点 public Node getRightLink() { return rLink; } //设置结点的前驱结点 public void setLeftLink(Node lLink) { this.lLink = lLink; } //设置结点的后继结点 public void setRightLink(Node rLink) { this.rLink = rLink; } }
在带有头结点的双向循环链表类代码如下。在代码示例中,仅介绍了双向循环链表的创建、插入元素、删除元素和打印链表的操作。
public class DoubleLink { /** * 带有头结点的双向循环链表的头结点 */ private Node headNode = new Node(); /** * 链表长度 */ private int length = 0; /** * 创建一个带有头结点的双向链表 * * @param datas 数组,用来表示双向链表中各个结点的数据域 */ public void createDoubleLink(Object[] datas) { Node p, r; r = headNode; for(int i=0; i<datas.length; i++) { p = new Node(datas[i]); r.setRightLink(p); p.setLeftLink(r); p.setRightLink(headNode); r = p; length++; } headNode.setLeftLink(r); } /** * 打印带有头结点的双向循环链表 */ public void printDoubleLink() { Node p = headNode.getRightLink(); while(p != headNode) { System.out.print(p.getData() + " "); p = p.getRightLink(); } System.out.println(); } /** * 在双向循环链表的pos位置后面插入数据域为item的结点 * * @param pos 表示插入元素的位置。计算位置时,头结点的位置为0 * @param item 表示插入结点的数据域 * @return 插入成功返回true;否则返回false */ public boolean insertItem(int pos, Object item) { if(pos < 0 || pos > length) { return false; } else { Node p = new Node(item); if(pos == 0) { p.setLeftLink(headNode); p.setRightLink(headNode.getRightLink()); headNode.getRightLink().setLeftLink(p); headNode.setRightLink(p); } else if (pos == length) { p.setLeftLink(headNode.getLeftLink()); p.setRightLink(headNode); headNode.getLeftLink().setRightLink(p); headNode.setLeftLink(p); } else { int count = 1; Node r = headNode.getRightLink(); while(count < pos) { r = r.getRightLink(); count++; } p.setLeftLink(r); p.setRightLink(r.getRightLink()); r.getRightLink().setLeftLink(p); r.setRightLink(p); } return true; } } /** * 删除带头结点的双向链表中第一次出现数据域为item的结点 * * @param item 删除结点的数据域 * @return 删除成功,返回true;否则,返回false */ public boolean deleteItem(Object item) { Node p = headNode.getRightLink(), r = headNode; while(p != headNode) { if(p.getData() == item) { r.setRightLink(p.getRightLink()); p.getRightLink().setLeftLink(r); return true; } else { r = p; p = p.getRightLink(); } } return false; } }
数据结构之双向链表(包含双向循环链表),布布扣,bubuko.com
原文:http://blog.csdn.net/bbewx/article/details/26058003