什么是单向循环链表
单向循环链表基本与单向链表相同,唯一的区别就是单向循环链表的尾节点指向的不是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个移除链表,然后依次循环直到链表为空,移除的顺序就是我们需要的死亡顺序。
源码实现(此处的循环单向链表是上面我们实现的-SingleLink)
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,*/
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。