算法基础06:单向环形链表

单向环形链表应用场景

Josephu问题

代码实现

添加和遍历思路

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package com.algorithm.linkedlist;

/**
* 约瑟夫问题
*
* @author:XMD
* @date: 13.8.22
*/
public class Josephu {
public static void main(String[] args) {
CircleSingleLinkedList list = new CircleSingleLinkedList();
list.addBoy(5);
list.showBoy();
}

}

/**
* 创建环形单向链表
*/
class CircleSingleLinkedList {
//创建一个first节点,当前没有编号
private Boy first = new Boy(-1);

//添加小孩节点,构建成一个环形链表
public void addBoy(int nums) {
//对nums判断
if (nums < 1) {
System.out.println("nums 值不正确");
return;
}
//辅助节点。帮助构建环形链表
Boy curBoy = null;
for (int i = 1; i <= nums; i++) {
//根据编号创建小孩节点
Boy boy = new Boy(i);
//如果是第一个小孩
if (i == 1) {
first = boy;
//构成一个环
first.setNext(first);
curBoy = first;
} else {
curBoy.setNext(boy);
boy.setNext(first);
curBoy = boy;
}
}
}

/**
* 遍历当前环形链表
*/
public void showBoy() {
//链表是否为空
if (first == null) {
System.out.println("链表为空");
return;
}
//因为first不能动,因此我们仍然使用一个辅助指针完成遍历
Boy curBoy = first;
while (true) {
System.out.println("小孩编号:" + curBoy.getNo());
if (curBoy.getNext() == first) {
//说明遍历结束
break;
}
curBoy = curBoy.getNext();
}
}


}

class Boy {
private int no;
private Boy next;//指向下一个节点

Boy(int no) {
this.no = no;
}

public int getNo() {
return no;
}

public void setNo(int no) {
this.no = no;
}

public Boy getNext() {
return next;
}

public void setNext(Boy next) {
this.next = next;
}
}

打印

1
2
3
4
5
小孩编号:1
小孩编号:2
小孩编号:3
小孩编号:4
小孩编号:5

出圈顺序的逻辑思路

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package com.algorithm.linkedlist;

/**
* 约瑟夫问题
*
* @author:XMD
* @date: 13.8.22
*/
public class Josephu {
public static void main(String[] args) {
CircleSingleLinkedList list = new CircleSingleLinkedList();
list.addBoy(125);
list.showBoy();
System.out.println(">>>>>>>>>>>>>>");
list.countBoy(10,20,215);

}

}

/**
* 创建环形单向链表
*/
class CircleSingleLinkedList {
//创建一个first节点,当前没有编号
private Boy first = new Boy(-1);

//添加小孩节点,构建成一个环形链表
public void addBoy(int nums) {
//对nums判断
if (nums < 1) {
System.out.println("nums 值不正确");
return;
}
//辅助节点。帮助构建环形链表
Boy curBoy = null;
for (int i = 1; i <= nums; i++) {
//根据编号创建小孩节点
Boy boy = new Boy(i);
//如果是第一个小孩
if (i == 1) {
first = boy;
//构成一个环
first.setNext(first);
curBoy = first;
} else {
curBoy.setNext(boy);
boy.setNext(first);
curBoy = boy;
}
}
}

/**
* 遍历当前环形链表
*/
public void showBoy() {
//链表是否为空
if (first == null) {
System.out.println("链表为空");
return;
}
//因为first不能动,因此我们仍然使用一个辅助指针完成遍历
Boy curBoy = first;
while (true) {
System.out.println("小孩编号:" + curBoy.getNo());
if (curBoy.getNext() == first) {
//说明遍历结束
break;
}
curBoy = curBoy.getNext();
}
}

/**
* 根据用户的输入,计算出小孩出圈的顺序
*
* @param startNum 从第几个小孩开始数数
* @param countNum 表示几下
* @param nums 表示最初有多少个小孩在圈中
*/
public void countBoy(int startNum, int countNum, int nums) {
if (first == null || startNum < 1 || startNum > nums) {
System.out.println("输入数据有误");
return;
}
//创建要给辅助指针帮助完成小孩出圈
Boy helper = first;
//创建一个辅助指针helper,事先应该指向环形链表的最后这个节点
while (true) {
if (helper.getNext() == first) {
//说明helper指向最后小孩节点
break;
}
helper = helper.getNext();
}
//小孩报数前,先让first和helper移动k-1次
for (int i = 0; i < startNum - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//当小孩报数时,让first和helper指针同时的移动 m-1次,然后出圈
//这里是一个循环操作,直到圈中只有一个节点
while (true) {
if (helper == first) {
//说明圈中只有一个节点
break;
}
//让first helper 指针同时移动 countNum-1
for (int i = 0; i < countNum - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//这时first指向的节点 就是要出圈的小孩节点
System.out.println("小孩" + first.getNo() + "出圈");

first = first.getNext();
helper.setNext(first);
}

System.out.println("最后留在圈中的小孩:" + first.getNo());


}


}

class Boy {
private int no;
private Boy next;//指向下一个节点

Boy(int no) {
this.no = no;
}

public int getNo() {
return no;
}

public void setNo(int no) {
this.no = no;
}

public Boy getNext() {
return next;
}

public void setNext(Boy next) {
this.next = next;
}
}

-------------本文结束感谢您的阅读-------------