【恋上数据结构】约瑟夫问题(循环链表解决)

练习-约瑟夫问题

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3。

分析:

(1)由于对于每个人只有死和活两种状态,因此可以用布尔型数组标记每个人的状态,可用true表示死,false表示活。

(2)开始时每个人都是活的,所以数组初值全部赋为false。

(3)模拟杀人过程,直到所有人都被杀死为止。

【恋上数据结构】约瑟夫问题(循环链表解决)

为了活到最后,我们只能写个算法来帮我们算了!!

思路:

  • 使用循环链表
  • 用一个指针,用于指向节点
  • 增加一个reset方法,重置指针指向头结点
  • 增加一个next方法,让指针往后走一步
  • 增加一个remove方法,用于杀死指针指向的节点,删除后指向下一个节点。
public class JosephusProblem {
    public static void main(String[] args) {
       josephus(3,8);
    }

    /**
     * @param m 数到几淘汰
     * @param people 共有几个人
     */
    public static void josephus(int m,int people){
        CircleLinkedList<Integer> list = new CircleLinkedList<>();
        for (int i = 1; i <= people; i++) {
            list.add(i);
        }
        System.out.println(list.toString());
        //指向头结点
        list.reset();
        //循环杀
        while(! list.isEmpty()){
            for (int i = 1; i < m; i++) {
                list.next();
            }
            System.out.println(list.remove());
        }
    }
}

package 链式结构.test;

import common.AbstractList;

/**
 * @ClassName: CircleLinkedList
 * @Description: 循环链表
 * @author: wangz48
 * @date: 2021-12-29 10:39
 */
public class CircleLinkedList<E> {
    /**
     * 第一个节点
     */
    private Node<E> first;
    /**
     * 最后一个节点
     */
    private Node<E> last;
    /**
     * 当前节点指针
     */
    private Node<E> current;

    /**
     * 双向循环链表节点类
     * @param <E>
     */
    private static class Node<E> {
        E element;
        Node<E> prev;
        Node<E> next;
        public Node(Node<E> prev, E element, Node<E> next) {
            this.prev = prev;
            this.element = element;
            this.next = next;
        }
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            if (prev != null) {
                sb.append(prev.element);
            } else {
                sb.append("null");
            }
            sb.append("_").append(element).append("_");

            if (next != null) {
                sb.append(next.element);
            } else {
                sb.append("null");
            }
            return sb.toString();
        }
    }
    /*===================================================*/

    /**
     * 重置节点
     */
    public void reset(){
        current = first;
    }

    /**
     * 移动指针
     */
    public E next(){
        if (current == null){
            return null;
        }
        current = current.next;
        return current.element;
    }

    /**
     * 删除指向的节点
     */
    public E remove(){
        if(current == null){return null;}
        Node<E> next = current.next;
        E element = remove(current);
        if (size == 0) {
            current = null;
        } else {
            current = next;
        }

        return element;
    }
    private E remove(Node<E> node) {
        if (size == 1) {
            first = null;
            last = null;
        } else {
            Node<E> prev = node.prev;
            Node<E> next = node.next;
            prev.next = next;
            next.prev = prev;

            if (node == first) { // index == 0
                first = next;
            }

            if (node == last) { // index == size - 1
                last = prev;
            }
        }

        size--;
        return node.element;
    }

    public void add(int index, E element) {
        rangeCheckForAdd(index);

        // size == 0
        // index == 0
        if (index == size) { // 往最后面添加元素
            Node<E> oldLast = last;
            last = new Node<>(oldLast, element, first);
            if (oldLast == null) { // 这是链表添加的第一个元素
                first = last;
                first.next = first;
                first.prev = first;
            } else {
                oldLast.next = last;
                first.prev = last;
            }
        } else {
            Node<E> next = node(index);
            Node<E> prev = next.prev;
            Node<E> node = new Node<>(prev, element, next);
            next.prev = node;
            prev.next = node;

            if (next == first) { // index == 0
                first = node;
            }
        }

        size++;
    }

    /**
     * 获取index位置对应的节点对象
     * @param index
     * @return
     */
    private Node<E> node(int index) {
        rangeCheck(index);

        if (index < (size >> 1)) {
            Node<E> node = first;
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
            return node;
        } else {
            Node<E> node = last;
            for (int i = size - 1; i > index; i--) {
                node = node.prev;
            }
            return node;
        }
    }
    /*====================================================*/

【恋上数据结构】约瑟夫问题(循环链表解决)

上一篇:jQuery基本选择器和层级选择器


下一篇:单向循环链表实现