目录
双向链表
双向链表要注意区分是否是尾节点的情况
public class DoubleLinkedlistDemo {
public static void main(String[] args) {
//创建节点
HeroNode_2 hero1 = new HeroNode_2(1,"宋江","及时雨");
HeroNode_2 hero2 = new HeroNode_2(2,"卢俊义","玉麒麟");
HeroNode_2 hero3 = new HeroNode_2(3,"吴用","智多星");
//创建一个双向链表
DoubleLinedlist doubleLinedlist = new DoubleLinedlist();
doubleLinedlist.addByorder(hero3);
doubleLinedlist.addByorder(hero1);
doubleLinedlist.addByorder(hero2);
doubleLinedlist.list();
System.out.println("****************");
doubleLinedlist.del(2);
doubleLinedlist.list();
}
}
//创建双向链表的类
class DoubleLinedlist{
private HeroNode_2 head = new HeroNode_2(0,"","");
public HeroNode_2 getHead() {
return head;
}
//添加到双向链表的最后
public void add(HeroNode_2 heroNode){
HeroNode_2 temp = head;
while(true){
if(temp.next == null){
break;
}
temp = temp.next;
}
temp.next = heroNode;
heroNode.pre = temp;
}
//按顺序添加到双向链表
public void addByorder(HeroNode_2 heroNode){
HeroNode_2 temp = head;
boolean flag = false; //表示编号是否已经存在
while(true){
if(temp.next == null){
break;
}
if(temp.next.no > heroNode.no){ //找到插入位置
break;
}else if(temp.next.no == heroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if(flag){
System.out.println("编号已经存在,不能插入");
}else{
if(temp.next!=null){
temp.next.pre = heroNode;
heroNode.next = temp.next;
temp.next = heroNode;
heroNode.pre = temp;
}else{
temp.next = heroNode;
heroNode.pre = temp;
}
}
}
//修改链表的节点内容
public void update(HeroNode_2 newHeroNode){
//判断是否为空
if(head.next==null){
System.out.println("链表为空");
return;
}
HeroNode_2 temp = head.next;
boolean flag = false; //表示是否找到该节点
while(true){
if(temp == null){
break; //遍历完成
}
if(temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if(flag){
temp.name = newHeroNode.name;
temp.nickname = newHeroNode.nickname;
}else{
System.out.println("没有找到该节点");
}
}
public void del(int no){
//判断当前链表是否为空
if(head.next == null){
System.out.println("链表为空");
return;
}
HeroNode_2 temp = head.next;
boolean flag = false; //是否删除成功
while(true){
if(temp == null){
break;
}
if(temp.no==no){
flag = true;
break;
}
temp = temp.next;
}
if(flag){
temp.pre.next = temp.next;
if(temp.next != null){
temp.next.pre = temp.pre; //如果删除的是尾结点则不需要这句话
}
}else{
System.out.println("链表中没有找到");
}
}
//遍历双向链表的方法
public void list(){
HeroNode_2 temp = head;
while(true){
if(temp.next == null){
break;
}
temp = temp.next;
System.out.println(temp);
}
}
}
// 定义节点
class HeroNode_2{
public int no;
public String name;
public String nickname;
public HeroNode_2 pre; //指向前一个节点
public HeroNode_2 next; //指向下一个节点
//构造器
public HeroNode_2(int no, String name, String nickname){
this.no = no;
this.name = name;
this.nickname = nickname;
}
@Override
public String toString() {
return "HeroNode_2{" +
"no=" + no +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
输出结果:
单向环形链表
约瑟夫环问题
问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
举例:
n = 5 , 即有5个人
k = 1, 从第一个人开始报数
m = 2, 数2下
出圈的顺序
2->4->1->5->3
思路:用一个不带头结点的循环链表来处理 Josephu 约瑟夫环问题。
构建一个单向的环形链表思路
- 先创建第一个节点, 让 first 指向该节点,并形成环形
- 后面当我们每创建一个新的节点,就把该节点,加入到已有的环形链表中即可
Josephu 约瑟夫环问题出圈思路
public class Josephu {
public static void main(String[] args) {
//生成单向的环形链表
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
circleSingleLinkedList.addBoy(5);
circleSingleLinkedList.showBoy();
System.out.println("*****************");
//测试小孩出圈
circleSingleLinkedList.countBoy(1,2,5);
}
}
//创建一个单向的环形链表
class CircleSingleLinkedList{
//创建first节点,当前没有编号
private Boy first = new Boy(-1);
//添加小孩节点,构建成一个环形链表
public void addBoy(int 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; //用于循环遍历
}
curBoy.setNext(boy);
curBoy = boy;
boy.setNext(first);
}
}
//遍历当前环形链表
public void showBoy(){
//判断链表是否为空
if(first == null){
System.out.println("链表为空");
}
Boy curBoy = first; //辅助变量,帮助构建环形链表
while(true){
System.out.printf("小孩的编号%d\n",curBoy.getNo());
if(curBoy.getNext() == first){
break;
}
curBoy = curBoy.getNext(); //curBoy后移
}
}
//根据用户的输入,计算小孩出圈的顺序
public void countBoy(int startNo, int countNum, int nums){
//先对数据进行校验
if(first == null || startNo < 1 || startNo > nums){
System.out.println("参数输入有误");
return;
}
//创建辅助指针,事先指向环形链表的最后节点
Boy helper = first;
while(true){
if(helper.getNext() == first){ //说明helper指向最后小孩节点
break;
}
helper = helper.getNext();
}
//小孩报数前,先让first 和 helper 移动 k-1次
for(int j=0; j< startNo-1; j++){
first = first.getNext();
helper = helper.getNext();
}
//当小孩报数时,让first和helper同时移动 m-1 次,然后出圈
//循环直到只有一个节点
while(true){
if(helper == first){
break;
}
//让first和helper同时移动 m-1 次
for (int j=0; j<countNum-1; j++){
first = first.getNext();
helper = helper.getNext();
}
//这时first指向的节点,就是要出圈的小孩节点
System.out.printf("小孩%d号出圈\n",first.getNo());
//出圈动作
first = first.getNext();
helper.setNext(first);
}
System.out.printf("最后留在圈中的小孩%d号",first.getNo());
}
}
//创建一个Boy类,表示一个节点
class Boy{
private int no;
private Boy next;
public Boy(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public Boy getNext() {
return next;
}
public void setNo(int no) {
this.no = no;
}
public void setNext(Boy next) {
this.next = next;
}
}
运行结果: