zoukankan      html  css  js  c++  java
  • (java实现)单向循环链表

    什么是单向循环链表

    单向循环链表基本与单向链表相同,唯一的区别就是单向循环链表的尾节点指向的不是null,而是头节点(注意:不是头指针).
    因此,单向循环链表的任何节点的下一部分都不存在NULL值。

    由于单向循环链表的特性,它在处理一些环状数据的时候十分有效.大名鼎鼎的约瑟夫环问题就可以用循环单向链表求解,下面我们会有进一步的介绍。

    由于单向循环链表和单向链表的差别真的不大,增添改查原理都相同。因此在这里我们不详细讲解,只提供源码。(如果你还是不理解的话,这里有单向链表的传送门)


    源码实现(Java)

    public class Node<Anytype> {
        public Anytype data;
        public Node<Anytype> next;
        public Node(Anytype data,Node<Anytype> next){
            this.data=data;
            this.next=next;
        }
    }
    
    ------------------------------------
    
    public class SingleLink<AnyType> {
    
    
        //首元节点
        public Node<AnyType> first;
    
        //头指针
        public Node<AnyType> head;
    
        //链表长度
        int thesize;
    
        //初始化链表
        public boolean initlist(){
            thesize=0;
            first=new Node<>(null,null);
            head=new Node<>(null,first);
            first.next=head;
            return true;
        }
    
        //判断链表是否为空
        public boolean isEmpty(){
            return thesize==0;
        }
    
        //获取节点
        public Node<AnyType> getNode(int i){
            Node<AnyType> renode=head;
            for(int j=-2;j<i;j++){
                renode=renode.next;
            }
            return renode;
        }
    
        //在末尾添加元素
        public void add(AnyType a){
            Node<AnyType> renode=new Node<>(a,null);
            getNode(thesize-1).next=renode;
            renode.next=first.next;
            thesize++;
        }
    
        //删除i位置节点,并返回删掉的数据
        public AnyType remove(int i){
            if(i==thesize-1){
                AnyType a=getNode(thesize-1).data;
                getNode(thesize-2).next=first.next;
                return a;
            }
            Node<AnyType> prev=getNode(i-1);
            AnyType a=prev.next.data;
            prev.next=prev.next.next;
            thesize--;
            return  a;
        }
    
        public void remove2(Node<AnyType> n){
    
        }
    
        //在i位置插入新节点
        public void insert(int i,AnyType a){
            Node<AnyType> prev=getNode(i-1);
            Node<AnyType> renode=new Node<>(a,prev.next);
            prev.next=renode;
            thesize++;
        }
    
        //获取i位置节点的数据
        public AnyType get(int i){
            return getNode(i).data;
        }
    
        //为i位置元素重新赋值
        public void set(int i,AnyType a){
            getNode(i).data=a;
        }
    
        //返回链表节点个数
        public int length(){
            return thesize;
        }
    
        //清空链表
        public void clear(){
            initlist();
        }
    
        //打印链表
        public void print(){
            for(int i=0;i<thesize;i++){
                System.out.println(getNode(i).data);
            }
        }
    
    }
    
    

    单向循环链表的应用----约瑟夫环问题

    问题来历

    据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

    思路分析

    首先所有的人是围城一圈的,而且需要循环很多圈才能够将所有人依次排除,而这非常适合刚刚完成的单向循环链表才解决,尾节点的下一个节点又重新拿到的头节点,刚刚和问题中的情况契合。
    首先我们只要拿到链表的头节点,然后依次通过头节点的next指针往后拿到下一个节点,找到第3个移除链表,然后依次循环直到链表为空,移除的顺序就是我们需要的死亡顺序。

    import java.util.Scanner;
    
    public class JosephRing {
        public static void main(String[] args){
            int sum=0;
            int space=0;
            String s="";
            System.out.println("输入环数和间隔");
            Scanner sc=new Scanner(System.in);
            sum=sc.nextInt();
            space=sc.nextInt();
            SingleLink<Integer> sl=new SingleLink<>();
            sl.initlist();
            //编号add进链表
            for(int i=0;i<sum;i++){
                sl.add(i+1);
            }
            Node<Integer> n=sl.first;
            while(n.next!=n){
                for(int i=1;i<space;i++){
                    n=n.next;
                }
                int a=n.next.data;
                n.next=n.next.next;
                s=s+a+",";
            }
            System.out.println(s);
        }
    }
    /*
        输入:41
              3
        输出:3,6,9,12,15,18,21,24,27,30,33,36,39,1,5,10,14,19,23,28,32,37,41,7,13,20,26,34,40,8,17,29,38,11,25,2,22,4,35,16,
     */
    
    
    
    花五年时间成为某个领域的专家
  • 相关阅读:
    Spring整合MyBatis (使用扫描包配置mapper代理)
    spring扫描配置文件
    文件上传解析器
    Jackson介绍(1)-jackson2.x与Jackson1.9的比较
    SpringMVC中使用RedirectAttributes重定向传参,防止暴露参数
    Spring中Model,ModelMap以及ModelAndView之间的区别
    浅谈@RequestMapping @ResponseBody 和 @RequestBody 注解的用法与区别
    Vagrant 创建虚拟环境
    centos安装VirtualBox增强包VBoxGuestAdditions
    Vagrant 命令详解
  • 原文地址:https://www.cnblogs.com/sang-bit/p/11610181.html
Copyright © 2011-2022 走看看