双向(循环)链表是线性表的链式存储结构的又一种形式。
在之前已经讲述了单向链表和循环链表。相比于单向链表只能从头结点出发遍历整个链表的局限性,循环链表使得可以从任意一个结点遍历整个链表。
但是,不管单向链表也好,循环链表也罢,都只能从一个方向遍历链表,即只能查找结点的下一个结点(后继结点),而不能查找结点的上一个结点(前驱结点)。鉴于上述问题,引入了双向链表。由于双向循环链表包含双向链表的所有功能操作。因此,我们只讲述双向循环链表。
与单向链表不同,双向链表的结点构造如下图所示。即一个结点由三个部分组成,数据域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