目录
1.单链表介绍与内存布局
链表是有序的列表,但是它在内存中是存储如下:
小结:
1)链表是以节点的方式来存储,是链式存储
2)每个节点包含data域,next域: 指向下一个节点.
3)如图:发现链表的各个节点不一定是连续存储.
4)链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定
单链表(带头结点)逻辑结构示意图如下
2.单链表的应用示例
使用带head头的单向链表实现-水浒英雄排行榜管理
1)完成对 英雄人物的增删改查操作,注: 删除和修改,查找.
2)第一 种方法在添加英雄时,直接添加到链表的尾部
3)第二种方式在添加英雄时,根据排名将英雄插入到指定位置
(如果有这个排名,则添加失败,并给出提示)
2.1 单链表的创建和遍历的分析实现
单链表的创建示意图,显示单向链表的分析
class HeroNode{
int no; //编号
String name;
String nickname; //昵称
HeroNode next;
}
添加(创建)
1.先创建一个head头节点,作用就是表示单链表的头
2.后面我们每添加一个节点,就直接加入到链表的最后
遍历:
1.通过一个辅助变量遍历,帮助遍历整个链表
单链表判断最后一个结点的方法:判断结点的next域是否为空
以下代码实现链表插入和遍历
//定义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来管理我们的英雄
class SingleLinkedList{
//先初始化头结点,头结点不要动,不存放具体数据
private HeroNode head=new HeroNode(0,"","");
//添加结点到单向链表
/*
添加元素的时候,最重要的就是要找到链表的最后一个结点。(尾插法)。
然后让最后一个结点的next域指向最新的结点。
* */
//思路:当不考虑编号顺序时
//1.找到当前链表的最后结点
//2.将最后结点的next域指向新的结点即可
public void add(HeroNode heroNode){
//因为head结点不能动,因此我们需要一个辅助变量
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;
//如果temp所指结点不为空,那么我们就可以打印
while(temp!=null){
System.out.println(temp); //输出结点信息
temp=temp.next; //一定小心,要后移,否则死循环
}
}
}
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.list();
}
}
此时的顺序是按照插入顺序来输入的,如何按照编号顺序来输出呢?
2.2 单链表按照顺序插入信息
需要按照编号的顺序添加
1.首先找到新添加的节点的位置,是通过辅助变量(指针),通过遍历来搞定
2.新的节点.next =temp.next
3.将temp.next=新的节点
//第二种方式在添加英雄时,根据排名将英雄插入到指定位置
// (如果有这个排名,则添加失败,并给出提示)
public void OrderAdd(HeroNode heroNode){
//因为头结点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
//因为单链表,因为我们找的temp是位于添加位置的前一个结点,否则插入不了
HeroNode temp=head;
//如果temp.next==null,说明temp已经在链表的最后,说明添加的结点就是位于链表的最后
while(temp.next!=null){
//位置找到,就在temp的后边
if(temp.next.no>heroNode.no){
break ;
}else if(temp.next.no==heroNode.no){
//不能添加,说明编号存在
System.out.println("准备插入的英雄的编号已经存在,不能加入");
return;
}
temp=temp.next; //遍历当前链表
}
heroNode.next=temp.next;
temp.next=heroNode;
return;
}
//先创建结点
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.OrderAdd(hero1);
singleLinkedList.OrderAdd(hero4);
singleLinkedList.OrderAdd(hero2);
singleLinkedList.OrderAdd(hero3);
2.3 单链表结点的修改
//修改结点的信息,根据no编号来修改,即no编号不能改
//说明:1.根据newHeroNode的no来修改
public void update(HeroNode newHeroNode){
//判断是否空
if(head.next==null){
System.out.println("链表为空");
return;
}
//找到需要修改的结点,根据no编号
//定义一个辅助变量
HeroNode temp=head.next;
while(temp!=null){
if(temp.no==newHeroNode.no){
System.out.println("找到了");
temp.nickname=newHeroNode.nickname;
temp.name=newHeroNode.name;
return;
}
temp=temp.next;
}
//已经遍历完链表,但是还没找到
System.out.printf("没有找到编号%d的结点",newHeroNode.no);
}
//先创建结点
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.OrderAdd(hero1);
singleLinkedList.OrderAdd(hero4);
singleLinkedList.OrderAdd(hero2);
singleLinkedList.OrderAdd(hero3);
//测试修改结点的代码
HeroNode newHeroNode=new HeroNode(2,"小卢","玉麒麟~~");
singleLinkedList.update(newHeroNode);
2.4 单链表结点的删除
从单链表中删除一个节点的思路
1.我们先找到需要删除的这个节点的前一个节点temp
2. temp.next = temp.next.next
3.被删除的节点,将不会有其它引用指向,会被垃圾回收机制回收
//删除结点
//思路
//1.head不动,因此我们需要一个temp辅助结点找到待删除结点的前一个结点
//2.说明我们在比较时,是temp.next.no和需要删除的结点的no进行比较
public void delete(int no){
HeroNode temp=head;
//当遍历到链表的最后,就必须退出了
while(temp.next!=null){
//注意,我们要找的是待删除结点的前一个结点
if(temp.next.no==no){
temp.next=temp.next.next; //删除结点
return ;
}
temp=temp.next; //后移才能实现遍历
}
//说明一直都没有找到
System.out.printf("没有找到指定的要删除的编号为%d\n",no);
}
//测试删除结点
singleLinkedList.list();
singleLinkedList.delete(3);
System.out.println("删除后");
//显示一把
singleLinkedList.list();