数据结构之双向链表和约瑟夫问题(单向环形链表)

双向链表的定义:
在这里插入图片描述
双向链表的实现
1.代码如下:注意删除时考虑最后一个节点的空指针异常

			package List;
			public class doublelinkedlistdemo {
				public static void main(String[] args) {
				//测试
					HeroNode2 hero1 = new HeroNode2(1,"宋江","及时雨");
					HeroNode2 hero2 = new HeroNode2(2,"卢俊义","玉麒麟");
					HeroNode2 hero3 = new HeroNode2(3,"吴用","智多星");
					HeroNode2 hero4 = new HeroNode2(4,"林冲","豹子头");
					HeroNode2 hero5 = new HeroNode2(5,"史进","九纹龙");
					//创建单链表
					DoubleLinkedList dt =new DoubleLinkedList();
					dt.add(hero1); //添加节点数据
					dt.add(hero2);
					dt.add(hero3);
					dt.add(hero4);
					dt.add(hero5);
					dt.show(); //显示数据
					//修改数据
					System.out.println();
					HeroNode2 hero6 = new HeroNode2(5,"史进","小花龙");
					dt.update(hero6);
					dt.show(); //显示数据
					//删除数据
					System.out.println();
					dt.delete(hero5);
					dt.show(); //显示数据
			  }
			}
			//创建链表属性
			class DoubleLinkedList{
				//初始化一个头节点
					HeroNode2 head = new HeroNode2(0,"","");
					//返回头结点
					public HeroNode2 getHead() {
						return head;
					}
				//遍历双向链表
				public void show() {
					if(head.next==null) {
						System.out.println("链表为空");
						return;
						}
					HeroNode2 temp = head.next;
					while(true) {
						if(temp==null) {break;}
						System.out.println(temp);
						temp = temp.next;
					}
				}
				//在链表后面进行添加
				public void add(HeroNode2 heronode) {
					HeroNode2 temp = head;
					while(true) {
							if(temp.next==null) {
								break; //找到最后的位置
								}
							temp = temp.next;
					}//这里执行完就是最好的位置
					temp.next = heronode;
					heronode.pre = temp;
				}
				//修改一个节点的内容
				public void update(HeroNode2 heronode) {
					if(head.next==null) {
						System.out.println("无该节点");
						return;
						}
					HeroNode2 temp = head;
					boolean flag = false;
					while(true) {
						if(temp==null) {  
									break; //已经遍历完 
			                        }
						if(temp.num==heronode.num) {//编号相同
								flag = true;
								break; //找到最后的位置
								}
						temp = temp.next;//继续遍历
					 }
					if(flag) {
							temp.name = heronode.name;
							temp.pname = heronode.pname;
					}else {
						System.out.println("无该节点编号匹配");
					}
				}
				//删除一个节点,删除本身即可
				public void delete(HeroNode2 heronode ) {
					if(head.next==null) {
						System.out.println("链表为空");
						return;}
					HeroNode2 temp = head;
					boolean flag =false;
					while(true) {
					      if(temp==null) {break;}
					      if(temp.num == heronode.num) {
					    	 flag = true;
					    	 break;
					      }
					      temp = temp.next;
					}
					if(flag) {
						temp.pre.next = temp.next;//跳过temp节点,
						//若删除的是最后一个节点,考虑空指针异常
						if(temp.next!=null) {
							  temp.next.pre = temp.pre;	
						}
					}else {
						System.out.println("无此节点");
					}
				}	
			}
			//创建节点属性
			class HeroNode2 {
				public int num;  //编号
				public String name; //名字
				public String pname; //昵称
				public HeroNode2 next;//指向下一节点
				public HeroNode2 pre; //指向前一个节点
				//构造方法
				public HeroNode2(int numb,String nameb,String pnameb ) {
					this.num = numb;
					this.name = nameb;
					this.pname= pnameb;
				}
				//重写toString方法,方便输出信息
				@Override
				public String toString() {
					return "HeroNode2 [num=" + num + ", name=" + name + ", pname=" + pname + "]";
				}
			}

