前言
今天大致了解了链表的基本概念,然后着重学习了单链表的增删改查、统计单链表的有效节点数和按序查找单链表的节点。由于时间原因,还要复习考试,并且这次学习的也是比较多啦,所以剩余的单链表的三个方法就明天再学之后再加上一个补充。综合来看这次的学习代码比较多,知识概念比较少。OK,切入正题!
何为链表?
链表是有序的列表
在内存中存储如下:
- 链表是以节点的方式来存储,是链式存储
- 每个节点包含data 域, next 域:指向下一个节点.两域
- 链表的各个节点不一定是连续存储.
- 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确
文字很抽象?
来张单链表的存储图瞅瞅(原来我以为一直很好奇链式的代码要怎么写,用了java才知道是用类定义的,就有一种恍然大悟的感觉)

简单的概念介绍之后就是应用实例的代码编写,好,进入正文!
正文
应用实例是对于带头结点的英雄节点的单链表进行如下操作:
- 增加(分两种,一种是简单的来一个添加一个,第二种就是按no编号按顺序的添加)
- 删除(简单的删除节点操作)
- 修改(根据英雄的no修改英雄的信息)
- 查询(直接显示所有的英雄信息)
- 统计单链表中所有有效节点的个数(不包括头节点)
- 按index查找倒数第k个节点
最开始我是很好奇,为什么要用单链表实现?(不知道你们有没有这样的好奇)
其实单链表实现的方式不需要连接数据库等进行操作,所以直接在内存中进行操作,速度比较快。
为了实现以上的功能,需要建立三个类,编写若干方法,详见如下:
1、HeroNode类
该类主要是定义一些属性即英雄所含的信息,重要的是next属性,是指向下一个节点的属性。代码中的注释也比较详细。
//定义一个HeroNode,每一个HeroNode对象就是一个aa节点
class HeroNode{
public int no;//编号
public String name;//英雄的姓名
public String nickname;//英雄的昵称
public HeroNode next;//指向下一个节点
//构造器
public HeroNode(int hNo,String hName,String hNickname){
this.no=hNo;
this.name=hName;
this.nickname=hNickname;
}
//为了显示方便,重写toString方法
@Override
public String toString() {
return "HeroNode [no="+no+",name="+name+",nickname="+nickname+"]";
}
}
2、SingleLinkedList类
最为重要的单链表类,其中包含操作的所有方法,下面为有些比较不同的方法的实现原因和代码,删除和修改比较简单就不单独列出啦。
(1)添加节点到单向链表的add()方法
实现思路:
- 找到当前链表的最后节点
- 将最后这个节点的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;
}
(2)顺序添加的addByOrder()方法
多增加了一个判断,当待添加节点的编号小于一个节点时,就将待添加节点添加在该节点的前面。
public void addByOrder(HeroNode heroNode){
//因为头节点不能动,因此我们仍然通过辅助变量temp帮助找到添加的位置;
//因为是单链表,因此我们找到的temp是位于添加位置的前一个节点,否则加入不了
HeroNode temp=head;
boolean flag=false;//标志添加的编号是否存在,默认为false
while(true){
if(temp.next==null){//说明已在链表的最后
break;
}
if(temp.next.no>heroNode.no){
break;
}else if(temp.next.no==heroNode.no){//说明希望添加的HeroNode的编号已然存在
flag=true;//说明编号存在
}
temp=temp.next;//后移就相当与在遍历当前链表
}
//判断flag的值
if (flag){
System.out.printf("准备插入的英雄的编号%d已经存在了不能插入!\n",heroNode.no);
}else{
//插入到链表中,temp的后面
heroNode.next=temp.next;
temp.next=heroNode;
}
}
(3)查询所有节点信息的list()方法
这个要注意的是判断是否为空的情况以及建立辅助变量.
//显示链表(遍历)
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;
}
}
(4)统计单链表中所有有效节点的个数
/**
*
* @param head 链表的头节点
* @return返回的就是有效节点的个数
*/
public static int getLength(HeroNode head){
if (head.next==null){
return 0; }
int length=0;
//定义一个辅助的变量,这里我们没有统计头节点
HeroNode cur=head.next;
while(cur!=null){
length++;
cur=cur.next;
}
return length;
}
(5)按index查找倒数第k个节点
/**
* 查找单链表中的倒数第k个结点
* 思路
* 1、编写一个方法接受head节点,同时接受一个index
* 2、index表示是倒数index个节点
* 3、先把链表从头到尾遍历,得到链表的总得长度getLength()
* 4、得到siz后,从链表的第一个遍历,遍历(size-index)个,就可以得到
*5、如果找到则返回该节点,否则返回为空
*/
public static HeroNode findLastIndexNode(HeroNode head,int index){
//判断如果链表为空,返回null
if (head.next==null)
return null;//没有找到
//第一次遍历得到链表节点的个数
int size=getLength(head);
//第二次遍历,遍历到(size-index)个,就是目标节点
//先做一个index的校验
if (index<=0||index>size){
return null;
}
//定义一个辅助变量,for循环定位
HeroNode cur=head.next;
for (int i=0;i<size-index;i++){
cur=cur.next;
}
return cur;
}
3、SingleLinkedListDemo类
用于测试操作的功能:
public class SingleLinkedListDemo {
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(hero4);
// singleLinkedList.add(hero2);
// singleLinkedList.add(hero3);
//加入按照编号的顺序
singleLinkedList.addByOrder(hero1);
singleLinkedList.addByOrder(hero4);
singleLinkedList.addByOrder(hero2);
singleLinkedList.addByOrder(hero3);
System.out.println("修改前:");
//显示
singleLinkedList.list();
//测试修改的代码
HeroNode newHeroNode=new HeroNode(2,"小卢","玉麒麟**");
singleLinkedList.update(newHeroNode);
System.out.println("修改后:");
//显示
singleLinkedList.list();
//删除一个节点
singleLinkedList.del(1);
singleLinkedList.del(4);
System.out.println("删除后");
singleLinkedList.list();
//测试一个单链表有效节点的个数
System.out.println(getLength(singleLinkedList.getHead()));
//测试是否得到倒数第K个节点
HeroNode res=findLastIndexNode(singleLinkedList.getHead(),3);
System.out.println("res="+res);
}
}
完整代码:由于完整代码较多我就把代码的放在码云上了,有兴趣的可以看一下:
链接:https://gitee.com/lumengli/DataStructure/blob/master/day02
运行效果如下:
来源:CSDN
作者:静默大焉
链接:https://blog.csdn.net/weixin_44873349/article/details/103464225