约瑟夫问题-单向环形链表的简单代码实现

package com.structure.linkedList;

import java.util.LinkedList;

/**
 * 单向环形链表-约瑟夫问题
 */
public class CircleSingleLinkedListDemo {

    public static void main(String[] args) {
        CircleSingleLinkedList list = new CircleSingleLinkedList();
        list.add(5);
        list.showLinkedList();
        list.countPerson2(2,5);
        System.out.println(list.countPerson3(2,5));
    }
}

class CircleSingleLinkedList{
    CircleSingleNode firstNode = null;

    //添加节点,构建单向环形链表
    public void add(int num){
        if(num<1){
            System.out.println("参数有误");
            return;
        }
        //定义一个辅助遍量
        CircleSingleNode curNode = null;
        for (int i=1;i<=num;i++){
            CircleSingleNode node = new CircleSingleNode(i);
            //判断是否为第一个节点
            if(i==1){
                firstNode=node; //将第一个节点指向当前节点
                firstNode.setNext(firstNode);
                curNode=firstNode;
            }else {
                curNode.setNext(node);
                node.setNext(firstNode);
                curNode=node;
            }
        }
    }

    //遍历单向环形链表
    public void showLinkedList(){
        //定义一个辅助指针指向firstNode节点
        CircleSingleNode curNode = firstNode;
        while (true){
            System.out.println("当前节点的编号是:"+curNode.getNo());
            if(curNode.getNext()==firstNode){//如果当前指针的下一个节点是第一个节点则表示循环完成
                break;
            }
            curNode = curNode.getNext();
        }
    }

    //约瑟夫问题:有n个人,每次从第k个人开始数数,数到第m个数的人就自杀
    //自定义链表实现
    public void countPerson(int k,int m,int n){
        //先进行数据校验
        if(n<1 || k<1||m<0||k>n){
            System.out.println("参数不合理");
            return;
        }
        //定义一个辅助变量指向环形链表第一个节点的前一个节点
        CircleSingleNode helperNode = firstNode;
        //循环遍历找到helperNode的位置
        while (true){
            if(helperNode.getNext()==firstNode){
                break;
            }
            helperNode = helperNode.getNext();
        }
        //循环遍历找到第k个人开始数数时first和helper的位置
        for(int i=1;i<=k-1;i++){
            firstNode=firstNode.getNext();
            helperNode=helperNode.getNext();
        }

        //
        while (true){
            if(helperNode==firstNode){
                break;
            }
            //first和helper移动m-1次
            for(int i=1;i<=m-1;i++){
                firstNode=firstNode.getNext();
                helperNode=helperNode.getNext();
            }
            //此时firstNode就是要自杀的人的位置
            System.out.println("要自杀的人的编号是:"+firstNode.getNo());
            //将找到的位置的人移除链表
            firstNode=firstNode.getNext();
            helperNode.setNext(firstNode);
        }
        System.out.println("最后活下来的人的编号是:"+firstNode.getNo());
    }

    /**
     * 使用LinkedList实现
     * @param m m是数的数
     * @param n n表示一共有多少个人
     */
    public void countPerson2(int m,int n){
        LinkedList<Integer> linkedList = new LinkedList<Integer>();
        for (int i=1;i<=n;i++){
            linkedList.add(i);
        }
        int removeIndex = 0;
        while (linkedList.size()!=1){
            removeIndex = (removeIndex+m-1)%linkedList.size();
            System.out.println("当前编号是:"+linkedList.get(removeIndex));
            linkedList.remove(removeIndex);
        }
        System.out.println("最后活下来的人的编号是:"+linkedList.get(0));
     }

     //使用递归的方式得到最后一个活下来的人的编号
    public int countPerson3(int m,int n){
        if(n==1){
            return 0;
        }
        return ((countPerson3(m,n-1)+m)%n)+1;
    }
}

class CircleSingleNode{
    private int no;
    private CircleSingleNode next;

    public CircleSingleNode(int no) {
        this.no = no;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public CircleSingleNode getNext() {
        return next;
    }

    public void setNext(CircleSingleNode next) {
        this.next = next;
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
约瑟夫问题是一个经典的数学问题,它的具体描述是:有n个人围成一圈,从第k个人开始报数,报到m的人出列,然后从下一个人开始重新报数,直到所有人都出列。现在我来介绍一下如何使用C语言的单向链表实现约瑟夫问题。 首先,我们需要定义一个链表节点的结构体,包含两个成员变量:一个是保存人员编号的整型变量,另一个是指向下一个节点的指针。 ```c typedef struct Node { int data; struct Node* next; } Node; ``` 接下来,我们可以编写一个函数来创建一个包含n个节点的循环链表,并返回链表的头节点。 ```c Node* createCircularLinkedList(int n) { Node* head = NULL; Node* prev = NULL; for (int i = 1; i <= n; i++) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = i; if (head == NULL) { head = newNode; } else { prev->next = newNode; } prev = newNode; } prev->next = head; // 将最后一个节点的next指针指向头节点,形成循环链表 return head; } ``` 接下来,我们可以编写一个函数来模拟约瑟夫问题的求解过程。 ```c void josephusProblem(Node* head, int k, int m) { Node* current = head; Node* prev = NULL; // 找到从第k个人开始报数的节点 for (int i = 1; i < k; i++) { prev = current; current = current->next; } // 开始报数并出列,直到所有人都出列 while (current->next != current) { // 报数m次 for (int i = 1; i < m; i++) { prev = current; current = current->next; } // 出列 prev->next = current->next; Node* temp = current; current = current->next; free(temp); } // 输出最后一个出列的人员编号 printf("最后一个出列的人员编号:%d\n", current->data); // 释放头节点的内存 free(current); } ``` 最后,我们可以在主函数中调用上述函数来解决约瑟夫问题。 ```c int main() { int n, k, m; printf("请输入总人数n:"); scanf("%d", &n); printf("请输入从第k个人开始报数:"); scanf("%d", &k); printf("请输入报数m次出列:"); scanf("%d", &m); Node* head = createCircularLinkedList(n); josephusProblem(head, k, m); return 0; } ``` 这样,我们就可以通过C语言的单向链表实现约瑟夫问题了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值