环形单链表的约瑟夫问题

该算法为求解环形单链表的约瑟夫问题,有两种方法可以求出剩下的结点。直接上代码,注释里有具体的思路。

package List;

/**环形链表
 * Created by HH on 2018/3/5.
 */
public class CircleList {
    //方法一:时间复杂度ON*M    public Node findServiorNode(Node head,int m){

        int n = 0;
        //边界判断:若结点为空或只有一个结点或报数小于1,则直接返回头结点
        if(head == null || head.next == head || m < 1){
            return head;
        }
        //定义一个辅助结点,为了在删除结点时做一些辅助功能
        Node pre = head.next;
        //prehead结点的前方,即head == pre.next
        while(pre != head){
            pre = pre.next;
        }
        //删除结点方法,当剩下多个结点时
        while(pre != head){
            //每次循环先将n++
            n++;
            //如果nm相同,则删除当前结点,当前结点用head表示
            if(n == m){
                //删除head结点,并重新组成链表,此时head重新指向pre.next
                pre.next = head.next;
                head.next = null;
                head = pre.next;
                //此时重置n
                n = 0;
                //否则,headpre都向下移动一位
            }else{
                pre = head;
                head = head.next;
            }
        }
        //此时剩下的结点就是唯一的那个结点了
        return head;
    }
    //方法二:时间复杂度ON    public Node findTheOnlyOne(Node head, int m){

        //边界判断:若结点为空或只有一个结点或报数小于1,则直接返回头结点
        if(head == null || head.next == head || m < 1){
            return head;
        }
        //辅助结点node,可以有多个用处
        Node node = head;
        //辅助int,占32位,4个字节,4byte,可用来表示链表的个数与留下结点的编号
        int len = 1;
        //循环得到链表的个数
        while(node != head){
            node = node.next;
            len++;
        }
        //得到留下的结点的编号
        len = getLiveNode(len, m);
        //找到留下的结点
        while(--len != 0){
            node = node.next;
        }
        //令其自身形成循环链表,返回得到所需要的值
        node.next = node;
        return node;

    }
    /*
     *得到编号的算法,该算法是通过归纳得出
     *思想是将每个结点都标上标号,然后根据m,每删除一个结点则环形链表的结点生成一个新的编号
     * 表达式为编号(i = (编号(i-1+ m - 1% i + 1
     * 一层层递归下去,直到i = 1
     * 便可得到最后剩余的结点的编号
     */
    private int getLiveNode(int len, int m){
        //如果len == 1,则返回编号1
        if(len == 1){
            return 1;
        //否则进入递归函数
        }else{
            return (getLiveNode(len-1, m) + m - 1)%len + 1;
        }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
循环链表是一个环形链表,最后一个节点的 next 指针指向头结点。求解问题可以利用循环链表模拟,具体步骤如下: 1. 构建循环链表,将每个人的编号作为节点的数据域,将每个节点的 next 指针指向下一个节点。 2. 定义一个计数器 count,用于记录当前数到了第几个节点。 3. 从头节点开始遍历链表,每次计数器加1,直到计数器的值等于 m 时,就找到了要删除的节点。将该节点从链表中删除,并将计数器 count 重置为 0。 4. 重复步骤 3,直到链表中只剩下一个节点,此时该节点即为最后一个幸存者的编号。 下面是具体的代码实现: ```c++ #include <iostream> using namespace std; struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; int josephus(int n, int m) { ListNode* head = new ListNode(1); ListNode* cur = head; for (int i = 2; i <= n; i++) { cur->next = new ListNode(i); cur = cur->next; } cur->next = head; // 构造循环链表 int count = 0; while (cur->next != cur) { // 链表中还有多于一个节点 count++; if (count == m) { ListNode* temp = cur->next; cur->next = temp->next; delete temp; // 释放要删除的节点 count = 0; } else { cur = cur->next; } } int ans = cur->val; delete cur; // 释放最后一个节点 return ans; } int main() { int n = 5, m = 2; int ans = josephus(n, m); cout << "The last survivor's number is: " << ans << endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值