1. 应用场景
2. 思路
- 节点结构:
- 数据域(Data):存储 当前节点 的 数据
- 地址域1(Next):指向 下一个节点 的 地址
- 环形链表结构:
- 头节点:储存环形链表的第一个节点
- 储存方式:尾部节点指向头节点
- 不一定 是连续存储
- 添加节点:本文章按照直接添加到尾节点的方式
3. 数据结构(类结构):
【节点 SingleNode】
(1)成员变量(Field)
- data: int,节点所储存的数据
- nextNode: SingleNode,所指向的下一个节点
private int data;
private SingleNode nextNode;
(2)初始化 / 构造器(Constructor)
- 参数传入节点所要储存的数据
- 初始化节点数据
public SingleNode(int data) {
this.data = data;
}
(3)方法(Methods)
- 两个成员变量的getter和setter
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public SingleNode getNextNode() {
return nextNode;
}
public void setNextNode(SingleNode nextNode) {
this.nextNode = nextNode;
}
- toString方法
@Override
public String toString() {
return "SingleNode{" +
"data=" + data +
'}';
}
【单向环形链表 CircleSingleLinkedList】
(1)成员变量(Field)
- firstNode: 头节点,指向链表的第一个节点
private SingleNode firstNode;
(2)初始化 / 构造器(Constructor)
- 默认构造器
(3)方法(Methods)
- 批量添加新节点
initializeForJoseph(int) -> void
/**
* 添加 number 个节点到环形链表, 编号为 1 ~ number(为约瑟夫问题作准备)
* @param number - 待添加的节点数
*/
public void initializeForJoseph(int number) {
// 若链表不为空,将其变为空
if (this.firstNode != null) {
this.firstNode = null;
}
// 循环创造number个新节点,数值为 1~number,逐个加入环形链表
SingleNodePractice currentNode = null;
for (int i = 1; i <= number; i++) {
SingleNodePractice newNode = new SingleNodePractice(i);
if (this.firstNode == null) {
this.firstNode = newNode;
} else {
currentNode.setNextNode(newNode);
}
currentNode = newNode;
}
currentNode.setNextNode(this.firstNode);
}
- 查找某节点是否存在
isNodeExist(SingleNode) -> boolean
/**
* 查找所给节点是否存在于环形链表
* @param node - 待查找节点
* @return - boolean,是否找到节点
*/
public boolean isNodeExist(SingleNode node) {
// 1. 若链表为空,抛出异常
if (this.firstNode == null) {
throw new RuntimeException("empty!");
}
// 2. 遍历查找所给节点,若存在则found为true退出循环
// 2.1 设置boolean变量found
boolean found = false;
// 2.2 设置当前节点变量
SingleNode currentNode = this.firstNode;
// 2.3 遍历,逐个判断所给节点值和链表中的节点值,相等时找到,设found为true,退出循环
while (true) {
// (1) 若相等,找到,found为true,退出循环
if (currentNode.getData() == node.getData()) {
found = true;
break;
}
// (2) 若下一节点为首节点,到末尾,退出循环
if (currentNode.getNextNode() == this.firstNode) {
break;
}
// (3) 移动当前节点到下一节点
currentNode = currentNode.getNextNode();
}
// 3. 返回found值
return found;
}
- 获取全部节点的计数
countNodes() -> int
/**
* 统计环形链表的有效节点数
* @return int - 节点数
*/
public int countNodes() {
// 设置辅助int变量count
int count = 0;
// 若链表不为空,遍历并统计有效节点数
if (this.firstNode != null) {
// 设置辅助节点变量,储存当前节点
SingleNode currentNode = this.firstNode;
// 遍历整个链表,统计节点数
while (true) {
// count加1
count++;
// 若当前节点的next为首节点,到达末尾,结束循环
if (currentNode.getNextNode() == this.firstNode) {
break;
}
// 移动当前节点到下一位
currentNode = currentNode.getNextNode();
}
}
// 返回count
return count;
}
- 打印全部节点的数据
displayAllNodes() -> void
/**
* 打印全部节点值
*/
public void displayAllNodes() {
// 1. 若首节点为null,则链表为空,抛出异常
if (this.firstNode == null) {
throw new RuntimeException("The list is empty!");
}
// 2. 遍历,打印每个节点值
// 2.1 设置current节点
SingleNode currentNode = this.firstNode;
// 2.2 遍历,打印当前节点值,到末尾停止
while (true) {
// (1) 打印当前节点值
System.out.println(currentNode.toString());
// (2) 若当前节点值的下一节点为首节点,则到达末尾,结束循环
if (currentNode.getNextNode() == this.firstNode){
break;
}
// (3) 移动当前节点到下一节点
currentNode = currentNode.getNextNode();
}
}
4. 完整实现
public class CircleSingleLinkedList {
private SingleNode firstNode;
/**
* 添加 number 个节点到环形链表, 编号为 1 ~ number(为约瑟夫问题作准备)
* @param number - 待添加的节点数
*/
public void initializeForJoseph(int number) {
// 若链表不为空,将其变为空
if (this.firstNode != null) {
this.firstNode = null;
}
// 循环创造number个新节点,数值为 1~number,逐个加入环形链表
SingleNodePractice currentNode = null;
for (int i = 1; i <= number; i++) {
SingleNodePractice newNode = new SingleNodePractice(i);
if (this.firstNode == null) {
this.firstNode = newNode;
} else {
currentNode.setNextNode(newNode);
}
currentNode = newNode;
}
currentNode.setNextNode(this.firstNode);
}
/**
* 打印全部节点值
*/
public void displayAllNodes() {
// 1. 若首节点为null,则链表为空,抛出异常
if (this.firstNode == null) {
throw new RuntimeException("The list is empty!");
}
// 2. 遍历,打印每个节点值
// 2.1 设置current节点
SingleNode currentNode = this.firstNode;
// 2.2 遍历,打印当前节点值,到末尾停止
while (true) {
// (1) 打印当前节点值
System.out.println(currentNode.toString());
// (2) 若当前节点值的下一节点为首节点,则到达末尾,结束循环
if (currentNode.getNextNode() == this.firstNode){
break;
}
// (3) 移动当前节点到下一节点
currentNode = currentNode.getNextNode();
}
}
/**
* 查找所给节点是否存在于环形链表
* @param node - 待查找节点
* @return - boolean,是否找到节点
*/
public boolean isNodeExist(SingleNode node) {
// 1. 若链表为空,抛出异常
if (this.firstNode == null) {
throw new RuntimeException("empty!");
}
// 2. 遍历查找所给节点,若存在则found为true退出循环
// 2.1 设置boolean变量found
boolean found = false;
// 2.2 设置当前节点变量
SingleNode currentNode = this.firstNode;
// 2.3 遍历,逐个判断所给节点值和链表中的节点值,相等时找到,设found为true,退出循环
while (true) {
// (1) 若相等,找到,found为true,退出循环
if (currentNode.getData() == node.getData()) {
found = true;
break;
}
// (2) 若下一节点为首节点,到末尾,退出循环
if (currentNode.getNextNode() == this.firstNode) {
break;
}
// (3) 移动当前节点到下一节点
currentNode = currentNode.getNextNode();
}
// 3. 返回found值
return found;
}
/**
* 统计环形链表的有效节点数
* @return int - 节点数
*/
public int countNodes() {
// 设置辅助int变量count
int count = 0;
// 若链表不为空,遍历并统计有效节点数
if (this.firstNode != null) {
// 设置辅助节点变量,储存当前节点
SingleNode currentNode = this.firstNode;
// 遍历整个链表,统计节点数
while (true) {
// count加1
count++;
// 若当前节点的next为首节点,到达末尾,结束循环
if (currentNode.getNextNode() == this.firstNode) {
break;
}
// 移动当前节点到下一位
currentNode = currentNode.getNextNode();
}
}
// 返回count
return count;
}
public SingleNode getFirstNode() {
return firstNode;
}
public void setFirstNode(SingleNode firstNode) {
this.firstNode = firstNode;
}
}
class SingleNode {
private int data;
private SingleNode nextNode;
public SingleNode(int data) {
this.data = data;
}
@Override
public String toString() {
return "SingleNode{" +
"data=" + data +
'}';
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public SingleNode getNextNode() {
return nextNode;
}
public void setNextNode(SingleNode nextNode) {
this.nextNode = nextNode;
}
}