五、单项环形链表

单项环形链表

约瑟夫环问题

设编号为1,2,3,...n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,他的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

思路:

用一个不带头结点的循环链表来处理约瑟夫问题:先构成一个有n个节点单项环形链表,然后由k节点起从1开始计数,到m时,把对应节点从链表中删除,然后再从被删除节点的下一个节点开始从1计数,知道最后一个节点从链表中删除算法结束。

代码示例:

public class Josepfu {
    public static void main(String[] args) {
        SingleCircleLinkedList singleCircleLinkedList = new SingleCircleLinkedList();
        singleCircleLinkedList.Josepfu(1, 2, 5);
    }
}

//创建单项环形链表
class SingleCircleLinkedList {
    //创建一个first节点,当前没有编号
    private Node first;

    /**
     * @param nums 为环形链表添加几个节点
     */
    public void createSingleCircleLinkedList(int nums) {
        if (nums < 1) {
            System.out.println("nums值不正确");
            return;
        }
        Node curNode = null;
        for (int i = 1; i <= nums; i++) {
            //根据编号创建节点
            Node node = new Node(i);
            if (i == 1) {
                first = node;
                first.setNext(first);//构成环
                curNode = first;//让curNode指向第一个节点
            } else {
                curNode.setNext(node);
                node.setNext(first);
                curNode = node;
            }
        }
    }

    /**
     * 遍历当前环形链表
     */
    public void list() {
        if (first == null) {
            throw new RuntimeException("链表为空!");
        }
        Node curNode = first;
        while (true) {
            System.out.println(curNode);
            if (curNode.getNext() == first) {
                break;
            }
            curNode = curNode.getNext();
        }
    }

    /**
     * 根据用户的输入来完成约瑟夫环问题
     *
     * @param startNo  表示从编号几开始数
     * @param countNum 表示数几下
     * @param nums     表示最初有几个人
     */
    public void Josepfu(int startNo, int countNum, int nums) {
        if (nums < 1 || startNo < 1 || startNo > nums) {
            throw new RuntimeException("参数输入有误!");
        }
        createSingleCircleLinkedList(nums);
        Node pre = first;
        //使pre指向first节点的前一个节点
        while (true) {
            if (pre.getNext() == first) {
                break;
            }
            pre = pre.getNext();
        }
        //使first和pre先移动到一开始报数的人那里
        for (int i = 0; i < startNo - 1; i++) {
            first = first.getNext();
            pre = pre.getNext();
        }
        //当第一个人开始报数时,让first和pre指针同时开始移动countNum-1此,然后first指向的节点出圈
        while (true) {
            if (first == pre) {
                break;
            }
            for (int i = 0; i < countNum - 1; i++) {
                first = first.getNext();
                pre = pre.getNext();
            }
            //这时first指向的节点就是要出圈的节点
            System.out.println(first);
            first = first.getNext();
            pre.setNext(first);
        }
        //退出循环后,圈中就只剩下一个节点了。
        System.out.println(first);
    }
}

class Node {
    private int no;

    private Node next;

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

    public int getNo() {
        return no;
    }

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

    public Node getNext() {
        return next;
    }

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

    @Override
    public String toString() {
        return "Node{" +
                "no=" + no +
                '}';
    }
}
posted @ 2019-12-10 20:03  ねぇ  阅读(235)  评论(0编辑  收藏  举报