如果把单链表的最后一个节点的指针指向链表的头部,而不是指向NULL,那么就构成了一个单向循环链表
package 动态链表;
import 接口.List;
import java.util.Comparator;
import java.util.Iterator;
public class LinkedSinglyCircularList<E> implements List<E> {
//定义一个结点,用内部类来实现
private class Node{
E data;//数据域,用来存储数据的
Node next;//指针域,用来存储下一个结点对象的地址
public Node(){
this(null,null);
}
public Node(E data){
this(data,null);
}
public Node(E data, Node next){
this.data=data;
this.next=next;
}
public String toString(){
return data.toString();//由data的类型指定toString的内容
}
}
//定义一个头指针,指向第一个头结点的对象
private Node head;
//定义一个尾指针
private Node tail;
//定义一个有效元素的个数,指向最后一个结点的对象
private int size;
public LinkedSinglyCircularList(){
head=null;
tail=null;
size=0;
}
public LinkedSinglyCircularList(E [] arr){
for(E e:arr){
add(e);
}
}
@Override
public void add(E element) {
add(size,element);//注意这里的角标都是虚拟的,链表是不存在角标的
}
@Override
public void add(int index, E element) {
if(index<0||index>size){
throw new ArrayIndexOutOfBoundsException("角标不存在");
}
//创建一个新结点
Node node =new Node(element);
//1,链表为空
if(isEmpty()){
head=node;
tail=node;
tail.next=head;//new code
// size++;
}
//2,表头添加
else if(index==0){
//在表头添加
node.next=head;
head=node;
tail.next=head;//new code
}
//3,在表尾添加
else if(index==size){
node.next=tail.next;//new code
tail.next=node;//node.next只是一个形象化的代称而已
tail=node;
}
else{
//4,在表中间添加元素
Node p =head;
for(int i=0;i<index-1;i++){
p=p.next;
}
node.next =p.next;
p.next=node;
}
size++;
}
@Override
public void remove(E element) {
int index=indexOf(element);
if(index!=-1){
remove(index);
}
}
//删除链表指定角标处的元素
@Override
public E remove(int index) {
if(index<0||index>=size){
throw new ArrayIndexOutOfBoundsException("角标不存在");
}
E ret =null;
//1,当链表只剩一个元素
if(size==1){
ret =head.data;
head=null;
tail=null;
}
//2,如果是表头
else if(index==0){
Node del=head;
ret =del.data;//和head.data是同一个值
head =del.next;
del.next=null;
tail.next=head;//new code
}
//3,删除表尾元素
else if(index==size-1){
Node p=head;
while(p.next!=tail){
p=p.next;
}
ret =tail.data;
// p.next=null;
p.next=tail.next;//new code
tail=p;
}
else{
//4,删除中间某一个元素
Node p=head;
for(int i=0;i<index-1;i++){
p=p.next;
}
//要删除的结点
Node del =p.next;
ret =del.data;
p.next=del.next;
del.next=null;
}
size--;
return ret;
}
//获取链表中指定角标的元素
@Override
public E get(int index) {
if(index<0||index>=size){
throw new ArrayIndexOutOfBoundsException("角标不存在");
}
//1,获取头
if(index==0){
return head.data;
}
else if(index==size-1){
//获取尾部
return tail.data;
}
else{
//获取中间
Node p=head;
for(int i=0;i<index;i++){//直接获取到本身
p=p.next;
}
return p.data;
}
//return null;
}
//修改链表中指定角标的元素
@Override
public E set(int index, E element) {
if(index<0||index>=size){
throw new ArrayIndexOutOfBoundsException("角标不存在");
}
E ret =null;
//1,修改头
if(index==0){
ret =head.data;
head.data =element;
}
else if(index==size-1){
ret = tail.data;
tail.data= element;
}
else{
//3,修改中间
Node p=head;
for(int i=0;i<index;i++){
p=p.next;
}
ret =p.data;
p.data=element;
}
return ret;
}
@Override
public int size() {
return size;
}
//查找元素在链表中第一次出现的角标
@Override
public int indexOf(E element) {
Node p=head;
int index=0;
while(!p.data.equals(element)){
p=p.next;
index++;
if(p==head){
return -1;
}
}
return index;
}
//在链表中判断是否包含元素element
@Override
public boolean contains(E element) {
return indexOf(element)!=-1;
}
@Override
public boolean isEmpty() {
return size==0&&head==null&&tail==null;
}
@Override
public void clear() {
head =null;
tail =null;
size=0;
}
@Override
public void sort(Comparator<E> c) {
if(c==null){
throw new IllegalArgumentException("比较器c不能为空");
}
// int j;
// E e =null;
// for(int i=1;i<size;i++){
// e =get(i);
// for(j=i;j>0&&c.compare(get(j-1),e)>0;j--){
// set(j,get(j-1));
// }
// set(j,e);
// }
//改进
if(size==0||size==1){
return;
}
Node A =head;
Node B=A.next;
while (true){
while (true){
if(c.compare(A.data,B.data)>0){
swap(A,B);
}
if(B==tail) {
break;
}
B =B.next;
}
if(A.next==tail){
break;
}
A=A.next;
B=A.next;
}
}
private void swap(Node a, Node b) {
E temp=a.data;
a.data=b.data;
b.data=temp;
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
//先判断条件是否满足
if(fromIndex<0){
throw new IllegalArgumentException("fromIndex不能小于0");
}
if(toIndex>=size){
throw new IllegalArgumentException("toIndex不能>=size");
}
if(toIndex<fromIndex){
throw new IllegalArgumentException("toIndex不能大于fromIndex");
}
//创建一个线性表
LinkedSinglyList<E> subList =new LinkedSinglyList<>();
// for(int i=fromIndex;i<=toIndex;i++){
// //默认在表尾添加
// subList.add(get(i));
// }
//改进
Node A =head;
for(int i=0;i<fromIndex;i++){
A=A.next;
}
Node B =head;
for(int i=0;i<toIndex;i++){
B=B.next;
}
Node p=A;
while (true){
subList.add(p.data);
if(p==B){
break;
}
p=p.next;
}
return subList;
}
public String toString(){
StringBuilder sb =new StringBuilder(String.format("LinkedSinglyList:%d[",size));
if(isEmpty()){
sb.append("]");
}
else{
Node p=head;
while (true){
sb.append(p.data);
if(p==tail){
sb.append("]");
break;
}
sb.append(",");
p=p.next;
}
}
return sb.toString();
}
@Override
public Iterator<E> iterator() {
return new LinkedSinglyCircularIterator();
}
class LinkedSinglyCircularIterator implements Iterator<E>{
private Node cur =head;
private boolean flag=true;//表示可以继续(在一圈之内)
@Override
public boolean hasNext() {
if(isEmpty()){
return false;
}
return flag;
}
@Override
public E next() {
E ret =cur.data;
cur=cur.next;
if(cur==head){
flag=false;//表示不可以继续(跑完了一圈)
}
return ret;
}
}
}
应用:
约瑟夫环问题
解法一:外部求解
package 动态链表;
public class JosephusLoop {
public static void main(String[] args) {
LinkedSinglyCircularList<Integer> list =new LinkedSinglyCircularList<>();
for(int i=1;i<=20;i++){
list.add(i);
}
// list.josephusLoop();
//System.out.println(list);
//外部解决约瑟夫环的问题
int p=0;
while(list.size()!=2){
p=(p+2)%list.size();
list.remove(p);
}
System.out.println(list
);
}
}
解法二:内部求解
package 动态链表;
import 接口.List;
import java.util.Comparator;
import java.util.Iterator;
public class LinkedSinglyCircularList<E> implements List<E> {
//定义一个结点,用内部类来实现
private class Node{
E data;//数据域,用来存储数据的
Node next;//指针域,用来存储下一个结点对象的地址
public Node(){
this(null,null);
}
public Node(E data){
this(data,null);
}
public Node(E data, Node next){
this.data=data;
this.next=next;
}
public String toString(){
return data.toString();//由data的类型指定toString的内容
}
}
//定义一个头指针,指向第一个头结点的对象
private Node head;
//定义一个尾指针
private Node tail;
//定义一个有效元素的个数,指向最后一个结点的对象
private int size;
public LinkedSinglyCircularList(){
head=null;
tail=null;
size=0;
}
public LinkedSinglyCircularList(E [] arr){
for(E e:arr){
add(e);
}
}
@Override
public void add(E element) {
add(size,element);//注意这里的角标都是虚拟的,链表是不存在角标的
}
@Override
public void add(int index, E element) {
if(index<0||index>size){
throw new ArrayIndexOutOfBoundsException("角标不存在");
}
//创建一个新结点
Node node =new Node(element);
//1,链表为空
if(isEmpty()){
head=node;
tail=node;
tail.next=head;//new code
// size++;
}
//2,表头添加
else if(index==0){
//在表头添加
node.next=head;
head=node;
tail.next=head;//new code
}
//3,在表尾添加
else if(index==size){
node.next=tail.next;//new code
tail.next=node;//node.next只是一个形象化的代称而已
tail=node;
}
else{
//4,在表中间添加元素
Node p =head;
for(int i=0;i<index-1;i++){
p=p.next;
}
node.next =p.next;
p.next=node;
}
size++;
}
@Override
public void remove(E element) {
int index=indexOf(element);
if(index!=-1){
remove(index);
}
}
//删除链表指定角标处的元素
@Override
public E remove(int index) {
if(index<0||index>=size){
throw new ArrayIndexOutOfBoundsException("角标不存在");
}
E ret =null;
//1,当链表只剩一个元素
if(size==1){
ret =head.data;
head=null;
tail=null;
}
//2,如果是表头
else if(index==0){
Node del=head;
ret =del.data;//和head.data是同一个值
head =del.next;
del.next=null;
tail.next=head;//new code
}
//3,删除表尾元素
else if(index==size-1){
Node p=head;
while(p.next!=tail){
p=p.next;
}
ret =tail.data;
// p.next=null;
p.next=tail.next;//new code
tail=p;
}
else{
//4,删除中间某一个元素
Node p=head;
for(int i=0;i<index-1;i++){
p=p.next;
}
//要删除的结点
Node del =p.next;
ret =del.data;
p.next=del.next;
del.next=null;
}
size--;
return ret;
}
//获取链表中指定角标的元素
@Override
public E get(int index) {
if(index<0||index>=size){
throw new ArrayIndexOutOfBoundsException("角标不存在");
}
//1,获取头
if(index==0){
return head.data;
}
else if(index==size-1){
//获取尾部
return tail.data;
}
else{
//获取中间
Node p=head;
for(int i=0;i<index;i++){//直接获取到本身
p=p.next;
}
return p.data;
}
//return null;
}
//修改链表中指定角标的元素
@Override
public E set(int index, E element) {
if(index<0||index>=size){
throw new ArrayIndexOutOfBoundsException("角标不存在");
}
E ret =null;
//1,修改头
if(index==0){
ret =head.data;
head.data =element;
}
else if(index==size-1){
ret = tail.data;
tail.data= element;
}
else{
//3,修改中间
Node p=head;
for(int i=0;i<index;i++){
p=p.next;
}
ret =p.data;
p.data=element;
}
return ret;
}
@Override
public int size() {
return size;
}
//查找元素在链表中第一次出现的角标
@Override
public int indexOf(E element) {
Node p=head;
int index=0;
while(!p.data.equals(element)){
p=p.next;
index++;
if(p==head){
return -1;
}
}
return index;
}
//在链表中判断是否包含元素element
@Override
public boolean contains(E element) {
return indexOf(element)!=-1;
}
@Override
public boolean isEmpty() {
return size==0&&head==null&&tail==null;
}
@Override
public void clear() {
head =null;
tail =null;
size=0;
}
@Override
public void sort(Comparator<E> c) {
if(c==null){
throw new IllegalArgumentException("比较器c不能为空");
}
// int j;
// E e =null;
// for(int i=1;i<size;i++){
// e =get(i);
// for(j=i;j>0&&c.compare(get(j-1),e)>0;j--){
// set(j,get(j-1));
// }
// set(j,e);
// }
//改进
if(size==0||size==1){
return;
}
Node A =head;
Node B=A.next;
while (true){
while (true){
if(c.compare(A.data,B.data)>0){
swap(A,B);
}
if(B==tail) {
break;
}
B =B.next;
}
if(A.next==tail){
break;
}
A=A.next;
B=A.next;
}
}
private void swap(Node a, Node b) {
E temp=a.data;
a.data=b.data;
b.data=temp;
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
//先判断条件是否满足
if(fromIndex<0){
throw new IllegalArgumentException("fromIndex不能小于0");
}
if(toIndex>=size){
throw new IllegalArgumentException("toIndex不能>=size");
}
if(toIndex<fromIndex){
throw new IllegalArgumentException("toIndex不能大于fromIndex");
}
//创建一个线性表
LinkedSinglyList<E> subList =new LinkedSinglyList<>();
// for(int i=fromIndex;i<=toIndex;i++){
// //默认在表尾添加
// subList.add(get(i));
// }
//改进
Node A =head;
for(int i=0;i<fromIndex;i++){
A=A.next;
}
Node B =head;
for(int i=0;i<toIndex;i++){
B=B.next;
}
Node p=A;
while (true){
subList.add(p.data);
if(p==B){
break;
}
p=p.next;
}
return subList;
}
//约瑟夫环的问题
public void josephusLoop(){
if (size==2){
return;
}
Node p=head;
while(size!=2){
p=p.next;
//删除结点
Node del =p.next;
//是头
if(del==head){
head=head.next;
}
//是尾
else if(del==tail){
tail=p;
}
p.next=del.next;
del.next=null;
size--;
p=p.next;
}
}
public String toString(){
StringBuilder sb =new StringBuilder(String.format("LinkedSinglyList:%d[",size));
if(isEmpty()){
sb.append("]");
}
else{
Node p=head;
while (true){
sb.append(p.data);
if(p==tail){
sb.append("]");
break;
}
sb.append(",");
p=p.next;
}
}
return sb.toString();
}
@Override
public Iterator<E> iterator() {
return new LinkedSinglyCircularIterator();
}
class LinkedSinglyCircularIterator implements Iterator<E>{
private Node cur =head;
private boolean flag=true;//表示可以继续(在一圈之内)
@Override
public boolean hasNext() {
if(isEmpty()){
return false;
}
return flag;
}
@Override
public E next() {
E ret =cur.data;
cur=cur.next;
if(cur==head){
flag=false;//表示不可以继续(跑完了一圈)
}
return ret;
}
}
}
应用2:
逢七过
package 动态链表;
import 动态数组.ArrayList;
public class SevenGames {
public static void main(String[] args) {
LinkedSinglyCircularList<ArrayList<String>> list =new LinkedSinglyCircularList();
int M=5;//M个人
int N=50;//N个数,默认从1开始
for(int i=1;i<=M;i++){
list.add(new ArrayList());//每一个ArrayList对应的都是一个玩家
}
int index=0;
for(int num=1;num<=N;num++){
list.get(index++ % M).add(getAnswer(num));
}
for(int i=0;i<list.size();i++){
System.out.println(String.format("玩家%d号的回答的顺序是:%s",i+1,list.get(i)));
}
}
private static String getAnswer(int num) {
if(num%7==0){
return "过";
}
if(containsSeven(num)){
return "过";
}
return num+"";
}
private static boolean containsSeven(int num) {
String s=num+"";//将num转为字符串,比如将17转为"17"
return s.contains("7");
}
}