简介:在单向链表的基础上,实现环形单链表(带表头)
环形链表是单向链表的优化,可以用于解决Josephus问题。
这里创建三个类,分别是节点数据类NodeData、节点类Node、环形链表类CircularLinkedList,前面的文章已做过单链表的分析,故不再分析,直接给出代码,详见:Java数据结构之单链表——day03
1.NodeData类
package 环形链表;
import java.util.Objects;
/**
* @Classname NodeData
* @Description TODO
* @Date 2022/5/8 15:06
* @Created by jiawen
*/
public class NodeData {
public int number;
public NodeData() {
}
public NodeData(int number) {
this.number = number;
}
}
2.Node类
package 环形链表;
/**
* @Classname Node
* @Description TODO
* @Date 2022/5/8 15:07
* @Created by jiawen
*/
public class Node {
public NodeData data;
public Node nextNode;
public Node(NodeData data) {
this.data = data;
}
public Node(NodeData data, Node nextNode) {
this.data = data;
this.nextNode = nextNode;
}
@Override
public String toString() {
return "Node{" +
"data=" + this.data.number +
", nextData=" + this.nextNode.data.number +
'}';
}
}
3. CircularLinkedList类
提供增、删、改、查、遍历、获取节点数等功能,如果想要链表中的数据可重复,请自行修改 NodeData的equals方法
package 环形链表;
/**
* @Classname CircularLinkedList
* @Description TODO
* @Date 2022/5/8 15:09
* @Created by jiawen
*/
public class CircularLinkedList {
private Node initialNode = new Node(new NodeData(-1), null);//头节点
public CircularLinkedList() {
}
public int getCount() {
int count = 1;
if (initialNode.nextNode == null) {
System.out.println("Please insert your data,otherwise the count of the list will be 0 !");
return 0;
}
Node temp = initialNode.nextNode;
Node firstNode = initialNode.nextNode;
while (true) {
if (temp.nextNode.equals(firstNode)) {
break;
} else {
temp = temp.nextNode;
count++;
}
}
return count;
}
public void addNode(NodeData nodeData) {
Node toBeAded = new Node(nodeData);
if (initialNode.nextNode == null) {
initialNode.nextNode = toBeAded;
toBeAded.nextNode = toBeAded;
System.out.println("Insert initial data success!");
return;
}
Node firstNode = initialNode.nextNode;
Node finalNode = initialNode.nextNode;
while (!finalNode.nextNode.equals(firstNode)) {
finalNode = finalNode.nextNode;
}
finalNode.nextNode = toBeAded;
toBeAded.nextNode = firstNode;
}
public void listAll() {
if (initialNode.nextNode == null) {
System.out.println("There is No data to list");
return;
}
Node temp = initialNode.nextNode;
Node first = initialNode.nextNode;
while (!temp.nextNode.equals(first)) {
System.out.println(temp);
temp = temp.nextNode;
}
System.out.println(temp);//用于输出最后一个数据,没有的话就不会输出最后一个
return;
}
public void dropNode(int number) {
if (initialNode.nextNode == null) {
System.out.println("There is no data to delete here!");
return;
}//首先判断list是不是空的,list为空则无法删除
Node finalNode = initialNode.nextNode;//定义一个firstNode节点,在删除第一个数据时使用;
Node temp = initialNode.nextNode;//定义一个指针temp,在要删除的数据不是第一个时使用;
Node firstNode = initialNode.nextNode;//定义一个finalNode节点,在删除第一个数据时使用;
boolean flag = true;//一个标记,在找到数据后取反,主要是用于在没有找到对应数据时跳出循环
//该while循环一旦跳出,则证明finalNode指针已指向最后一个数据
while (true) {
if (!(finalNode.nextNode.equals(firstNode))) {
finalNode = finalNode.nextNode;
} else {//注意有else和没有else的区别
break;
}
}
while (true) {
if (initialNode.nextNode.data.number == number) {//这个if主要用于删除第一个数据,第一个数据比较特殊,需要更改头节点的连接
finalNode.nextNode = firstNode.nextNode;//最后一个节点的next指向首个数据(也就是待删除数据)的下一个节点
initialNode.nextNode = firstNode.nextNode;//头节点的next需要指向新的firstNode
return;
} else {//如果要删除的数据不在第一个,则使用如下方式,注意,删除数据时temp指针必须在要指向待删除节点的上个节点,所以,
// 由于第一个节点已经有上面的方法删除了,这里就没必要一开始让它指向头节点了
while (flag) {
if (temp.nextNode.equals(firstNode)) {
break;//主要用于没找到时跳出while循环
}
if (temp.nextNode.data.number == number) {
flag = !flag;//找到则取反
break;
} else {
temp = temp.nextNode;//没找到则指针后移
}
}//这个子while循环结束则意味着temp指针已经指向待删除数据的上一个节点了
if (flag) {
System.out.println("No data with value equal to " + number + " was found!");//flag为true则表示不存在这个数据,结束即可
return;
} else {
temp.nextNode = temp.nextNode.nextNode;//temp指针指向下一个节点(也即是待删除结点)的下一个
return;
}
}
}
}
public void updateDate(int oldNumber, int newNumber) {
Node temp = initialNode.nextNode;
Node firstNode = initialNode.nextNode;
boolean flag = true;
while (true) {
if (temp.nextNode.equals(firstNode) && temp.data.number != oldNumber) {
//这里要特别注意,不能仅仅以temp的下一个元素等于first就判断,这样的话有bug
//这个bug就是:当要修改的元素刚好在最后一个时,temp指针也是在最后的,此时应该修改完数据再break,而不是直接break
break;
}
if (temp.data.number == oldNumber) {
flag = !flag;
break;
} else {
temp = temp.nextNode;
}
}
if (flag) {
System.out.println("No data with value equal to " + oldNumber + " was found!");//flag为true则表示不存在这个数据,结束即可
} else {
temp.data.number = newNumber;
}
}
public void searchValue(int value) {
Node temp = initialNode.nextNode;
Node firstNode = initialNode.nextNode;
boolean flag = true;
while (true) {
if (temp.nextNode.equals(firstNode)) {
if (temp.data.number == value) {
System.out.println(temp);
break;
} else {
flag = !flag;
break;
}
} else {
if (temp.data.number == value) {
System.out.println(temp);
break;
} else {
temp = temp.nextNode;
}
}
}
if (!flag) {
System.out.println("No data with value equal to " + value + " was found!");//flag为true则表示不存在这个数据,结束即可
}
}
}
4. 测试与调试(自行编写代码测试)
package 环形链表;
import org.junit.Test;
/**
* @Classname Demo
* @Description TODO
* @Date 2022/5/8 16:08
* @Created by jiawe
*/
public class Demo {
public static void main(String[] args) {
CircularLinkedList circularLinkedList = new CircularLinkedList();
NodeData nodeData1 = new NodeData(1);
NodeData nodeData2 = new NodeData(2);
NodeData nodeData3 = new NodeData(3);
NodeData nodeData4 = new NodeData(4);
NodeData nodeData5 = new NodeData(5);
NodeData nodeData6 = new NodeData(5);
// NodeData nodeData3 = new NodeData(13);
circularLinkedList.addNode(nodeData1);
circularLinkedList.addNode(nodeData2);
circularLinkedList.addNode(nodeData3);
circularLinkedList.addNode(nodeData4);
circularLinkedList.addNode(nodeData5);
// circularLinkedList.dropNode(5);
// circularLinkedList.dropNode(2);
// circularLinkedList.updateDate(9, 100);
System.out.println(circularLinkedList.getCount());
// circularLinkedList.listAll();
// circularLinkedList.searchValue(4);
circularLinkedList.searchValue(1);
circularLinkedList.searchValue(3);
circularLinkedList.searchValue(5);
circularLinkedList.searchValue(9);
}
// @Test
// public void test1(){
//
// CircularLinkedList circularLinkedList = new CircularLinkedList();
// System.out.println(circularLinkedList.initialNode.nextNode);
// }
}