Java数据结构(4)链表——环形链表
1.环形链表简介
如图所示:环形链表和单向链表的唯一区别就是尾节点指向头节点。
关于单向链表的相关内容可查看:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HQoBABqo-1572091678783)(D:\markdowm笔记软件\images\java数据结构\环形链表.png)]
以下代码中使用的节点类代码如下:
/**
* 代码实现环形链表——节点类
*/
class Node {
int bookId;//书籍序列号
String bookName;//书籍名称
Node next;//节点
//节点的构造方法:初始化数据域,将节点指向空
public Node(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
this.next = null;
}
}
2.环形链表的打印
//打印链表(从链表头打印到链表尾) 循环结束条件不同
public void printLinkedList() {
Node current = first;//定义一个暂时的节点,赋值为头节点
while (current != last) {
System.out.println(current.bookId + current.bookName);
current = current.next;
}
System.out.println(current.bookId + current.bookName);
}
3.环形链表节点插入
/**
* 环形链表插入节点
*
* @param needInsertNode 新插入节点 已初始化数据域与节点属性
*/
public void insertNode(Node needInsertNode) {
Node tempNode;
Node newNode;
if (this.isEmpty()) {//原环形链表空
first = needInsertNode;//头尾节点为新插入节点
last = needInsertNode;
last.next = first;//尾节点指向头节点
} else if (needInsertNode.next == null) {//next为空 插在表尾
last.next = needInsertNode;//原尾节点的下一节点赋值为新插入节点
last = needInsertNode;//重新设置头节点
last.next = first;//重新设置尾节点指向头节点
} else if (needInsertNode.next == first) {//插入链表头
first=needInsertNode;//设置新头节点
last.next=first;//重新设置尾节点指向头节点
} else {//插入链表中间 寻找新插入节点的next节点的前一个节点
System.out.println("插中间");
newNode = first;
while (newNode.next != needInsertNode.next) {//遍历链表至:newNode为新插入节点的next节点
newNode = newNode.next;
}
newNode.next=needInsertNode;
}
}
//插入节点测试
public static void main(String[] args) {
CircleLinkedList circleLinkedList = new CircleLinkedList();
Node node1 = new Node(12086, "《 数据结构 》");
Node node2 = new Node(18002, "《 计算机网络 》");
Node node3 = new Node(19121, "《 数据库概论 》");
Node node4 = new Node(39991, "《 设计模式 》");
Node node5 = new Node(34171, "《 Springboot 》");
//空表插
System.out.println("空表插");
circleLinkedList.insertNode(node1);
circleLinkedList.printLinkedList();
//插尾
System.out.println("插尾");
circleLinkedList.insertNode(node2);
circleLinkedList.insertNode(node3);
circleLinkedList.printLinkedList();
//插头
System.out.println("插头");
System.out.println("原头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
node4.next = circleLinkedList.first;
circleLinkedList.insertNode(node4);
System.out.println("新头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
circleLinkedList.printLinkedList();
//插中间
System.out.println("插中间");
Node node=circleLinkedList.last;
node5.next=node;
System.out.println("插在"+node.bookName+"之前");
circleLinkedList.insertNode(node5);
System.out.println("插入测试后");
circleLinkedList.printLinkedList();
//circleLinkedList.deleteNode();
}
}
测试结果
空表插
12086《 数据结构 》
插尾
12086《 数据结构 》
18002《 计算机网络 》
19121《 数据库概论 》
插头
原头:12086《 数据结构 》
新头:39991《 设计模式 》
39991《 设计模式 》
12086《 数据结构 》
18002《 计算机网络 》
19121《 数据库概论 》
插中间
插在《 数据库概论 》之前
插中间
插入测试后
39991《 设计模式 》
12086《 数据结构 》
18002《 计算机网络 》
34171《 Springboot 》
19121《 数据库概论 》
4. 环形链表节点删除
/**
* 环形链表 删除节点
*
* @param needDeleteNode 需删除节点 已初始化数据域与节点属性
*/
public void deleteNode(Node needDeleteNode) {
Node newNode;
Node tempNode;
if (this.isEmpty()) {
System.out.println("环形链表已空");
return;
} else if (first.bookId == needDeleteNode.bookId) {//删头
first = first.next;
if (first == null) {
System.out.println("删除的是头节点,环形链表已空");
return;
}
} else if (last.bookId == needDeleteNode.bookId) {//删尾
newNode = first;//用于保存尾节点前一节点
//遍历环形链表至尾节点前一节点 并保存至newNode
while (newNode.next != last) newNode = newNode.next;
newNode.next = null;//将原尾节点前一节点的next置空
last = newNode;//重新设置新的尾节点
last.next = first;//重新设置尾节点指向头节点
}else {//删中间
newNode = first;//用于遍历至需要删除节点
tempNode = first;//用于保存newNode的前一节点,即需要删除节点的前一节点
//遍历至需要删除节点
while (newNode.bookId!=needDeleteNode.bookId){
tempNode=newNode;
newNode=newNode.next;
}
//重新设置需要删除节点的前一节点的next属性 跳过needDeleteNode 指向它的后一个节点
tempNode.next=needDeleteNode.next;
}
}
//插入与删除测试
public static void main(String[] args) {
CircleLinkedList circleLinkedList = new CircleLinkedList();
Node node1 = new Node(12086, "《 数据结构 》");
Node node2 = new Node(18002, "《 计算机网络 》");
Node node3 = new Node(19121, "《 数据库概论 》");
Node node4 = new Node(39991, "《 设计模式 》");
Node node5 = new Node(34171, "《 Springboot 》");
//空表插
System.out.println("空表插");
circleLinkedList.insertNode(node1);
circleLinkedList.printLinkedList();
//插尾
System.out.println("插尾");
circleLinkedList.insertNode(node2);
circleLinkedList.insertNode(node3);
circleLinkedList.printLinkedList();
//插头
System.out.println("插头");
System.out.println("原头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
node4.next = circleLinkedList.first;
circleLinkedList.insertNode(node4);
System.out.println("新头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
circleLinkedList.printLinkedList();
//插中间
System.out.println("插中间");
Node node = circleLinkedList.last;
node5.next = node;
System.out.println("插在" + node.bookName + "之前");
circleLinkedList.insertNode(node5);
System.out.println("插入测试后");
circleLinkedList.printLinkedList();
System.out.println();
System.out.println("删头");
circleLinkedList.deleteNode(circleLinkedList.first);
circleLinkedList.printLinkedList();
System.out.println("删尾");
circleLinkedList.deleteNode(circleLinkedList.last);
circleLinkedList.printLinkedList();
System.out.println("删中间");
circleLinkedList.deleteNode(circleLinkedList.first.next);
circleLinkedList.printLinkedList();
//circleLinkedList.deleteNode();
}
测试代码是接着上述插入的结果来的,测试结果如下:
插入测试后
39991《 设计模式 》
12086《 数据结构 》
18002《 计算机网络 》
34171《 Springboot 》
19121《 数据库概论 》
删头
12086《 数据结构 》
18002《 计算机网络 》
34171《 Springboot 》
19121《 数据库概论 》
删尾
12086《 数据结构 》
18002《 计算机网络 》
34171《 Springboot 》
删中间
12086《 数据结构 》
34171《 Springboot 》
5.完整代码
package DataStructure.LinkedList;
/**
* 代码实现环形链表——节点类
*/
class Node {
int bookId;//书籍序列号
String bookName;//书籍名称
Node next;//节点
//节点的构造方法:初始化数据域,将节点指向空
public Node(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
this.next = null;
}
}
/**
* 代码实现环形链表——主类
*/
public class CircleLinkedList {
private Node first;
private Node last;
//判空
public boolean isEmpty() {
return first == null;//布尔表达式,头节点空返回true,反之返回false
}
//打印链表(从链表头打印到链表尾) 循环结束条件不同
public void printLinkedList() {
Node current = first;//定义一个暂时的节点,赋值为头节点
while (current != last) {
System.out.println(current.bookId + current.bookName);
current = current.next;
}
System.out.println(current.bookId + current.bookName);
}
/**
* 环形链表插入节点
*
* @param needInsertNode 新插入节点 已初始化数据域与节点属性
*/
public void insertNode(Node needInsertNode) {
Node tempNode;
Node newNode;
if (this.isEmpty()) {//原环形链表空
first = needInsertNode;//头尾节点为新插入节点
last = needInsertNode;
last.next = first;//尾节点指向头节点
} else if (needInsertNode.next == null) {//next为空 插在表尾
last.next = needInsertNode;//原尾节点的下一节点赋值为新插入节点
last = needInsertNode;//重新设置头节点
last.next = first;//重新设置尾节点指向头节点
} else if (needInsertNode.next == first) {//插入链表头
first = needInsertNode;//设置新头节点
last.next = first;//重新设置尾节点指向头节点
} else {//插入链表中间 寻找新插入节点的next节点的前一个节点
System.out.println("插中间");
newNode = first;
//遍历链表至:newNode为新插入节点的next节点
while (newNode.next != needInsertNode.next) newNode = newNode.next;
newNode.next = needInsertNode;
}
}
/**
* 环形链表 删除节点
*
* @param needDeleteNode 需删除节点 已初始化数据域与节点属性
*/
public void deleteNode(Node needDeleteNode) {
Node newNode;
Node tempNode;
if (this.isEmpty()) {
System.out.println("环形链表已空");
return;
} else if (first.bookId == needDeleteNode.bookId) {//删头
first = first.next;
if (first == null) {
System.out.println("删除的是头节点,环形链表已空");
return;
}
} else if (last.bookId == needDeleteNode.bookId) {//删尾
newNode = first;//用于保存尾节点前一节点
//遍历环形链表至尾节点前一节点 并保存至newNode
while (newNode.next != last) newNode = newNode.next;
newNode.next = null;//将原尾节点前一节点的next置空
last = newNode;//重新设置新的尾节点
last.next = first;//重新设置尾节点指向头节点
}else {//删中间
newNode = first;//用于遍历至需要删除节点
tempNode = first;//用于保存newNode的前一节点,即需要删除节点的前一节点
//遍历至需要删除节点
while (newNode.bookId!=needDeleteNode.bookId){
tempNode=newNode;
newNode=newNode.next;
}
//重新设置需要删除节点的前一节点的next属性 跳过needDeleteNode 指向它的后一个节点
tempNode.next=needDeleteNode.next;
}
}
//插入节点与删除节点的测试
public static void main(String[] args) {
CircleLinkedList circleLinkedList = new CircleLinkedList();
Node node1 = new Node(12086, "《 数据结构 》");
Node node2 = new Node(18002, "《 计算机网络 》");
Node node3 = new Node(19121, "《 数据库概论 》");
Node node4 = new Node(39991, "《 设计模式 》");
Node node5 = new Node(34171, "《 Springboot 》");
//空表插
System.out.println("空表插");
circleLinkedList.insertNode(node1);
circleLinkedList.printLinkedList();
//插尾
System.out.println("插尾");
circleLinkedList.insertNode(node2);
circleLinkedList.insertNode(node3);
circleLinkedList.printLinkedList();
//插头
System.out.println("插头");
System.out.println("原头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
node4.next = circleLinkedList.first;
circleLinkedList.insertNode(node4);
System.out.println("新头:" + circleLinkedList.first.bookId + circleLinkedList.first.bookName);
circleLinkedList.printLinkedList();
//插中间
System.out.println("插中间");
Node node = circleLinkedList.last;
node5.next = node;
System.out.println("插在" + node.bookName + "之前");
circleLinkedList.insertNode(node5);
System.out.println("插入测试后");
circleLinkedList.printLinkedList();
System.out.println();
System.out.println("删头");
circleLinkedList.deleteNode(circleLinkedList.first);
circleLinkedList.printLinkedList();
System.out.println("删尾");
circleLinkedList.deleteNode(circleLinkedList.last);
circleLinkedList.printLinkedList();
System.out.println("删中间");
circleLinkedList.deleteNode(circleLinkedList.first.next);
circleLinkedList.printLinkedList();
}
}
6.环形链表的更多
关于环形链表的常见问题,将在之后的文章中提及,比如 环形链表的串联,利用环形链表解决约瑟夫问题等