Java数据结构–循环链表
循环链表类
public class CircularLinkList<T> {
private class Node<T> {
T date;
Node next;
public Node(T date, Node next) {
this.date = date;
this.next = next;
}
}
private int length;
private Node head;
private Node rear;
CircularLinkList() {
head = new Node(null, null);
head.next = head;
rear = head;
length = 0;
}
/**
* 判断循环链表是否为空
* @return true为空 false不为空
*/
public boolean isEmpty() {
return length == 0;
}
/**
* 获得循环链表的长度
* @return 循环链表的长度
*/
public int size() {
return length;
}
/**
* 清空循环链表
*/
public void clear() {
head.next = head;
head.date=null;
length = 0;
}
/**
* 向循环链表中加入一个值
* @param t 待加入的值
*/
public void put(T t) {
if (isEmpty()) {
head.date = t;
length++;
} else {
Node<T> newNode = new Node<>(t, head);
/*Node<T> tempNode = head;
while (tempNode.next != head) {
tempNode = tempNode.next;
}
if(length == 1){
head.next = newNode;
}
tempNode.next = newNode;
length++;*/
if(head == rear){
head.next = newNode;
rear = newNode;
}else{
rear.next = newNode;
rear = rear.next;
}
length++;
}
}
/**
* 获取第i个元素的值
* @param i 待查找元素的位置
* @return 第i个节点的值
* @Exception NullPointerException
*/
public T get(int i){
Node<T> newNode=null;
if(i<length){
Node<T> tempNode=head;
for(int index=0;index<i;index++){
tempNode=tempNode.next;
}
newNode=tempNode;
}else{
throw new NullPointerException("找不到该元素");
}
return newNode.date;
}
/**
* 删除指定位置元素
* @param i 待删除的元素的位置
* @return 删除的值
* @Exception NullPointerException
*/
public T remove(int i) {
Node<T> delNode=null;
if(i<length){
Node<T> tempNode=head.next;
for(int index=0;index<i;i++){
tempNode=tempNode.next;
}
delNode=tempNode.next;
tempNode.next=delNode.next;
length--;
}else{
throw new NullPointerException("没有可删除的元素");
}
return delNode.date;
}
public void removelNode(Node temp) {
Node<T> tempNode = head;
Node<T> p = rear;
while(tempNode!=temp){
p = tempNode;
tempNode = tempNode.next;
}
p.next = temp.next;
length--;
}
/**
* 遍历循环链表
*/
public void showList(){
int i = 0;
if (isEmpty()){
System.out.println("没有任何元素");
}else{
Node<T> tempNode=head;
while(i<length){
System.out.println(tempNode.date);
tempNode=tempNode.next;
i++;
}
}
}
/**
*一个小游戏,约瑟夫问题
* @return 游戏结果
*/
public void playGame1(){
System.out.println("-------------");
//StringBuilder sb=new StringBuilder();
int count=1;
Node<T> tempNode=head;
while(length != 0){
if(count!=3){
tempNode=tempNode.next;
count++;
}else{
// this.remove1(count);
//showList();
count=1;
System.out.println("玩家"+tempNode.date+"出局");
removelNode(tempNode);
//sb.append("玩家"+tempNode.date+"出局"+"\n");
tempNode=tempNode.next;
}
}
}
}
测试类
public class CircularLinkListTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
CircularLinkList<String> circularLinkList=new CircularLinkList();
System.out.println("请输入想要玩的人数");
int counts = sc.nextInt();
System.out.println("游戏开始,请输入你想坐的位置:");
int seat = sc.nextInt();
for (int i = 0; i < counts; i++) {
if (i + 1 == seat) {
circularLinkList.put("你");
} else {
circularLinkList.put("第" + i + "个犹太人");
}
}
circularLinkList.showList();
circularLinkList.playGame1();
}
}
约瑟夫问题
约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:6,4,5,2,1,3。
分析:
(1)由于对于每个人只有死和活两种状态,因此可以用布尔型数组标记每个人的状态,可用true表示死,false表示活。
(2)开始时每个人都是活的,所以数组初值全部赋为false。
(3)模拟杀人过程,直到所有人都被杀死为止。
public class JosephuTest {
/*
* 采用单链表的环形结构实现约瑟夫问题
*/
public static void main(String[] args) {
// 终端输入n,m数据,n为孩子数量,m为第几个编号退出
Scanner scanner = new Scanner(System.in);
CircleLinkList link = new CircleLinkList();
String str = scanner.next();
link.add(Integer.valueOf(str.split(",")[0]));// 生成单循环链表
link.show();// 显示循环链表
link.josephuTest(Integer.valueOf(str.split(",")[1]));// 输出踢出编号的顺序
}
}
// 建立环形链表
class CircleLinkList{
LinkNode firstNode = new LinkNode(0);// 一个单独的节点,用于指向循环链表第一个元素
//添加数据
public void add(int n) {
// 判断输入的整数是否合理
if (n < 1) {
System.out.println("输入数据小于1,请重新输入");
return;
}
// 遍历增加循环链表的每个元素
LinkNode pre = firstNode;
LinkNode p = null;
for (int i = 1; i <= n; i++) {
LinkNode tmp = new LinkNode(i);
pre.next = tmp;
pre = pre.next;
p = tmp;
}
p.next = firstNode.next;// 头尾相连,生成循环链表
}
// 显示循环链表中的数据
public void show() {
if (firstNode.next == null) {
System.out.println("请先输入数据");
return;
}
// 遍历每个节点,并结合计算器判断是否遍历完成
LinkNode tmp = firstNode.next;
int count = 0;
while (true) {
if (tmp == firstNode.next && count > 0) {
return;
}
System.out.println("小孩子的编号: " + tmp.num);
count++;
tmp = tmp.next;
}
}
// 约瑟夫问题,n个孩子围成一个圈,从1开始报数,数到m时,去掉这个节点,并从1开始继续报数
// 输出所有孩子的编号
public void josephuTest(int m) {
LinkNode tmp = firstNode.next;
while (true) {
// 循环到m节点的前一个节点,方便删除
for (int i = 1; i <= m - 2; i++) {
tmp = tmp.next;
}
if (tmp.next == tmp) {// 判断是否是最后一个节点
System.out.print(tmp.num);
return;
} else {
System.out.print(tmp.next.num + "->");
tmp.next = tmp.next.next;// 删除报数为m的节点
tmp = tmp.next;// 从下一个节点开始报数
}
}
}
}
// 建立节点类
class LinkNode {
int num;
LinkNode next;
// 初始函数,构造器
LinkNode(int num) {
this.num = num;
}
}