C#实现单向环形链表及约瑟夫问题

环形链表

节点代码

    class Node
    {
        public int ID { get; set; }
        public Node Next { get; set; }

        public Node(int iniID)
        {
            this.ID = iniID;
        }
    }

实现思路

在类体中创建一个 first 节点,使其永远指向链表的第一个节点,如果链表为空,则first指向为空
添加新的节点时,创建一个新的节点 cur,通过cur进行遍历,直到cur的next指向first,此时遍历到了链表的最后一个节点。然后添加如下代码

if(链表为空)
{
	First = newNode;
	newNode.next = First;	//构成环
	cur = first;
}
else
{
	cur.next = newNode;
	newNode = First;	//构成环
	cur = cur.next;
}

代码

//环形单向链表
class CircleSingleLinkedList
{
    private Node First = null;

    //添加 num 个节点到环中
    public void Add(int num)
    {
        //检验num
        if (num < 1)
        {
            Console.WriteLine("num 值不正确");
            return;
        }

        Node cur = null;    //辅助变量,帮助构建环形链表

        //使用for循环来创建环形链表
        for (int i = 1; i <= num; i++)
        {
            //根据编号创建节点
            Node node = new Node(i);

            //第一个节点需要特殊处理
            if (i == 1)
            {
                First = node;
                First.Next = First; //构成环
                cur = First;
            }
            else
            {
                cur.Next = node;
                node.Next = First;
                cur = cur.Next;
            }

        }
    }

    //遍历
    public void Traverse()
    {
        if (First == null)
        {
            Console.WriteLine("链表为空");
            return;
        }

        var cur = First;
        while (true)
        {
            Console.WriteLine($"节点编号:{cur.ID}");
            if (cur.Next == First)  //遍历完毕
            {
                break;
            }
            cur = cur.Next;
        }
    }
}

约瑟夫(Josephu)问题

题目描述

设编号为 1,2,3, … , n 的 n 个人坐成一圈
约定编号为k(1<=k<=n) 的人从1开始报数
数到m的那个人出列,他的下一位再从1开始报数,数到m的人再出列,依此类推,求出队顺序。

思路

1.创建一个辅助变量 helper 指向链表的最后一个节点(即First的前一个节点)
2.让First 和 helper 移动 k-1 次,得到起始位置
3.让First 和helper 移动 m-1 次,得到出队节点
4.将first出队 First = First.next; helper.next = First;

代码

 /// <summary>
 /// do something
 /// </summary>
 /// <param name="startNum">表示从第几个开始报数</param>
 /// <param name="countNum">表示数几下</param>
 /// <param name="num">表示最初有多少个节点</param>
 public void SolveProblem(int startNum, int countNum, int num)
 {
     //校验数据
     if (First == null || startNum < 1 || startNum > num)
     {
         Console.WriteLine("输入有误");
         return;
     }

     //创建helper 
     var helper = First;
     while (true)
     {
         if (helper.Next == First)
         {
             break;
         }
         helper = helper.Next;
     }

     //先让移动 k-1次
     for (int i = 0; i < startNum - 1; i++)
     {
         First = First.Next;
         helper = helper.Next;
     }

     //当报数时,让first和helper同时移动 m-1次,然后出圈
     //直到圈中只有一个节点
     while (true)
     {
         if (helper == First)    //环形表中只剩一个节点
         {
             break;
         }

         for (int i = 0; i < countNum - 1; i++)
         {
             First = First.Next;
             helper = helper.Next;
         }

         Console.WriteLine($"节点 [{First.ID}] 出圈");
         First = First.Next;
         helper.Next = First;
     }
     Console.WriteLine($"最后留在圈中的节点 [{First.ID}]");
 }
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值