添加(创建)
先创建一个head头节点,作用就是表示单链表的头后面我们每添加一个节点,就直接加入到链表的最后遍历
通过一个辅助变量,帮助遍历整个链表代码
class SingleLinkedListDemo { //定义一个SingleLinkedList来管理我们的英雄人物 static class SingleLinkedList{ //先初始化头结点,头结点不要动,不存放具体数据 private HeroNode head = new HeroNode(0,"",""); //添加节点到单向链表 //思路,当不考虑编号顺序时 //1.找到当前链表的最后节点 //2.将最后这个节点的next指向新的节点 public void add(HeroNode heroNode){ // 因为head节点不能动,因此我们需要一个辅助变量遍历temp HeroNode temp = head; //遍历链表,找到最后 while (true){ //找到链表最后 if (temp.next == null){ break; } //如果没有找到最后,将temp后移 temp = temp.next; } //当退出while循环时,temp就指向了链表的最后 //将最后这个节点的next指向新的节点 temp.next = heroNode; } //显示链表(遍历) public void list(){ //判断链表是否为空 if (head.next == null){ System.out.println("链表为空"); return; } //因为头节点,不能动,因此我们需要一个辅助变量来遍历 HeroNode temp = head.next; while (true){ //判断是否到链表最后 if (temp == null){ break; } //输出节点信息 System.out.println(temp); //将temp后移,一定小心 temp = temp.next; } } } //定义HeroNode,每个HeroNode 对象就是一个节点 static class HeroNode{ public int no; public String name; public String nickname; public HeroNode next;//指向下一个节点 //构造器 public HeroNode(int no, String name, String nickname){ this.no = no; this.name = name; this.nickname = nickname; } //为了显示方便,重写toString方法 @Override public String toString() { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", nickname='" + nickname + '\'' + '}'; } } } public class test { public static void main(String[] args) { //进行测试 //先创建节点 SingleLinkedListDemo.HeroNode hero1 = new SingleLinkedListDemo.HeroNode(1, "宋江", "及时雨"); SingleLinkedListDemo.HeroNode hero2 = new SingleLinkedListDemo.HeroNode(2, "卢俊义", "玉麒麟"); SingleLinkedListDemo.HeroNode hero3 = new SingleLinkedListDemo.HeroNode(3, "吴用", "智多星"); SingleLinkedListDemo.HeroNode hero4 = new SingleLinkedListDemo.HeroNode(4, "林冲", "豹子头"); //创建一个链表 SingleLinkedListDemo.SingleLinkedList singleLinkedList = new SingleLinkedListDemo.SingleLinkedList(); //加入 singleLinkedList.add(hero1); singleLinkedList.add(hero2); singleLinkedList.add(hero3); singleLinkedList.add(hero4); //显示 singleLinkedList.list(); } }思路
我们先找到需要删除的这个节点的前一个节点temptemp.next = temp.next.next被删除的节点,将不会有其他引用指向,会被垃圾回收机制回收 //删除节点 public void del(int no){ HeroNode temp = head; boolean flag = false;//标志是否找到删除节点 while (true){ if (temp.next == null){//已经到链表最后 break; } if (temp.next.no == no){ //找到待删除节点的前一个节点temp flag = true; break; } temp = temp.next; } //判断flag if (flag){//找到 //可以删除 temp.next = temp.next.next; }else { System.out.println("要删除的节点"+no+"不存在"); } }双向链表与单向链表相比较:
查找的只能是一个方向,而双向链表可以向前或者向后查找单向链表不能自我删除,需要靠辅助节点(找到待删除节点的前一个节点),而双向链表可以自我删除遍历方法和单链表一致,只是可以向前,也可以向后查找
//遍历双向链表 public void list(){ //判断链表是否为空 if (head.next == null){ System.out.println("链表为空"); return; } //因为头节点,不能动,因此我们需要一个辅助变量来遍历 HeroNode2 temp = head.next; while (true){ //判断是否到链表最后 if (temp == null){ break; } //输出节点信息 System.out.println(temp); //将temp后移,一定小心 temp = temp.next; } }(默认添加到双向链表的最后)
先找到双向链表的最后一个节点temp.next = newHeroNodenewHeroNode.pre = temp //添加一个节点到双向链表的最后 public void add(HeroNode2 heroNode){ // 因为head节点不能动,因此我们需要一个辅助变量遍历temp HeroNode2 temp = head; //遍历链表,找到最后 while (true){ //找到链表最后 if (temp.next == null){ break; } //如果没有找到最后,将temp后移 temp = temp.next; } //当退出while循环时,temp就指向了链表的最后 //形成一个双向链表 temp.next = heroNode; heroNode.pre = temp; }双向链表的修改与单链表一致
//修改一个节点的内容,与单项链表一致 public void update(HeroNode2 newHeroNode){ //判断是否空 if (head.next == null){ System.out.println("链表为空"); return; } //找到需要修改的节点,根据no编号 //定义一个辅助变量 HeroNode2 temp = head.next; boolean flag = false;//表示是否找到该节点 while (true){ if (temp == null){ break;//已经遍历完链表 } if (temp.no == newHeroNode.no){ //找到了 flag = true; break; } temp = temp.next; } //根据flag判断是否找到要修改的节点 if (flag){ temp.name = newHeroNode.name; temp.nickname = newHeroNode.nickname; }else {//没有找到 System.out.println("没有找到编号为"+newHeroNode.no+"的节点"); } }从双向链表中删除一个节点 对于双向链表直接找到要删除的节点,不需要像单链表那样找到要删除节点的前一个节点 找到后自我删除即可
假设要删除temp这个节点,直接找到他temp.pre.next = temp.nexttemp.next.pre = temp.pre //从双向链表中删除一个节点 //对于双向链表直接找到要删除的节点,不需要像单链表那样找到要删除节点的前一个节点 //找到后自我删除即可 public void del(int no){ //判断当前链表是否为空 if (head.next == null){//空链表 System.out.println("链表为空,无法删除"); return; } HeroNode2 temp = head.next;//辅助变量 boolean flag = false;//标志是否找到删除节点 while (true){ if (temp == null){//已经到链表最后节点的next break; } if (temp.no == no){ //找到待删除节点的前一个节点temp flag = true; break; } temp = temp.next; } //判断flag if (flag){//找到 //可以删除 temp.pre.next = temp.next; //若是最后一个节点,就不需要执行temp.next.pre = temp.pre //否则会空指针异常 if (temp.next!=null){ temp.next.pre = temp.pre; } }else { System.out.println("要删除的节点"+no+"不存在"); } }m个人围成一个圈,指定一个数字n,从第一个人开始报数,每轮报到n的选手出局,由下一个人接着从头开始报,最后一个人是赢家。其中m>1,n>2。(这里我们可以得出一个出队编号的序列)
假设: n = 5,即有5个人 k = 1,即从第一个人开始报数 m = 2,数2下
出圈思路
创建一个辅助指针helper,事先应该指向环形链表的最后一个节点小孩报数前,先让first和helper移动k-1次当小孩报数时,让first和helper指针同时移动m-1次这时就可以将first指向Boy节点出圈 first = first.next helper.next = first 原来first指向的节点就没有任何引用,就会被回收手算的出队列的顺序为:24153
构建一个单向的环形链表的思路
先创建第一个节点,让first指向该节点,并形成环形后面当我们每创建一个新的节点,就把该节点加入到已有的环形链表中即可测试代码
public class Josepfu { public static void main(String[] args) { //测试构建和遍历是否正确 CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(); circleSingleLinkedList.addBoy(5);//5个Boy节点 circleSingleLinkedList.showBoy(); //测试Boy出圈 circleSingleLinkedList.countBoy(1,2,5);//24153 } }