2.测试结果如下:
在这里插入图片描述
2.单向环形链表
在这里插入图片描述
在这里插入图片描述
最后一位时,还是自己与自己为一个环形链表:
在这里插入图片描述
算法模拟过程:
在这里插入图片描述 在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
出圈如下:利用两个指针来同时step m-1次(包括本身节点报了m个数),通过这两个指针一前一后进行节点删除
在这里插入图片描述
代码如下:

				package List;
				
				public class YuesefuPro {
				   public static void main(String[] args) {
					//测试环形链表
					   CirLinkedList cst = new CirLinkedList();
					   cst.additems(10); //加入5个成员节点;
					   cst.showcurnode(); //显示链表节点编号
					   
					   //测试约瑟夫问题
					   cst.Getnums(1,2,10);//k,m,number
				}
				}
				//创建环形链表
				class CirLinkedList{
					//创建第一个节点,且无编号
					private  Nodeitems first = null; //定义头节点
					
					//添加队员节点,形成环形链表
					public void additems(int num) {
						if(num<1) { System.out.println("输入错误");
						            return;
						          }
						 Nodeitems temp = null; //作为记录指针,记录当前的添加节点
						//使用for循环来创建循环链表
						for(int i = 1;i<=num;i++) {
							  Nodeitems curnode =  new Nodeitems(i);//这是要添加的新节点
						       if(i==1) {
									 first = curnode; //记录第一个节点
									 first.setNext(first);  //指向自己,构成环形链表
									 temp = first;
						        }else {
							       temp.setNext(curnode); //指向新的下一节点
							       curnode.setNext(first); //指向首节点
							       temp = curnode;  //记录该节点,好指向下一节点  
						        }
						}
						
					}
					//约瑟夫问题构建
					/**
					 * @param k 是开始数数的节点
					 * @param m  数多少次数
					 * @param num 链表原来的成员个数
					 */
					public  void Getnums(int k,int m,int num) {
						//数据的校验
						if(first == null || k>num || k<1) {
							System.out.println("输入有问题");
							return;
							}
						Nodeitems curbefore = first; //构建第一个报数的前一个指针
						//使得前后指针相差一步
						while(true) {
							if(curbefore.getNext() ==first) {
								  break;
								 } 
							curbefore= curbefore.getNext(); 
						}
						//报数初始化,让first移动到第k个,curbefore移动到k-1个
						for(int i=0;i<k-1;i++) {
							first =first.getNext(); //first为1,需要走k-1步,这里走了k-2步
							curbefore = curbefore.getNext(); //比first慢一个指针	
						}
						//开始报m个数,走m-1步,找到要出队的节点
						while(true) {
							if(curbefore==first) {break;}//只剩下最后一个节点
							 for(int j=1;j<m;j++) {
									first =first.getNext(); //first就是待出队的节点
									curbefore = curbefore.getNext(); //比first慢一个指针	
							   }
							    System.out.println("出圈的节点"+first.getNum());
							    first = first.getNext();//将待删除节点的下一个赋给前一个节点
							    curbefore.setNext(first) ; //直接跳过要删除的节点
							}
						System.out.println("出圈的节点"+first.getNum());
					}
					//打印链表
					public void showcurnode() {
						//判断链表为空
						if(first == null) {
								System.out.println("链表为空");
							    return;
						                    }
						 Nodeitems temp = first; //作为记录指针,记录当前的添加节点
						 while(true) {
							 System.out.printf("%d \n",temp.getNum());
							 if(temp.getNext()==first) {
								 break; //指向第一个节点,遍历完毕
							 }
							 temp = temp.getNext(); //向下继续遍历  
						 }
					}
					
				}
				//创建节点属性
				class Nodeitems{
					private int num;//编号
					private Nodeitems next;//定义指下的指针
					
					public Nodeitems(int num) {
						this.num = num;
					}
				
					public int getNum() {
						return num;
					}
				
					public void setNum(int num) {
						this.num = num;
					}
				
					public Nodeitems getNext() {
						return next;
					}
				
					public void setNext(Nodeitems next) {
						this.next = next;
					}
					
					
				}

测试结果:k=1,m=2,num=5,10
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值