单向循环链表节点
public class Node
{
public int id;
public Node next;
public Node(int id)
{
this.id = id;
}
}
单向循环链表对象类
public class SingleLoopLinkList
{
//先默认创建第一个节点,这个节点不是头结点,是有效节点,默认数据是要修改的
Node first = new Node(-1);
public SingleLoopLinkList()
{
//初始化的时候默认把第一个节点环起来,环形链表嘛,一个节点也要环起来
first.next = first;
}
//显示节点数据
public void Show()
{
Node temp = first;
while (true)
{
Console.WriteLine(temp.id);
if(temp.next==first)
{
break;
}
temp = temp.next;
}
}
}
添加节点
在SingleLoopLinkList
类里面的方法
//添加节点
public void Add(Node node)
{
if (first.id == -1)
{
//如果第一个节点的数据是默认数据,则这次的添加就是第一次添加数据,就把数据赋值给first
first.id = node.id;
}
else//到了这一步,就说明第一个first节点已经有了真实数据
{
//当前指针,从first的下一个开始,因为是环形的,不用担心空指针
Node cur = first.next;
while (true)
{
if (cur.next == first)//如果当前节点的下一个就是first节点,说明当前节点就是最后一个节点
{
node.next = first;
cur.next = node;
break;
}
cur = cur.next;
}
}
}
Josephu(约瑟夫)问题
描述
设编号1,2,3,…..,n的n个人围坐在一圈,约定编号为k(1<=k<=n)的人开始从1开始报数,数到m的那个人出列,他的下一位又从1开始报数,数到m的那个人又出列,以此类推,直到所有人出列为止,由此产生一个出队编号的序列。
思路
代码
在SingleLoopLinkList
类里面的方法
在调用Josephu之前,先添加节点
public void Josephu(int k, int m)
{
Node temp = first;//辅助指针
//1.先把temp指向first之前的一个节点,因为first是第一个节点,所以遍历这个链表,找到最后一个节点,就是first前一个节点了
while (true)
{
if (temp.next == first)//说明temp就是最后一个了
{
break;
}
temp = temp.next;
}
//2.把temp和first移动k-1次,因为要从第k个开始数,first移动k-1此后,first就是第k个
for(int i = 0; i < k-1; i++)
{
first = first.next;
temp = temp.next;
}
//3.循环出圈(直到圈中只有一个节点):first和temp都同时移动m-1个,自身报数1,移动m-1就是报数m,然后出圈
while (true)
{
if (temp == first)//说明圈中只有一个节点
{
break;
}
//first和temp都同时移动m-1个
for(int j = 0; j < m - 1; j++)
{
first = first.next;
temp = temp.next;
}
//这时候first指向节点就是要出圈的节点
Console.WriteLine($"出圈:{first.id}");
//这时候要将出圈的first删掉,既然first就是要被删除的节点,单链表删除节点是要用到被删除节点的上一个辅助节点
//temp不就是被删除节点first的上一个节点吗
first = first.next;
temp.next = first;//这两句代码和单链表删除节点的temp.next=temp.next.next一样,temp指被删除节点的上一个节点
}
//当到了这里,说明链表就剩一个了,最后一个出圈
Console.WriteLine($"出圈:{first.id}");
}