一、初识链表
链表是有序的列表。
链表特点:
1、链表以节点的方式存储
2、每个节点包含data域和next域
3、链表分带头节点的链表(本文展示带头节点链表)和没有头节点的链表(由实际需求决定)
头节点:
1、不存放数据
2、表示单链表头,next指向第一个节点
尾节点:
next=null
带头节点链表图示:
节点(Node)基本格式:
class Node{
int data;
Node next;
}
二、引例
使用带头结点的单向链表实现王者荣耀英雄排行榜管理
要求:
1、能够对英雄人物增删改查
2、有两种方法添加英雄:①直接将新英雄加入链表尾部;②按照编号将英雄插入指定位置(不可重复添加,添加失败给出提示)
三、基本功能
1、创建初始节点和链表
思路:
1)先创建一个head头节点,作用就是表示单链表的头
2)每添加一个节点,就直接加入链表的最后
过程:
//定义HeroNode,每个HeroNode对象就是一个节点
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+"]";
}
}
创建SingleLinkedList类,创建头节点,并写入方法(以下2、3、4、5、6点功能):
class SingleLinkedList{
//初始化头节点
private HeroNode head=new HeroNode(0,"","");
}
2、添加节点
1)当不考虑编号顺序时,思路:
①找到当前链表最后节点(使用遍历)
②将最后这个节点next域指向新的节点
2)代码过程:
//添加节点到单向链表
public void add(HeroNode heroNode){
//辅助节点
HeroNode temp=head;
//遍历链表
while (true){
if(temp.next==null){
break;
}
//若没找到最后,temp后移
temp=temp.next;
}
//退出循环时,temp指向链表最后
temp.next=heroNode;
}
3、遍历显示
通过一个辅助变量(temp节点),帮助遍历整个链表
代码过程:
//显示链表,遍历
public void list(){
if(head.next==null){
//头指针next为空
System.out.println("链表为空!");
return;
}
HeroNode temp=head.next;
while (true){
if(temp==null){
break;
}
System.out.println(temp);//已经重写了toString方法
temp=temp.next;
}
}
4、指定位置插入节点
思路:
1)首先找到新添加节点的位置,通过辅助变量,通过遍历搞定
2)新的节点.next=temp.next
3)将temp.next=新的节点
public void insertadd(HeroNode heroNode){
HeroNode temp=head;
boolean flag=false;//添加编号是否存在,默认false
while (true){
//temp已经在链表最后
if(temp.next==null){
break;
}
//当temp的下一个节点序号大于新节点序号时,位置找到
if(temp.next.no>heroNode.no){
break;
}else if(temp.next.no== heroNode.no){
//说明heroNode已经存在
flag=true;
break;
}
temp=temp.next;
}
if(flag){
System.out.println("该英雄已经存在!");
}else {
//新英雄还不在链表中
heroNode.next=temp.next;
temp.next=heroNode;
}
}
5、修改节点信息
根据节点编号no来修改
public void update(HeroNode heroNode){
if(head.next==null){
System.out.println("链表为空!");
}
HeroNode temp=head.next;
boolean flag=false;
while (true){
if(temp==null){
break;//指的是已经遍历完链表
}
if(temp.no==heroNode.no){
flag=true;//找到同样编号的英雄
break;
}
temp=temp.next;
}
if(flag==true){
temp.name= heroNode.name;
temp.nickname= heroNode.nickname;
}else {
System.out.println("没有找到该节点!");
}
}
6、删除节点
1)利用辅助变量找到待删除结点的前一个节点(比较时,将temp.next.no与被删除节点heroNode.no比较)
2)temp.next=temp.next.next
3)被删除节点,将不会有其他引用指向,会被垃圾回收机制回收
public void delete(HeroNode heroNode){
HeroNode temp=head;
boolean flag=false;//是否找到待删除节点
while (true){
if(temp.next==null){
break;
}
if(temp.next.no==heroNode.no){
flag=true;
break;
}
temp=temp.next;
}
if(flag){
temp.next=temp.next.next;
}else {
System.out.println("待删除节点不存在!");
}
}
四、测试代码
public class SingleLinkedListDemo {
public static void main(String[] args) {
//创建四个英雄节点
HeroNode heroNode1=new HeroNode(1,"亚索","新手村领路人");
HeroNode heroNode2=new HeroNode(2,"孙悟空","齐天大圣");
HeroNode heroNode3=new HeroNode(3,"小乔","美人");
HeroNode heroNode4=new HeroNode(4,"武则天","女帝");
//创建链表添加节点,并显示英雄信息
SingleLinkedList singleLinkedList1=new SingleLinkedList();
singleLinkedList1.add(heroNode3);
singleLinkedList1.add(heroNode4);
singleLinkedList1.add(heroNode1);
singleLinkedList1.add(heroNode2);
singleLinkedList1.list();
System.out.println("——————————————这是一条不重要的分界线——————————————");
//创建链表按照编号顺序添加节点,并显示英雄信息
SingleLinkedList singleLinkedList2=new SingleLinkedList();
singleLinkedList2.insertadd(heroNode3);
singleLinkedList2.insertadd(heroNode4);
singleLinkedList2.insertadd(heroNode1);
singleLinkedList2.insertadd(heroNode2);
singleLinkedList2.list();
System.out.println("——————————————这是一条不重要的分界线——————————————");
//修改节点信息,并显示更新后的英雄信息
HeroNode newheroNode=new HeroNode(1,"李白","唐朝诗人");
singleLinkedList2.update(newheroNode);
singleLinkedList2.list();
System.out.println("——————————————这是一条不重要的分界线——————————————");
//删除第一个英雄信息,并显示删除后的英雄信息
singleLinkedList2.delete(heroNode1);
singleLinkedList2.list();
}
}