Java数据结构与算法:单向环形链表、约瑟夫问题、思路分析、代码实现

文章目录

  • 单向环形链表
    • 1、经典 约瑟夫问题
      • . 思路分析
      • . 代码实现


单向环形链表

Java数据结构与算法:单向环形链表、约瑟夫问题、思路分析、代码实现_第1张图片


1、经典 约瑟夫问题

Josephus约瑟夫环、约瑟夫问题又称“丢手绢问题”。

有n个人,编号为1~n,从第k个人开始报数,从1开始报,报到m的人会死掉,然后从第m+1个人开始,重复以上过程。在死了n-1个人后,问最后一个人的编号是?


. 思路分析


添加新节点:

示意图 — 添加7号新节点
Java数据结构与算法:单向环形链表、约瑟夫问题、思路分析、代码实现_第2张图片

首先要明确一个头节点,给一个辅助变量head一直指向头节点1。再给一个辅助变量temp,用于遍历链表,当temp.next==head时,说明当前遍历到的temp节点是尾节点。那么就在这里添加新节点,即temp.next=newNode,添加完新节点之后,还需要将新节点的next指向头节点head,即newNode.next=head。这样就新添加了一个节点,并且形成了环状。


移除一个节点:

示意图 — 删除1号节点
Java数据结构与算法:单向环形链表、约瑟夫问题、思路分析、代码实现_第3张图片
Java数据结构与算法:单向环形链表、约瑟夫问题、思路分析、代码实现_第4张图片
首先需要定义一个辅助变量temp,该辅助变量需要指向尾节点即头节点的前一个节点,有一个指向头节点1的head变量。由于需要定位到第k个人开始报数,所以temp和head需要同时向前移动k-1次,此时head就指向第k个节点,报到m的节点会被移除,head和temp同时向前移动m-1次,head就指向了需要被删除的节点,删除该节点的操作是:head=head.next; temp.next=head;这样就把那个节点移除了。之后又继续移动m-1次,继续移除节点。直到head==temp时,环形链表就只剩下最后一个节点。


. 代码实现

public class Josephus {
    public static void main(String[] args) {
        CircleLinkedList circleLinkedList = new CircleLinkedList();

        circleLinkedList.josephus(5,2,2);
    }
}

class CircleLinkedList{
    private JosNode head = null;

    // 创建环形链表
    public void createCircleLinkedList(int nums){
        if(nums<1){
            System.out.println("人数输入错误...");
            return;
        }
        JosNode temp = null; // 用于辅助遍历定位 添加新节点
        for (int i = 1; i <= nums; i++) {
            JosNode node = new JosNode(i);
            // 当等于1时,将辅助遍历head定位到第一个节点,作为头节点
            if(i==1){
                head = node;
                node.next = head; // 形成自循环
                temp = head;
            }
            while (true){
                // temp.next == head 当前定位的节点的next节点是head,说明已到尾节点
                if(temp.next == head){
                    temp.next = node;
                    node.next = head;
                    break;
                }
                temp = temp.next;
            }

        }
    }

    // 遍历环形链表
    public void showNode(){
        JosNode temp = head;
        // head为null就说明没有添加任何节点
        if(head == null){
            System.out.println("空链表...");
            return;
        }
        while (true){
            System.out.println(temp);
            if(temp.next == head){
                break;
            }
            temp = temp.next;
        }
    }

    // nums人数,第k个节点开始,报数到m移除节点
    public void josephus(int nums, int k, int m){
        // 校验数据是否正确
        if(nums < 1 || k > nums || m > nums){
            System.out.println("输入有误...");
            return;
        }
        createCircleLinkedList(nums); // 创建单向环形链表
        // 遍历,将temp指向最后一个节点,此时head指向的是第一个节点
        JosNode temp = head.next;
        while (true){
            if (temp.next == head){
                break;
            }
            temp = temp.next;
        }
        // 第k个人开始报数,将head指向第k个人,temp一直更在head后面,以便操作移除节点
        for (int i = 0; i < k-1; i++) {
            head = head.next;
            temp = temp.next;
        }
        
        while (true){
            // 当temp == head说明,只剩下一个节点
            if (temp == head){
                break;
            }
            // 从head指向的节点开始从1报数,报到m时,temp和head都要移动m-1下
            for (int i = 0; i < m-1; i++) {
                head = head.next;
                temp = temp.next;
            }
            // 此时,head指向的就是需要移除的节点,进行移除操作
            System.out.println("已移除节点:"+head.no);
            head = head.next;
            temp.next = head;
        }
        System.out.println("最后一个节点:" + head.no);
    }
}

class JosNode{
    protected int no;
    protected JosNode next;

    public JosNode() {
    }

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

    @Override
    public String toString() {
        return "JosNode{" +
                "no=" + no +
                '}';
    }
}

结果:

已移除节点:3
已移除节点:5
已移除节点:2
已移除节点:1
最后一个节点:4

你可能感兴趣的:(Java数据结构与算法)