上图小结:
1、链表是以节点的方式来存储,是链式存储
2、每个节点包含data域,next域:指向下一个节点
3、如图发现链表的各个节点不一定是连续存储
单链表的逻辑结构示意图:
三、关于头结点
链表可以有头节点,也可以没有头节点。
区别在于链表有头节点虽然浪费空间,但易理解,边界好处理,不易出错,代码简单;
相反无头节点,省空间,难理解,边界不易处理,代码稍复杂。
头节点是为了对链表建立、删除、逆向的时候操作更统一,不用专门对第一个元素或最后一个元素进行单独处理。
四、为什么要使用链表呢?
1、数组的物理内存上连续的、顺序的空间,如果数组太大或没有连续大小的空间时就需要使用链表了。
2、如果我们要对一组数据进行删除操作时,用数组的话,我们就需要将要删除的那个数据所在的位置后面的所有数据都向前移动一个位置,当我们添加数据时,同样也要让后面的向后挪动一个位置。
如果使用链表的话,就是把那个节点的指针域所指向地址指向下一个节点的地址就可以了。而添加呢,也是类似的指针操作。
当然链表也有劣势,就是查找,如果想要查找某个数据,就必须要从第一个节点开始依次查找。
那么综上所述,可以知道为什么要用到链表,数组和链表存在的意义了。
那什么又是单向链表?什么又是循环链表?就用一个结构图来表明它们的关系吧。
线性表:一种最简单、常用的数据结构,数据元素之间是一对一的关系。
五、代码实例
使用带head头的单向链表实现水浒英雄排行管理完成对英雄人物的增删改查操作。
定义英雄实例
package com.atguigu.linkedlist;
public 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;
}
@Override
public String toString() {
return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname+"]";
}
}
增删改查
package com.atguigu.linkedlist;
public class SingleLinkedList {
//先初始化一个头节点,头节点不要动,不存放具体数据
private HeroNode head = new HeroNode(0, "", "");
//添加节点到单向链表
//思路,当不考虑编号顺序时
//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就指向了链表的最后
temp.next = heroNode;
}
//第二种添加英雄方法,根据排名插入指定位置
//如果排名存在,则添加失败,并给出提示
public void addByOrder(HeroNode heroNode) {
//因为头节点不能动,我们仍然通过辅助变量来找到添加的位置
//因为是单链表,因此我们找的temp是位于添加位置的前一个节点,否者加入失败
HeroNode temp = head;
boolean flag = false;//标识添加的编号是否存在,默认为false
while(true) {
//说明temp在链表最后
if(temp.next == null) {
System.out.println("在链表最后");
break;
}
//位置找到,就在temp的后面插入
if(temp.next.no > heroNode.no) {
break;
}
//说明编号已经存在
if(temp.next.no == heroNode.no) {
flag = true;
break;
}
//后移,遍历当前链表
temp = temp.next;
}
//判断flag的值
if(flag) {//不能添加,说明编号存在
System.out.printf("插入英雄的编号%d已经存在,插入失败",heroNode.no);
}else {
//插入到链表中,temp的后面
heroNode.next = temp.next;
temp.next = heroNode;
}
}
//修改节点的信息,根据编号no来修改,no不能修改
//根据新节点的编号来修改
public void update(HeroNode newHeroNode) {
//判断是否为空
if(head.next == null) {
System.out.println("链表为空");
return;
}
//找到需要修改的节点,根据no编号
//定义一个辅助变量
HeroNode 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.printf("没找到编号%d的节点,不能修改\n",temp);
}
}
//删除节点