双向链表有前后两个指针,一个指向直接前驱节点,另一个指向直接后继节点。完整的双向链表如下图(原谅手画比较粗糙)所示:
在实现代码时,需要定义一个节点类,并且初始化一下他们的指针,如图所示:
节点类实现代码如下:
public class Node {
int data;
Node prior;
Node next;
public Node(int data) {
this.data = data;
prior = this;
next = this;
}
}
下面是对双向链表的一系列操作:
- 打印双向链表
public void showList() { System.out.println("开始检索双向列表......"); if(this.head == null) { System.out.println("目前双向链表为空。"); } else { Node pointer = this.head; do { System.out.print(pointer.data + " "); pointer = pointer.next; } while(pointer != this.head); System.out.println("\n检索完成。"); } }
- 从链表头插入
public void addFirst(int data) { //创建一个新节点 Node node = new Node(data); //若头节点为空 if(this.head == null) { this.head = node; } else { node.next = this.head; node.prior = head.prior; head.prior.next = node; this.head.prior = node; this.head = node; //头指针指向新插入的节点 } }
- 从链表尾插入
public void addEnd(int data) { //创建一个新节点 Node node = new Node(data); //若头节点为空 if(this.head == null) { this.head = node; } else { node.prior = head.prior; node.next = head; node.prior.next = node; head.prior = node; } }
- 从链表中间位置插入
public void addMiddle(int position, int data) { //创建一个新节点 Node node = new Node(data); //若头节点为空 if(this.head == null) { this.head = node; } else { Node pointer = this.head; for(int i=1; i<position; i++) { pointer = pointer.next; //定位到插入位置的前驱节点 } //注意顺序很重要! node.prior = pointer; node.next = pointer.next; pointer.next.prior = node; pointer.next = node; } }
- 删除双向链表中第一个某个数值的节点
public void remove(int key) { //判断是否为空 if(this.head == null) { System.out.println("这个双向链表是空的。"); return; } //创建一个新节点 Node pointer = this.head; //定位待删除节点 while(pointer.data != key) { pointer = pointer.next; if(pointer == this.head) { System.out.println("未找到值为" + key + "的节点。"); return; } } //删除节点为头节点的情况 if(pointer == this.head) { if(pointer.next == this.head) { //双向链表只有头节点的情况 this.head = null; System.out.println("值为" + pointer.data + "的节点已删除。"); return; } this.head = pointer.next; //先将头指针指向下一节点 pointer.next.prior = pointer.prior; pointer.prior.next = pointer.next; System.out.println("值为" + pointer.data + "的节点已删除。"); return; } //普通情况 pointer.next.prior = pointer.prior; pointer.prior.next = pointer.next; System.out.println("值为" + pointer.data + "的节点已删除。"); }
- 删除双向链表中所有某个数值的节点
public void removeAll(int key) { //双向链表为空的情况 if(this.head == null) { System.out.println("这个双向链表是空的。"); return; } Node pointer = this.head; //循环不包含最后一个节点 while(pointer.next != this.head) { if(pointer.data == key) { if(pointer == this.head) //判断该节点是否为头节点 this.head = this.head.next; pointer.prior.next = pointer.next; pointer.next.prior = pointer.prior; } pointer = pointer.next; } //最后一个节点单独考虑 if(pointer.data == key) { pointer.prior.next = pointer.next; pointer.next.prior = pointer.prior; } System.out.println("所有值为" + key + "节点均已删除。") ; }
完整代码如下:
//双向链表节点结构
public class Node {
int data;
Node prior;
Node next;
public Node(int data) {
this.data = data;
prior = this;
next = this;
}
}
public class MakeList {
public static void main(String[] args) {
ListOperation list = new ListOperation();
list.addFirst(12);
list.addEnd(13);
list.addMiddle(2, 14);
list.showList();
list.removeAll(12);
list.showList();
}
}
public class ListOperation {
private Node head; //头节点
public void showList() {
System.out.println("开始检索双向列表......");
if(this.head == null) {
System.out.println("目前双向链表为空。");
} else {
Node pointer = this.head;
do {
System.out.print(pointer.data + " ");
pointer = pointer.next;
} while(pointer != this.head);
System.out.println("\n检索完成。");
}
}
//头插法
public void addFirst(int data) {
//创建一个新节点
Node node = new Node(data);
//若头节点为空
if(this.head == null) {
this.head = node;
} else {
node.next = this.head;
node.prior = head.prior;
head.prior.next = node;
this.head.prior = node;
this.head = node; //头指针指向新插入的节点
}
}
//尾插法
public void addEnd(int data) {
//创建一个新节点
Node node = new Node(data);
//若头节点为空
if(this.head == null) {
this.head = node;
} else {
node.prior = head.prior;
node.next = head;
node.prior.next = node;
head.prior = node;
}
}
//从中间位置插入
public void addMiddle(int position, int data) {
//创建一个新节点
Node node = new Node(data);
//若头节点为空
if(this.head == null) {
this.head = node;
} else {
Node pointer = this.head;
for(int i=1; i<position; i++) {
pointer = pointer.next; //定位到插入位置的前驱节点
}
//注意顺序很重要!
node.prior = pointer;
node.next = pointer.next;
pointer.next.prior = node;
pointer.next = node;
}
}
//删除第一次出现值为key的节点
public void remove(int key) {
//判断是否为空
if(this.head == null) {
System.out.println("这个双向链表是空的。");
return;
}
//创建一个新节点
Node pointer = this.head;
//定位待删除节点
while(pointer.data != key) {
pointer = pointer.next;
if(pointer == this.head) {
System.out.println("未找到值为" + key + "的节点。");
return;
}
}
//删除节点为头节点的情况
if(pointer == this.head) {
if(pointer.next == this.head) {
//双向链表只有头节点的情况
this.head = null;
System.out.println("值为" + pointer.data + "的节点已删除。");
return;
}
this.head = pointer.next; //先将头指针指向下一节点
pointer.next.prior = pointer.prior;
pointer.prior.next = pointer.next;
System.out.println("值为" + pointer.data + "的节点已删除。");
return;
}
//普通情况
pointer.next.prior = pointer.prior;
pointer.prior.next = pointer.next;
System.out.println("值为" + pointer.data + "的节点已删除。");
}
//删除所有值为key的节点
public void removeAll(int key) {
//双向链表为空的情况
if(this.head == null) {
System.out.println("这个双向链表是空的。");
return;
}
Node pointer = this.head;
//循环不包含最后一个节点
while(pointer.next != this.head) {
if(pointer.data == key) {
if(pointer == this.head)
//判断该节点是否为头节点
this.head = this.head.next;
pointer.prior.next = pointer.next;
pointer.next.prior = pointer.prior;
}
pointer = pointer.next;
}
//最后一个节点单独考虑
if(pointer.data == key) {
pointer.prior.next = pointer.next;
pointer.next.prior = pointer.prior;
}
System.out.println("所有值为" + key + "节点均已删除。") ;
}
}