文章目录
链表
一、链表内存存储结构介绍
-
链表是以节点的方式来存储,是链式存储
-
每个节点包含
data 域
:当前节点的值
,next 域
:指向下一个节点
-
链表的各个节点不一定是连续存储 ----
靠next域进行节点间的连接指向,最后链表的以NULL值结束
-
链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定
二、链表逻辑结构介绍
- 所谓的逻辑结构其实就是将链表中的节点按照先后顺序依次连接直到结束形成的一条链式结构。
三、单链表的应用实例 使用带head头的单向链表实现 –水浒英雄排行榜管理
♑ 添加英雄时,直接添加到链表的尾部
单链表类
- 主要功能:
构建含有头节点的单链表
、实现链表节点的添加
、链表的输出
- 利用节点类创建头节点 ---- 固定不变
- 链表元素的添加方法:直接向链表最后添加节点。要实现直接向链表的最后添加节点,首先要回到链表的结构上去,链表
最后节点的特点 ---- next域为null
,抓住这一点,我们在添加节点的时候对链表进行遍历,找到当前链表的最后一个(temp.next = null
),然后将新的节点赋给最后节点的next域(temp.next = heroNode
)。 - 注意在整个过程中我们引入
辅助节点temp
,将头节点的属性赋值给它,让它代表头节点依次往后去比较,某种意义上可以将temp看成是指针,引入辅助节点的关键在于头节点是不可变的。 - 同样的,在进行链表输出的时候,也借助到辅助节点进行遍历输出。
class singleLinkedList{
// 创建头节点,固定不动
private HeroNode head = new HeroNode(0,"","");
// 添加节点
public void add(HeroNode heroNode){
// 借助辅助节点进行遍历
HeroNode temp = head;
// 循环遍历,直到找不到下一个(以达到当前链表的最后一个节点)
while (true){
if (temp.next == null){
break;
}
// 不是最后一个,后移一个节点
temp = temp.next;
}
// 当退出循环的时候,temp指向了链表的最后
// 将最后节点的next指向新的节点
temp.next = heroNode;
}
// 显示链表
public void showList(){
// 既然显示链表,那就得遍历,首先判断链表是否为空
// 如果头节点的下一个为空,那么该链表为空
if (head.next == null){
System.out.println("该链表为空!");
return;
}
// 同样借助辅助节点
HeroNode temp = head.next;
// 循环遍历
while (true){
// 如果temp为空,表示到了链表的最后
if (temp == null){
break;
}
// 输出信息
System.out.println(temp);
// 节点后移
temp = temp.next;
}
}
}
节点类
- 主要功能:
创建节点
- 声明节点的结构、包含的信息
// 创建节点,每个节点就是一个对象
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;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
测试
package 链表;
public class singleLinkedLsitDemo {
public static void main(String[] args) {
// 创建一个单链表
singleLinkedList singleLinkedList = new singleLinkedList();
// 创建多个节点
HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
HeroNode hero3 = new HeroNode(3,"吴用","智多星");
HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
HeroNode hero5 = new HeroNode(5,"李逵","黑旋风");
// 向链表中添加节点
singleLinkedList.add(hero1);
singleLinkedList.add(hero2);
singleLinkedList.add(hero3);
singleLinkedList.add(hero4);
singleLinkedList.add(hero5);
// 输出链表
singleLinkedList.showList();
}
}
♑ 添加英雄时,根据排名将英雄插入到指定位置
实现根据排名进行添加的方法
- 主要功能:
找到排名位置进行节点插入
- 这里主要有两个要求:
1.对链表的添加元素实行有序添加
;2.对于已存在编号的元素舍弃添加
- 在直接添加到链表最后的add()方法的基础上,难点在于找到新节点添加的位置。所谓的有序,就是按照节点的编号信息(
no
),那么我们就对编号进行比较,依旧使用辅助节点进行遍历。 - 遍历的时候对
辅助节点.next
和新节点
的编号进行大小比较(结合上图看会更容易理解),获取位置后,利用next域的指向将链表串联起来。
// 进行排名添加
public void addByOrder(HeroNode heroNode) {
// 通过编号顺序添加到列表中,若已存在编号,则不能添加
HeroNode temp = head;
boolean flag = false; // 标志是否已存在某一编号的节点
while (true) {
// 链表为空
if (temp.next == null) {
break;
}
// 在插入的时候,是位于添加位置的前一个节点
if (temp.next.no > heroNode.no) {
break; // 添加位置找到
} else if (temp.next.no == heroNode.no) {
flag = true; // 编号已存在
break;
}
// 节点后移
temp = temp.next;
}
// 判断状态
if (flag) {
System.out.printf("该英雄的编号 %d 已经存在\n", heroNode.no);
} else {
// 将新的节点加入到链表中
heroNode.next = temp.next;
temp.next = heroNode;
}
}
测试
public class singleLinkedLsitDemo {
public static void main(String[] args) {
// 创建一个单链表
singleLinkedList singleLinkedList = new singleLinkedList();
// 创建多个节点
HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
HeroNode hero5 = new HeroNode(5, "李逵", "黑旋风");
// 向链表中添加节点(乱序)
singleLinkedList.addByOrder(hero2);
singleLinkedList.addByOrder(hero5);
singleLinkedList.addByOrder(hero1);
singleLinkedList.addByOrder(hero4);
singleLinkedList.addByOrder(hero3);
// 输出链表
singleLinkedList.showList();
}
}