有不足指出,欢迎大佬指出!共同进步。
目录
如何构建环形链表?
约瑟夫问题
完整代码
- 准备
static class RingNode {
private int num;
private RingNode next;
// .....
}
如何构建环形链表?
RingNode firstNode = null; // 环形链表第一个元素(固定不变)
/**
* 构建一个环形链表
* <p>
* 思路:(无头节点)
* 1. 存储的第一个元素,一定要先实现自我环形
* 2. 需要2个指针,2.1:firstNode(即第一个元素)固定不动
* 2.2:curNode => 表示当前元素(每添加一个元素,curNode后移一位),保证 curNode是当前最新
* 3. 新数据插入时,让curNode的next指向,当前插入的元素。再让当前插入的元素指向firstNode,从而首尾相连形成环形
* 4. 插入数据后curNode后移一位,保证指针是最新位置
*/
public void addNode(int list) {
if (list < 1) {
log("链表为空");
return;
}
RingNode curNode = null; // 记录当前位置的元素,每添加一个元素,curNoded就往后移一位
for (int i = 1; i < list; i++) {
RingNode ringNode = new RingNode(i);
if (i == 1) { // 分析1--> 第一个元素,需要特殊处理,先让其自身形成一个环形(自己指向自己)
firstNode = ringNode;
firstNode.setNext(firstNode);
curNode = ringNode;
} else {//分析2--> 先指向要插入的ringNode,在让 ringNode指向firstNode,形成环形
curNode.setNext(ringNode);
ringNode.setNext(firstNode);
curNode = curNode.next; //后移
}
}
// 打印出来
if (firstNode == null) {
log("链表没有add");
return;
}
curNode = firstNode;//curNode用于记录当前位置的curNode,每遍历一位,后移一位
while (true) {
log(curNode.num);
if (curNode.next == firstNode) {// 当前位置的next指向的数据,如果和firstNode 相等,说明已经是最后一位 结束循环
log("链表遍历结束");
break;
}
curNode = curNode.next;
}
}
约瑟夫问题
直接百度具体描述 -->
人们站在一个等待被处决的圈子里。 计数从圆圈中的指定点开始,并沿指定方向围绕圆圈进行。 在跳过指定数量的人之后,执行下一个人。 对剩下的人重复该过程,从下一个人开始,朝同一方向跳过相同数量的人,直到只剩下一个人,并被释放。
如何实现上述的问题?
数组
、环形链表
都可以实现
环形链表实现代码:
请结合图文理解:
/**
* 约瑟夫问题
*
* 场景:环形链表中,每隔几个数取出一个数据,打印出对应的取出顺序
*
* @param startOut 起始位置
* @param outNum 每数几下移除一个数据
* @param allNode 环形链表初始数据是多少
*
* 思路:
* 1.首先考虑,如何让删除元素的前一个元素和后一个元素通过next相连? =》 A B C B是删除元素,要让A.next=C
* 2.准备2个指针:
* firstNode => 记录起始位置的元素也是要删除位置的元素
* helper => 时刻,让helper在first的前一个位置
* 3. 删除元素:
* firstNode = firstNode.next -> 让firstNode后位移一位
* helper.next = firstNode -> 让helper指向位移后的firstNode (时刻保持helper 在firstNode的前一个位置)
* 4. helper = first 时,说明只剩一个元素
*/
public void takeOutNode(int startOut, int outNum, int allNode) {
// 分析1--> 链表不可为null 起点位置不能小于1 起点位置不能大于原有链表的长度
if (firstNode == null || startOut < 1 || startOut > allNode) {
log("takeOutNode return");
return;
}
// 分析2--> 指向指定起点位置的前一个数据
RingNode helper = firstNode;
// 分析2.1 --> 首先要找到环形链表的最后一个元素
while (true) {
if (helper.getNext() == firstNode) {
break;
}
helper = helper.getNext(); // 指针后移
}
// 分析3--> 将firstNode指针指向,用户指定起始位置 helper在firstNode的前一位
for (int i = 0; i < startOut - 1; i++) {
firstNode = firstNode.getNext();
helper = helper.getNext();
}
// 分析4 -->
while (true) {
// 分析4.1 --> 相等说明环形链表中只剩一个数据
if (helper == firstNode) {
log("最后一个元素 " + helper.num);
break;
}
//分析 4.2 --> 根据指定的outNum,移动数据 (outNum-1)=》链表当前位置本身算1下。所以只需后移一位就得到要移除位置的元素
for (int x = 0; x < outNum - 1; x++) {
firstNode = firstNode.getNext();
helper = helper.getNext();
}
log("This is cur Node: " + firstNode.num);
// 分析 4.3 --> 更新当前的firstNode ,helper(移除元素)
// 当前A、B、C B是当前要移除的元素, 让指针A直接指向C
firstNode = firstNode.getNext(); // 将firstNode的指向的下一个数据,赋值给firstNode
helper.next = firstNode; // helper指向最新的firstNode
}
}
图文解释:
分析2-->
分析3--> ``分析4-->
分析4.1-->
分析4.2-->
删除前对应的链表结构
实现删除操作:分析4.3-->
删除后的链表结构
完整代码
public class RingLinkList {
public static void main(String[] args) {
RingLinkList r = new RingLinkList();
r.addNode(16);
log("--------------");
r.takeOutNode(3, 3, 16);
}
RingNode firstNode = null; // 环形链表第一个元素(固定不变)
/**
* 构建一个环形链表
* <p>
* 思路:(无头节点)
* 1. 存储的第一个元素,一定要先实现自我环形
* 2. 需要2个指针,2.1:firstNode(即第一个元素)固定不动
* 2.2:curNode => 表示当前元素(每添加一个元素,curNode后移一位),保证 curNode是当前最新
* 3. 新数据插入时,让curNode的next指向,当前插入的元素。再让当前插入的元素指向firstNode,从而首尾相连形成环形
* 4. 插入数据后curNode后移一位,保证指针是最新位置
*/
public void addNode(int list) {
if (list < 1) {
log("链表为空");
return;
}
RingNode curNode = null; // 记录当前位置的元素,每添加一个元素,curNoded就往后移一位
for (int i = 1; i < list; i++) {
RingNode ringNode = new RingNode(i);
if (i == 1) { // 分析1--> 第一个元素,需要特殊处理,先让其自身形成一个环形(自己指向自己)
firstNode = ringNode;
firstNode.setNext(firstNode);
curNode = ringNode;
} else {//分析2--> 先指向要插入的ringNode,在让 ringNode指向firstNode,形成环形
curNode.setNext(ringNode);
ringNode.setNext(firstNode);
curNode = curNode.next; //后移
}
}
// 打印出来
if (firstNode == null) {
log("链表没有add");
return;
}
curNode = firstNode;//curNode用于记录当前位置的curNode,每遍历一位,后移一位
while (true) {
log(curNode.num);
if (curNode.next == firstNode) {// 当前位置的next指向的数据,如果和firstNode 相等,说明已经是最后一位 结束循环
log("链表遍历结束");
break;
}
curNode = curNode.next;
}
}
/**
* 约瑟夫问题
*
* 场景:环形链表中,每隔几个数取出一个数据,打印出对应的取出顺序
*
* @param startOut 起始位置
* @param outNum 每数几下移除一个数据
* @param allNode 环形链表初始数据是多少
*
* 思路:
* 1.首先考虑,如何让删除元素的前一个元素和后一个元素通过next相连? =》 A B C B是删除元素,要让A.next=C
* 2.准备2个指针:
* firstNode => 记录起始位置的元素也是要删除位置的元素
* helper => 时刻,让helper在first的前一个位置
* 3. 删除元素:
* firstNode = firstNode.next -> 让firstNode后位移一位
* helper.next = firstNode -> 让helper指向位移后的firstNode (时刻保持helper 在firstNode的前一个位置)
* 4. helper = first 时,说明只剩一个元素
*/
public void takeOutNode(int startOut, int outNum, int allNode) {
// 分析1--> 链表不可为null 起点位置不能小于1 起点位置不能大于原有链表的长度
if (firstNode == null || startOut < 1 || startOut > allNode) {
log("takeOutNode return");
return;
}
// 分析2--> 指向指定起点位置的前一个数据
RingNode helper = firstNode;
// 分析2.1 --> 首先要找到环形链表的最后一个元素
while (true) {
if (helper.getNext() == firstNode) {
break;
}
helper = helper.getNext(); // 指针后移
}
// 分析3--> 将firstNode指针指向,用户指定起始位置 helper在firstNode的前一位
for (int i = 0; i < startOut - 1; i++) {
firstNode = firstNode.getNext();
helper = helper.getNext();
}
// 分析4 -->
while (true) {
// 分析4.1 --> 相等说明环形链表中只剩一个数据
if (helper == firstNode) {
log("最后一个元素 " + helper.num);
break;
}
//分析 4.2 --> 根据指定的outNum,移动数据 (outNum-1)=》链表当前位置本身算1下。所以只需后移一位就得到要移除位置的元素
for (int x = 0; x < outNum - 1; x++) {
firstNode = firstNode.getNext();
helper = helper.getNext();
}
log("This is cur Node: " + firstNode.num);
// 分析 4.3 --> 更新当前的firstNode ,helper(移除元素)
// 当前A、B、C B是当前要移除的元素, 让指针A直接指向C
firstNode = firstNode.getNext(); // 将firstNode的指向的下一个数据,赋值给firstNode
helper.next = firstNode; // helper指向最新的firstNode
}
}
static class RingNode {
private int num;
public RingNode(int num) {
this.num = num;
}
private RingNode next;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public RingNode getNext() {
return next;
}
public void setNext(RingNode next) {
this.next = next;
}
}
}