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

Posted 结构化思维wz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了恋上数据结构约瑟夫问题(循环链表解决)相关的知识,希望对你有一定的参考价值。

练习-约瑟夫问题

约瑟夫问题是个有名的问题: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;
        
    
    /*====================================================*/

以上是关于恋上数据结构约瑟夫问题(循环链表解决)的主要内容,如果未能解决你的问题,请参考以下文章

暑假OJ练习——8 圆桌问题(使用循环链表解决约瑟夫环问题)

循环链表解决约瑟夫问题

golang数据结构之用循环链表解决约瑟夫环问题

约瑟夫问题--循环链表解决方案

C++ 用循环链表解决约瑟夫环问题

用循环链表解决约瑟夫环问题