在单链表的基础上加上一个pre节点,用来保存上一个节点
[pre-Data-next] 看起来这种感觉qwq
下面是代码实现
public class DoubleLinkedList {
public NewHeroNode getNewHeroNode() {
return newHeroNode;
}
//拿这个做头结点啦
private final NewHeroNode newHeroNode = new NewHeroNode(null, null, 0);
/**
* 双向链表-添加节点-尾插法
*
* @param heroNode
*/
public void addRear(NewHeroNode heroNode) {
NewHeroNode cur = getNewHeroNode();
//循环遍历找到最后一个节点
while (cur.next != null) {
cur = cur.next;
}
heroNode.pre = cur;//新增节点的pre指向头结点
cur.next = heroNode;//头结点的next指向新增节点
}
/**
* 修改链表某个节点 根据no进行修改 修改方式和单链表几乎一样
*
* @param newHeroNode
* @return
*/
public boolean update(NewHeroNode newHeroNode) {
if (getNewHeroNode().next == null) {
return false;
}
//找到需要修改的节点
//遍历链表
NewHeroNode cur = getNewHeroNode().next;
boolean flag = false;
while (cur != null) {
if (cur.getNo() == newHeroNode.getNo()) {
cur.setName(newHeroNode.getName());
cur.setNickName(newHeroNode.getNickName());
return true;
}
cur = cur.next;
}
return false;
}
public NewHeroNode delete(int No) {
NewHeroNode cur = getNewHeroNode().next; //获取链表的第一个节点
while (cur != null) {
if (cur.getNo() == No && cur.next != null) {
//下面就是删除节点
cur.pre.next = cur.next;
cur.next.pre = cur.pre;
return cur;
}else if (cur.getNo() == No && cur.next == null){
//如果是删除最后一个节点
cur.pre.next = cur.next;
return cur;
}
cur = cur.next;
}
System.out.println("删除失败");
return null;
}
/**
* 遍历双向链表链表
*/
public void list() {
//判断链表是否为空
if (newHeroNode.next == null) {
System.out.println("链表为空");
return;
}
NewHeroNode cur = newHeroNode.next;
while (cur != null) {
System.out.println(cur.toString());
cur = cur.next;
}
}
}
约瑟夫问题
讲一个比较有意思的故事:约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队40余人,他们都是宁死不屈的人,所以不愿投降做叛徒。一群人表决说要死,所以用一种策略来先后kill所有人。
于是约瑟夫建议:每次由其他两人一起kill一个人,而被kill的人的先后顺序是由抽签决定的,约瑟夫有预谋地抽到了最后一签,在kill了除了他和剩余那个人之外的最后一人,他劝服了另外一个没死的人投降了罗马。我们这个规则是这么定的:
在一间房间总共有n个人(下标0~n-1),只能有最后一个人活命。按照如下规则去排除人:
所有人围成一圈
顺时针报数,每次报到q的人将被排除掉
被排除掉的人将从房间内被移走
然后从被kill掉的下一个人重新报数,继续报q,再清除,直到剩余一人
/**
* 约瑟夫环
* 首先需要一个单向环形链表
*/
public class Josephu {
public static void main(String[] args) {
CircleSingleLinkedList circleSingleLinkedList =
new CircleSingleLinkedList();
circleSingleLinkedList.add(5);
circleSingleLinkedList.showBoy();
circleSingleLinkedList.countBoy(1,2,5);
}
}
class CircleSingleLinkedList {
private Boy first = new Boy(-1);//用来指向第一个节点
/**
* 约瑟夫环实现
*
* @param startNo 表示从第几个小孩开始数数
* @param countNum 表示数几下
* @param num 表示最初有多少小孩在圈中
*/
public void countBoy(int startNo, int countNum, int num) {
//先进行数据校验
if (first == null || startNo < 1 || startNo > num) {
System.out.println("参数非法!");
return;
}
//创建一个辅助指针,帮助完成小孩出圈
Boy helper = first;
//让helper指向最后一个节点
while (helper.getNext() != first) {
helper = helper.getNext();
}
//因为startNo不一定每次都是在1,也有可能在2可能在4。
// 之前的工作是为了让first指针指向第一个节点,helper指向最后一个节点。
// 假设startNo是2,那fist和helper就要移动一次,所以要让小孩移动startNo-1次
for (int i = 0; i < startNo - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//小孩报数时,让first和helper指针同时移动countNum-1次(因为当前被指到的节点也要喊一个数嘛),然后出圈
//在这里不停的循环直到只剩下一个节点
while (true){
if (helper == first){
break;
}
for (int i = 0; i < countNum - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//循环完后first指向的节点就是要出圈的节点
System.out.printf("\n小孩%d出圈啦",first.getNo());
//下面就是出圈操作
first = first.getNext();
helper.setNext(first);
}
System.out.println("\n最后留在圈中的小孩:"+first.getNo());
}
/**
* //添加新节点,构建成一个环形链表 一次性加多个Boy
*
* @param nums
*/
public void add(int nums) {
if (nums <= 1) {
System.out.println("nums的值非法");
return;
}
Boy cur = null; //辅助指针 帮助构建环形链表
for (int i = 1; i <= nums; i++) {
//根据编号创建节点
Boy boy = new Boy(i);
if (i == 1) {
first = boy;
first.setNext(first); //在这里建立第一个节点
cur = first; //因为first要保持在第一个节点上,所以接下来让cur代劳
} else {
//增加第一个节点之后的所有节点都这样做
cur.setNext(boy); //当前节点的下一个节点设为新增的节点
boy.setNext(first);//因为新增是在链表尾部,所以新增的节点也是在尾部,让它指向first即可完成循环
cur = boy; //cur新增的节点,即尾部
}
}
}
/**
* 遍历环形链表
*/
public void showBoy() {
//校验
if (first == null) {
System.out.println("链表为空");
return;
}
//设置一个辅助指针
Boy cur = first;
do {
System.out.println("\n小孩的编号为:" + cur.getNo());
cur = cur.getNext();
}
while (cur.getNext() != first);
System.out.println("\n小孩的编号为:" + cur.getNo());
}
}
class Boy {
private int no; //编号
private Boy next; //指向下一个节点
public 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;
}
}