双向链表提供了向前遍历,也可以向后遍历整个链表,其中的问题关键就在每个链结点有两个指向其他链结点的引用。而不是一个,第一个像普通链表一样指向下一个链结点,第二个指向前一个链结点
,如图:双向链表的缺点是每次插入或者删除一个链结点的时候,要处理四个链结点的引用,而不是两个;两个链接前一个链结点,两个链接后一个链结点,由于多了两个引用,链结点的占用空间也变得大了一些
插入一个新的链结点,会把原来的链结点指向新的链结点,同时把新的链结点又指向前面的链结点,因为是双向链表,所以用图片更容易说清楚。
删除,删除的话相对来说比较复杂,假设被删除的是current所指的链结点,同时假设删除的不是第一个链结点,也不是最后一个链结点,current.previus(被删链结点的前一个链结点)的next字段指向current.next(被删链结点的后一个链结点),current.next的previous字段指向current.previous,这样就使current指向的链结点和链表断开了链接
current.previous.next = current.next;
current.next.previous = current.previous;
以下是代码 java代码建议对照上面的图形查看
public class DoubleLinkList {
public class DoubleNode {
public long data; //节点数据
public DoubleNode next;//下一个节点
public DoubleNode previous;//上一个节点
public DoubleNode(long value) {
this.data = value;
}
public void display() {
System.out.print(data + " ");
}
}
public DoubleNode first;//头节点
public DoubleNode end;//尾节点
public DoubleLinkList() {
first = null;
end = null;
}
/**
* 判断是否为空
*/
public boolean isEmpty() {
return first == null;
}
/**
* 在头节点插入数据
*/
public void insertFirst(long value) {
DoubleNode node = new DoubleNode(value);
if (isEmpty()) {
end = node;//当没有节点信息 新增的节点就是尾节点
} else {
first.previous = node;//因为是新增头节点所以旧头节点的上个节点等于新节点
}
node.next = first;//新增节点的下一个节点就为旧的新节点
first = node;//赋值后,新增的节点就为头节点
}
/**
* 在尾部添加节点
*/
public void insertEnd(long value) {
DoubleNode node = new DoubleNode(value);
if (isEmpty()) {
first = node;//当不存存在的时候 设置为新的节点
} else {
end.next = node;//存在的话 将新增的节点赋值给尾节点的下一个节点
}
node.previous = end;//将旧的尾节点设置为新增节点的上一个节点
end = node;//将新增的节点设置为新的尾节点
}
/**
* 删除链头 修改first的值
*/
public DoubleNode deleteHead() {
DoubleNode doubleNode = first;
if (doubleNode.next != null) {
doubleNode.next.previous = null;//将下一个节点里面的里面关联的上一个节点设置为null
} else {
return null;//没有下一个节点就直接返回null
}
first = doubleNode.next;//将下一个节点设置为新的开始节点
return doubleNode;
}
/**
* 删除链尾 修改end的值
*/
public DoubleNode deleteEnd() {
DoubleNode doubleNode = end;
if (doubleNode.previous != null) {
doubleNode.previous.next = null;//将删除节点的上一个节点的下一个节点设置为null
} else {
return null;
}
end = doubleNode.previous;//index尾节点就是被删除的节点的上一个节点
return doubleNode;//返回被删除的尾节点
}
/**
* 显示所有
*/
public void display() {
DoubleNode doubleNode = first;
while (doubleNode != null) {
doubleNode.display();//采用递归
doubleNode = doubleNode.next;//指针后移以为
}
System.out.println(" ");
}
/**
* 根据数据查找
*/
public DoubleNode find(long value) {
DoubleNode doubleNode = first;
while (doubleNode.data != value) {
if (doubleNode.next == null) {//当没有下一个节点的时候 返回null
return null;
}
doubleNode = doubleNode.next;//将下一个节点的内容赋值给本节点继续查找
}
return doubleNode;
}
/**
* 根据数据删除
*/
public DoubleNode deleteByValue(long value) {
DoubleNode doubleNode = first;
if (doubleNode == first) {//没有新节点的话
end = null;//没有尾节点
}
if (doubleNode != null) {
while (doubleNode.data != value && doubleNode.next != null) {//当查询的数不等于本节点的数据并且 存在下一个节点的时候 进去循环
doubleNode = doubleNode.next;//将下一个节点的内容赋值给本节点
}
}
doubleNode.previous.next = doubleNode.next;//将被删除的节点的下一个节点赋值给被删除节点的上一个节点的下一个节点 头节点
doubleNode.next.previous = doubleNode.previous;//将被删除的上一个节点赋值给删除节点的下一个节点的上一个节点 尾节点
return doubleNode;
}
public static void main(String[] args) {
DoubleLinkList doubleLinkList = new DoubleLinkList();
// 在头节点添加4个数据
doubleLinkList.insertFirst(12);
doubleLinkList.insertFirst(22);
doubleLinkList.insertFirst(33);
doubleLinkList.insertFirst(44);
// 打印出来
System.out.println("插入头节点的数据展示");
doubleLinkList.display();
// 将尾节点新增四个数据
doubleLinkList.insertEnd(55);
doubleLinkList.insertEnd(66);
doubleLinkList.insertEnd(77);
doubleLinkList.insertEnd(88);
// 输出打印
System.out.println("插入尾节点后数据的显示");
doubleLinkList.display();
// 删除 尾节点
doubleLinkList.deleteHead();
System.out.println("删除头节点的数据展示");
doubleLinkList.display();
System.out.println("删除尾节点的数据展示");
doubleLinkList.deleteEnd();
doubleLinkList.display();
}
}
输出
小结
双向链表中,没和链结点包含对前一个节点的引用,后一个节点的引用,
双向链表允许反向遍历,并且可以从表尾删除
双向链表可以从表位插入