单链表
先说一下在C语言中的链表:
- 每个节点包含两个域,存数据元素信息的叫数据域(data域),存储直接后继(下一个节点)的存储位置的叫指针域(next域)
- 首元结点是指表中存储第一个数据的结点,头结点(head)是在首元结点之前附设的一个结点,其指针域指向首元结点;头指针是指向链表中第一个结点的指针,若有头结点,则头指针就指向头结点,否则指向首元结点;
- 最后一个结点没有直接后继,指针域为null
类比去学习
在java中:(虽无指针,在java 指针即是引用)
- 基本单元是节点Node,每个节点都有两个属性:存储的数据和下一个节点的内存地址,即data域和next域,也会有头结点head, 不放数据,作用就是表头,专门用于存放首元结点的内存位置
- 最后一个结点没有直接后继,(指针域)为null,链表分有无头结点的
- 整个链表的存取都是要从头结点开始进行
增删改查
1. 链表结点的添加(创建)和遍历,修改
对于创建链表:
- 先创建一个head头结点,作用就表示点链表的头
- 后面每添加一个结点,就直接加入到链表的最后(需要遍历找到)
遍历:
通过一个辅助变量帮助遍历整个链表
3.要添加到指定位置时:
首先找到新添加结点的位置的前一个结点,并让辅助结点temp指向此结点
新结点的next = temp.next(保证新节点连上它后面的结点)
temp.next = 新结点(保证新节点连上它前面的结点)
应用实例:
使用带头结点的单链表实现:水浒英雄排行榜的管理
- 在添加英雄时,直接添加到链表的尾部
public class Test {
public static void main(String[] args) {
//创建结点
HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode hero3 = new HeroNode(3,"吴用","智多星");
HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
//创建链表
SingleLinkedList singleLinkedList = new SingleLinkedList();
//将结点添加到链表
singleLinkedList.add(hero1);
singleLinkedList.add(hero2);
singleLinkedList.add(hero3);
singleLinkedList.add(hero4);
//显示链表的内容
singleLinkedList.list();
}
}
//定义HeroNode,每个HeroNode对象就是一个结点
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 + "]";
}
}
//创建单链表,管理英雄对象
class SingleLinkedList{
//先初始化一个头结点,头结点不要动,不存放具体的数据
private HeroNode head = new HeroNode(0, "", "");
//添加结点到单链表
//要先找到链表最后的结点,让最后的结点的next域指向要添加的新结点
public void add(HeroNode heroNode) {//参数就是一个结点
//1. 因为head结点不能动,要借助一个辅助变量temp帮助遍历整个链表
HeroNode temp = head;//此时temp指向头结点
//2. 遍历链表
while(true) {
if(temp.next == null) {//此时找到链表的最后
break;
}
//如果没有找到链表的最后,就将temp后移
temp = temp.next;
}
//3. 当退出while循环后,temp就指向了链表的最后
temp.next = heroNode;//让最后的结点的next域指向要添加的新结点
}
//显示链表(遍历)
public void list() {
//1.先判断链表是否为空
if(head.next == null) {
System.out.println("说明链表为空");
return;
}
//2. 借助一个辅助变量temp帮助遍历整个链表
HeroNode temp = head.next;//此时temp指向首元结点
while(true) {
if(temp == null) {//此时找到链表的最后
break;
}
//输出结点的信息
System.out.println(temp);//因为已经重写了toString 方法直接输出引用,会默认调用此方法
//将temp后移
temp = temp.next;
}
}
}
- 在添加英雄时,根据排名将英雄插入到指定位置(若已经有了这个排名,则提娜佳失败,并给出提示)
public class Test {
public static void main(String[] args) {
//创建结点
HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode hero3 = new HeroNode(3,"吴用","智多星");
HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
//创建链表
SingleLinkedList singleLinkedList = new SingleLinkedList();
//将结点添加到链表
singleLinkedList.addByOrder(hero1);
singleLinkedList.addByOrder(hero2);
singleLinkedList.addByOrder(hero3);
singleLinkedList.addByOrder(hero4);
//显示链表的内容
singleLinkedList.list();
}
}
//定义HeroNode,每个HeroNode对象就是一个结点
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 + "]";
}
}
//创建单链表,管理英雄对象
class SingleLinkedList{
//先初始化一个头结点,头结点不要动,不存放具体的数据
private HeroNode head = new HeroNode(0, "", "");
// //添加结点到单链表
// //要先找到链表最后的结点,让最后的结点的next域指向要添加的新结点
// public void add(HeroNode heroNode) {//参数就是一个结点
// //1. 因为head结点不能动,要借助一个辅助变量temp帮助遍历整个链表
//
// HeroNode temp = head;//此时temp指向头结点
// //2. 遍历链表
// while(true) {
// if(temp.next == null) {//此时找到链表的最后
// break;
// }
// //如果没有找到链表的最后,就将temp后移
// temp = temp.next;
// }
//
// //3. 当退出while循环后,temp就指向了链表的最后
// temp.next = heroNode;//让最后的结点的next域指向要添加的新结点
// }
//3.结点要添加到指定位置时:(此处排名有顺序要求,按编号的大小)
public void addByOrder(HeroNode heroNode) {
//1. 首先找到新添加结点的位置的前一个结点,并让辅助结点temp指向此结点
HeroNode temp = head;
boolean flag = false;//标识添加的编号是否存在,默认不存在
while(true) {
if(temp.next==null) {//说明temp已经在链表的最后
break;
}
if(temp.next.no>heroNode.no) {//位置找到,就在temp的后面插入
break;
}
else if(temp.next.no == heroNode.no) {//说明要添加的heroNode结点的编号已经存在
flag = true;
break;
}
//以上都没找到,直接让temp向后移动
temp = temp.next;
}
//退出循环,判断flag的值
if(flag) {
System.out.print("准备插入的英雄的编号%d 已经存在,不能加入\n"+heroNode.no);
}
else {
//插入到链表中,即temp的后面
// 新结点的next = temp.next(保证新节点连上它后面的结点)
// temp.next = 新结点(保证新节点连上它前面的结点)
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//显示链表(遍历)
public void list() {
//1.先判断链表是否为空
if(head.next == null) {
System.out.println("说明链表为空");
return;
}
//2. 借助一个辅助变量temp帮助遍历整个链表
HeroNode temp = head.next;//此时temp指向首元结点
while(true) {
if(temp == null) {//此时找到链表的最后
break;
}
//输出结点的信息
System.out.println(temp);//因为已经重写了toString 方法直接输出引用,会默认调用此方法
//将temp后移
temp = temp.next;
}
}
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
}
2. 链表结点的修改
- 英雄编号不变,修改其他属性值
//四.修改结点(英雄编号不变,修改其他属性值)
//根据no编号来修改,no编号不变
public void update(HeroNode newNode) {
//判断是否为空
if(head.next==null) {
System.out.println("链表为空");
return;
}
//根据no编号找到需要修改的结点
//借助辅助变量
HeroNode temp =head.next;
boolean flag = false;//标识是否找到改结点
while(true) {
if(temp==null) {//说明temp已经在链表的最后
break;
}
if(temp.no==newNode.no) {//说明已经找到了
flag = true;
break;
}
//最重要的,不要忘记让temp后移,才能遍历
temp = temp.next;
}
//根据flag来判断是否找到要修改的结点
if(flag) {
temp.name = newNode.name;
temp.nickname = newNode.nickname;
}
else {
//没有找到
System.out.println("未找到编号为 %d 的结点,不能修改\n"+newNode.no);
}
}
3. 链表结点的删除
- 借助辅助变量找到需要删除的结点的前一个结点
- temp.next = temp.next.next;
public class Test {
public static void main(String[] args) {
//创建结点
HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode hero3 = new HeroNode(3,"吴用","智多星");
HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
//创建链表
SingleLinkedList singleLinkedList = new SingleLinkedList();
//将结点添加到链表
singleLinkedList.addByOrder(hero1);
singleLinkedList.addByOrder(hero2);
singleLinkedList.addByOrder(hero3);
singleLinkedList.addByOrder(hero4);
//显示链表的内容
singleLinkedList.list();
//测试修改结点
HeroNode newNode = new HeroNode(2,"卢俊义yaya","玉麒麟yayaya");
singleLinkedList.update(newNode);
System.out.println("修改后的结果-----------");
//显示链表的内容
singleLinkedList.list();
//删除一个节点
singleLinkedList.del(1);
System.out.println("删除结点后的结果-----------");
singleLinkedList.list();
}
}
//定义HeroNode,每个HeroNode对象就是一个结点
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 + "]";
}
}
//创建单链表,管理英雄对象
class SingleLinkedList{
//先初始化一个头结点,头结点不要动,不存放具体的数据
private HeroNode head = new HeroNode(0, "", "");
// //一. 添加结点到单链表--------------------------
// //要先找到链表最后的结点,让最后的结点的next域指向要添加的新结点
// public void add(HeroNode heroNode) {//参数就是一个结点
// //1. 因为head结点不能动,要借助一个辅助变量temp帮助遍历整个链表
//
// HeroNode temp = head;//此时temp指向头结点
// //2. 遍历链表
// while(true) {
// if(temp.next == null) {//此时找到链表的最后
// break;
// }
// //如果没有找到链表的最后,就将temp后移
// temp = temp.next;
// }
//
// //3. 当退出while循环后,temp就指向了链表的最后
// temp.next = heroNode;//让最后的结点的next域指向要添加的新结点
// }
//三.结点要添加到指定位置时:(此处排名有顺序要求,按编号的大小)----------------
public void addByOrder(HeroNode heroNode) {
//1. 首先找到新添加结点的位置的前一个结点,并让辅助结点temp指向此结点
HeroNode temp = head;
boolean flag = false;//标识添加的编号是否存在,默认不存在
while(true) {
if(temp.next==null) {//说明temp已经在链表的最后
break;
}
if(temp.next.no>heroNode.no) {//位置找到,就在temp的后面插入
break;
}
else if(temp.next.no == heroNode.no) {//说明要添加的heroNode结点的编号已经存在
flag = true;
break;
}
//以上都没找到,直接让temp向后移动
temp = temp.next;
}
//退出循环,判断flag的值
if(flag) {
System.out.print("准备插入的英雄的编号%d 已经存在,不能加入\n"+heroNode.no);
}
else {
//插入到链表中,即temp的后面
// 新结点的next = temp.next(保证新节点连上它后面的结点)
// temp.next = 新结点(保证新节点连上它前面的结点)
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//四.修改结点(英雄编号不变,修改其他属性值)
//根据no编号来修改,no编号不变
public void update(HeroNode newNode) {
//判断是否为空
if(head.next==null) {
System.out.println("链表为空");
return;
}
//根据no编号找到需要修改的结点
//借助辅助变量
HeroNode temp =head.next;
boolean flag = false;//标识是否找到改结点
while(true) {
if(temp==null) {//说明temp已经在链表的最后
break;
}
if(temp.no==newNode.no) {//说明已经找到了
flag = true;
break;
}
//最重要的,不要忘记让temp后移,才能遍历
temp = temp.next;
}
//根据flag来判断是否找到要修改的结点
if(flag) {
temp.name = newNode.name;
temp.nickname = newNode.nickname;
}
else {
//没有找到
System.out.println("未找到编号为 %d 的结点,不能修改\n"+newNode.no);
}
}
//五. 删除结点
// 1. 借助辅助变量找到需要删除的结点的前一个结点
// 2. temp.next = temp.next.next;
public void del(int no) {
HeroNode temp =head;
boolean flag = false;//标识是否找到待删除结点的前一个结点
while(true) {
if(temp.next == null) {//说明temp已经在链表的最后
break;
}
//在比较时,是temp.next.no 和 需要删除结点的no进行比较
if(temp.next.no == no) {
flag = true;
break;
}
temp = temp.next;
}
if(flag) {
temp.next = temp.next.next;
}
else {
//没有找到
System.out.println("未找到编号为 %d 的结点,不存在\n"+no);
}
}
//二.显示链表(遍历)-----------------------
public void list() {
//1.先判断链表是否为空
if(head.next == null) {
System.out.println("说明链表为空");
return;
}
//2. 借助一个辅助变量temp帮助遍历整个链表
HeroNode temp = head.next;//此时temp指向首元结点
while(true) {
if(temp == null) {//此时找到链表的最后
break;
}
//输出结点的信息
System.out.println(temp);//因为已经重写了toString 方法直接输出引用,会默认调用此方法
//将temp后移
temp = temp.next;
}
}
输出结果:
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
修改后的结果-----------
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
删除结点后的结果-----------
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
}
一些应用:
1. 统计有效结点的个数(若是带头结点,需求不统计头结点),考遍历
// 六,统计有效结点的个数(遍历)
public static int getLength(HeroNode head) {// 其中head指 链表的头结点
if (head.next == null) {// 空链表
return 0;
}
int length = 0;
HeroNode temp = head.next;
while (temp != null) {
length++;
temp = temp.next;
}
return length;
}
2.查找单链表中的倒数第K个结点
//七.查找单链表中的倒数第K个结点
// 思路:
// 编写一个方法,接收一个头结点,还要接收一个k,表示倒数第K个结点
// 先把链表从头到尾遍历,得到链表的总的长度length,调用getLength()方法
// 再从链表的第一个结点开始遍历(length-k)个,找到就返回该结点,否则返回null
public static HeroNode find(HeroNode head,int k) {
if (head.next == null) {// 空链表
return null;
}
int length = getLength(head);
//第二次遍历length-k个,即为倒数第K个结点
//先对k做一下校验
if(k<=0 || k>length) {
return null;
}
HeroNode temp = head.next;
//for循环定位到倒数第k位
for(int i=0;i<length-k;i++) {
temp = temp.next;
}
return temp;
}
3.单链表的反转
思路:
- 先新建一个头结点newhead
- 从头到尾遍历原来的链表,每遍历一个结点,就将其取出,并放在新的链表的头结点newhead的后面,(注意:是每取出一个就放置在紧邻着newhead的后面)
- 最后取完所有原来的结点后,让原来链表的头结点.next = newhead.next
//八.单链表的反转
public static void reverseList(HeroNode head) {
//如果当前链表为空或者只有一个结点,无需反转,直接返回
if(head.next==null || head.next.next==null) {
return;
}
//定义一个辅助指针(变量)来遍历原来链表
HeroNode cur = head.next;//指向当前结点
HeroNode next = null;//指向当前结点cur的下一个结点,因为cur指向的结点要被取走,若没有记录被取走结点的下一个结点,链表断开
HeroNode newhead = new HeroNode(0,"","");//新的头结点
//从头到尾遍历原来的链表,每遍历一个结点,就将其取出,并放在新的链表的头结点newhead的后面
while(cur!=null) {
next = cur.next;//先保存cur的下一个结点的位置,再将此结点取出
cur.next = newhead.next;//将cur的下一个结点指向新的链表的最前端
newhead.next = cur;//链接上新链表
cur = next;//cur实现后移
//以上过程画图就明白了
}
head.next = newhead.next;
}
再次汇总代码:
public class Test {
public static void main(String[] args) {
// 创建结点
HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
// 创建链表
SingleLinkedList singleLinkedList = new SingleLinkedList();
// 将结点添加到链表
singleLinkedList.addByOrder(hero1);
singleLinkedList.addByOrder(hero2);
singleLinkedList.addByOrder(hero3);
singleLinkedList.addByOrder(hero4);
// 显示链表的内容
singleLinkedList.list();
// 测试修改结点
HeroNode newNode = new HeroNode(2, "卢俊义yaya", "玉麒麟yayaya");
singleLinkedList.update(newNode);
System.out.println("修改后的结果-----------");
// 显示链表的内容
singleLinkedList.list();
// 删除一个节点
singleLinkedList.del(1);
System.out.println("删除结点后的结果-----------");
singleLinkedList.list();
// 统计有效结点的个数
// 因为头结点设为私有的,所以添加了get方法来获得
System.out.println("有效的结点个数:"+SingleLinkedList.getLength(singleLinkedList.getHead()));
//测试查找单链表中的倒数第1个结点
HeroNode reHeroNode = SingleLinkedList.find(singleLinkedList.getHead(),1);
System.out.println("倒数第1个结点是"+reHeroNode);
//测试反转
System.out.println("反转后的链表:");
SingleLinkedList.reverseList(singleLinkedList.getHead());
singleLinkedList.list();
}
}
//定义HeroNode,每个HeroNode对象就是一个结点
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 + "]";
}
}
//创建单链表,管理英雄对象
class SingleLinkedList {
// 先初始化一个头结点,头结点不要动,不存放具体的数据
private HeroNode head = new HeroNode(0, "", "");
public HeroNode getHead() {
return head;
}
public void setHead(HeroNode head) {
this.head = head;
}
// //一. 添加结点到单链表--------------------------
// //要先找到链表最后的结点,让最后的结点的next域指向要添加的新结点
// public void add(HeroNode heroNode) {//参数就是一个结点
// //1. 因为head结点不能动,要借助一个辅助变量temp帮助遍历整个链表
//
// HeroNode temp = head;//此时temp指向头结点
// //2. 遍历链表
// while(true) {
// if(temp.next == null) {//此时找到链表的最后
// break;
// }
// //如果没有找到链表的最后,就将temp后移
// temp = temp.next;
// }
//
// //3. 当退出while循环后,temp就指向了链表的最后
// temp.next = heroNode;//让最后的结点的next域指向要添加的新结点
// }
// 三.结点要添加到指定位置时:(此处排名有顺序要求,按编号的大小)----------------
public void addByOrder(HeroNode heroNode) {
// 1. 首先找到新添加结点的位置的前一个结点,并让辅助结点temp指向此结点
HeroNode temp = head;
boolean flag = false;// 标识添加的编号是否存在,默认不存在
while (true) {
if (temp.next == null) {// 说明temp已经在链表的最后
break;
}
if (temp.next.no > heroNode.no) {// 位置找到,就在temp的后面插入
break;
} else if (temp.next.no == heroNode.no) {// 说明要添加的heroNode结点的编号已经存在
flag = true;
break;
}
// 以上都没找到,直接让temp向后移动
temp = temp.next;
}
// 退出循环,判断flag的值
if (flag) {
System.out.print("准备插入的英雄的编号%d 已经存在,不能加入\n" + heroNode.no);
} else {
// 插入到链表中,即temp的后面
// 新结点的next = temp.next(保证新节点连上它后面的结点)
// temp.next = 新结点(保证新节点连上它前面的结点)
heroNode.next = temp.next;
temp.next = heroNode;
}
}
// 四.修改结点(英雄编号不变,修改其他属性值)
// 根据no编号来修改,no编号不变
public void update(HeroNode newNode) {
// 判断是否为空
if (head.next == null) {
System.out.println("链表为空");
return;
}
// 根据no编号找到需要修改的结点
// 借助辅助变量
HeroNode temp = head.next;
boolean flag = false;// 标识是否找到改结点
while (true) {
if (temp == null) {// 说明temp已经在链表的最后
break;
}
if (temp.no == newNode.no) {// 说明已经找到了
flag = true;
break;
}
// 最重要的,不要忘记让temp后移,才能遍历
temp = temp.next;
}
// 根据flag来判断是否找到要修改的结点
if (flag) {
temp.name = newNode.name;
temp.nickname = newNode.nickname;
} else {
// 没有找到
System.out.println("未找到编号为 %d 的结点,不能修改\n" + newNode.no);
}
}
// 五. 删除结点
// 1. 借助辅助变量找到需要删除的结点的前一个结点
// 2. temp.next = temp.next.next;
public void del(int no) {
HeroNode temp = head;
boolean flag = false;// 标识是否找到待删除结点的前一个结点
while (true) {
if (temp.next == null) {// 说明temp已经在链表的最后
break;
}
// 在比较时,是temp.next.no 和 需要删除结点的no进行比较
if (temp.next.no == no) {
flag = true;
break;
}
temp = temp.next;
}
if (flag) {
temp.next = temp.next.next;
} else {
// 没有找到
System.out.println("未找到编号为 %d 的结点,不存在\n" + no);
}
}
// --------------------------------------------------
// 六,统计有效结点的个数(遍历)
public static int getLength(HeroNode head) {// 其中head指 链表的头结点
if (head.next == null) {// 空链表
return 0;
}
int length = 0;
HeroNode temp = head.next;
while (temp != null) {
length++;
temp = temp.next;
}
return length;
}
//七.查找单链表中的倒数第K个结点
// 思路:
// 编写一个方法,接收一个头结点,还要接收一个k,表示倒数第K个结点
// 先把链表从头到尾遍历,得到链表的总的长度length,调用getLength()方法
// 再从链表的第一个结点开始遍历(length-k)个,找到就返回该结点,否则返回null
public static HeroNode find(HeroNode head,int k) {
if (head.next == null) {// 空链表
return null;
}
int length = getLength(head);
//第二次遍历length-k个,即为倒数第K个结点
//先对k做一下校验
if(k<=0 || k>length) {
return null;
}
HeroNode temp = head.next;
//for循环定位到倒数第k位
for(int i=0;i<length-k;i++) {
temp = temp.next;
}
return temp;
}
//八.单链表的反转
public static void reverseList(HeroNode head) {
//如果当前链表为空或者只有一个结点,无需反转,直接返回
if(head.next==null || head.next.next==null) {
return;
}
//定义一个辅助指针(变量)来遍历原来链表
HeroNode cur = head.next;//指向当前结点
HeroNode next = null;//指向当前结点cur的下一个结点,因为cur指向的结点要被取走,若没有记录被取走结点的下一个结点,链表断开
HeroNode newhead = new HeroNode(0,"","");//新的头结点
//从头到尾遍历原来的链表,每遍历一个结点,就将其取出,并放在新的链表的头结点newhead的后面
while(cur!=null) {
next = cur.next;//先保存cur的下一个结点的位置,再将此结点取出
cur.next = newhead.next;//将cur的下一个结点指向新的链表的最前端
newhead.next = cur;//链接上新链表
cur = next;//cur实现后移
//以上过程画图就明白了
}
head.next = newhead.next;
}
// 二.显示链表(遍历)-----------------------
public void list() {
// 1.先判断链表是否为空
if (head.next == null) {
System.out.println("说明链表为空");
return;
}
// 2. 借助一个辅助变量temp帮助遍历整个链表
HeroNode temp = head.next;// 此时temp指向首元结点
while (true) {
if (temp == null) {// 此时找到链表的最后
break;
}
// 输出结点的信息
System.out.println(temp);// 因为已经重写了toString 方法直接输出引用,会默认调用此方法
// 将temp后移
temp = temp.next;
}
}
输出结果:
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
修改后的结果-----------
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
删除结点后的结果-----------
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
有效的结点个数:3
倒数第1个结点是HeroNode [no=4, name=林冲, nickname=豹子头]
反转后的链表:
HeroNode [no=4, name=林冲, nickname=豹子头]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现