一、单项环形链表介绍
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
链表分为带头节点的链表和没有头节点的链表,根据实际的需求确定
本文将使用没有头节点的链表
二、链表的应用实例
解决约瑟夫(Josephus)问题
问题:N个人围成一圈,从第一个开始报数,第M个将被带走,最后剩下一个为幸运儿。例如N=6,M=5,被带走的顺序是:5,4,6,2,3,1。
提示:用一个不带头结点的循环链表来处理Josephus问题:
1.先构建一个有N个节点的单向链表。
2.从第一个节点开始计数,数M个节点,第M个节点被移除。
3.从第M+1个节点处开始从1计数,直到最后一个节点被移除。
三、代码实现
具体解释再代码注释里
public class CircleSingleLinkedListDemo {
public static void main(String[] args) {
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
//添加20个节点
circleSingleLinkedList.add(6);
//显示节点
circleSingleLinkedList.show();
//进行排除操作 传入数几个数
circleSingleLinkedList.tackOut(5);
}
}
class CircleSingleLinkedList{
//创建第一个节点first
JosephusNode first = null;
//总节点数
int nodeCount = 0;
//创建指针(辅助变量)
JosephusNode temp = null;
// 添加节点,构成一个环形链表
public void add(int numbers){
//对numbers进行校验
if(numbers<1){
System.out.println("请输入正确节点数");
return;
}
nodeCount = numbers;
//使用for循环创建节点
for (int i = 1;i <= numbers;i++){
//根据编号创建节点
JosephusNode node = new JosephusNode(i);
//判断是否是第一个节点,若是第一个节点则next指向自己,否则正常添加节点
if(i == 1){
//添加节点--头节点
//将初始化链表的第一个节点指向刚创建的节点
first = node;
//将第一个节点的next指向自己
first.next = first;
//将指针(辅助变量)指向第一个节点
temp = first;
}else{
//添加节点--非头节点
//将指针(辅助变量)的next指向当前节点
temp.next = node;
//将当前节点的next指向第一个节点
node.next = first;
//将指针(辅助变量)指向当前节点
temp = node;
}
}
}
/**
* 显示当前链表中的所有节点
*/
public void show(){
if(first == null){
System.out.println("该链表暂无节点");
return;
}
temp = first;
//遍历节点
while (true){
//将节点信息进行输出
System.out.println("当前节点的编号为"+temp.id);
//遍历完成
if(temp.next==first){
break;
}
temp = temp.next;
}
}
/**
*
* @param count 每次数几个数
*/
public void tackOut(int count){
//校验,只能输入比0大的数
if(count<0){
System.out.println("请输入正确数字!");
return;
}
//让temp指针指向第一个节点
temp = first;
//临时指针,用于记录要排除节点的前一个节点
JosephusNode lastNode = null;
//进行输出节点
while(true){
//temp为要删除的节点的指针
// 说明:当temp.next 指向 自己的时候说明只剩下最后一个节点,直接退出
if(temp.next == temp){
break;
}
//用于计数,由于是从第一个节点开始数,所以要用count-1,避免第一个节点数两次
for(int i = 0; i < count-1; i++){
//lastNode用于记录要排除节点的前一个节点
lastNode = temp;
//temp为要删除的节点
temp = temp.next;
}
System.out.println("排除节点的编号为:"+temp.id);
//进行节点排除
lastNode.next = temp.next;
//要删除的节点 指向 删除后的节点的下一个节点
temp = lastNode.next;
}
System.out.println("最后一个节点编号为:"+temp.id);
}
}
/**
* 节点
*/
class JosephusNode{
public int id;
public JosephusNode next;
public JosephusNode(int id){
this.id = id;
}
}