第三章 链表
3.1 链表的介绍
- 链表是有序的列表,但是它在内存中的储存如下:

- 总结
- 链表是以结点的方式来存储的
- 每个结点包含data域:存储数据;next域:指向下一个结点
- 如图:发现链表的各个节点不一定是连续存储的
- 链表分带头结点的链表和不带头结点的链表,根据实际需求来确定
3.2 单链表介绍
3.2.1 单链表的创建示意图(添加),显示对象链表的分析

3.2.2 单链表操作
- 创建(添加):
1. 先创建一个head头结点,作用就是表示单链表的头
2. 后面我们每添加一个节点,就直接加入到链表的最后 - 遍历
1. 通过一个数组辅助变量遍历,帮助遍历整个链表 - 按学号大小进行添加,即添加时自动排序
- 首先找到新添加的节点的位置,时通过辅助变量(指针)
- 新的节点.next=temp.next
- 将temp.next=新的节点
- 演示图:

package com.wkj;
import sun.security.provider.certpath.PKIXTimestampParameters;
/**
* @author xxiao
* @date 2022/2/7 - 16:41
*/
public class SingleLinkedListDemo {
public static void main(String[] args) {
//测试
//先创建节点
HeroNode heroNode1 = new HeroNode(new Student(1,"张三",18));
HeroNode heroNode2 = new HeroNode(new Student(2,"李四",22));
HeroNode heroNode3 = new HeroNode(new Student(4,"王五",21));
HeroNode heroNode4 = new HeroNode(new Student(5,"李六",23));
//创建一个链表
SingleLinkedList singleLinkedList = new SingleLinkedList();
//加入
/* singleLinkedList.add(heroNode1);
singleLinkedList.add(heroNode4);
singleLinkedList.add(heroNode3);
singleLinkedList.add(heroNode2);
singleLinkedList.list();*/
//加入按照编号的顺序
singleLinkedList.addById(heroNode1);
singleLinkedList.addById(heroNode4);
singleLinkedList.addById(heroNode3);
singleLinkedList.addById(heroNode2);
singleLinkedList.list();
//显示按添加排名显示出来
}
}
//定义SingleLinkedList
class SingleLinkedList{
//先初始化一个头结点,头结点不要动,不存放具体的数据
private HeroNode head = new HeroNode(null);
//添加节点到单向链表
//思路:当不考虑编号顺序是
//1、找到当前链表的最后节点
//2、将最后这个节点的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;
}
public void addById(HeroNode heroNode){
//因为头结点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
//因为单链表,我们找到temp的位置时位于添加位置的前一个节点,否则插入不了
HeroNode temp = head;
while (true){
if (temp.next==null){
break;
}
if (temp.next.stu.id>heroNode.stu.id){
break;
}
temp = temp.next;
}
heroNode.next = temp.next;
temp.next = heroNode;
}
//显示链表(遍历)
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);
//将next后移,不后移会是死循环
temp = temp.next;
}
}
}
class Student{
public int id;
public String name;
public int age;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"no=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public int getNo() {
return id;
}
public void setNo(int no) {
this.id = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(int no, String name, int age) {
this.id = no;
this.name = name;
this.age = age;
}
}
//定义HeroNode,每个HeroNode对象就是一个节点
class HeroNode{
public Student stu;
public HeroNode next;
public HeroNode(Student stu) {
this.stu = stu;
}
@Override
public String toString() {
return "HeroNode{" +
"stu=" + stu +
'}';
}
}
-
普通添加效果图:

-
加入自动排序效果图:

-
修改:根据编号修改
public void updata(HeroNode heroNode){
if (head.next==null){
System.out.println("链表为空!");
return;
}
HeroNode temp = head.next;
boolean falg = false;
while (true){
if(temp==null){
break;
}
if (temp.stu.id==heroNode.stu.id){
falg = true;
break;
}
temp = temp.next;
}
if (falg){
temp.stu.name = heroNode.stu.name;
temp.stu.age = heroNode.stu.age;
}else{//没有找到
System.out.println("没有找到编号为"+heroNode.stu.id+"的节点");
}
}
显示效果:

- 节点的删除
- 辅助变量找到节点的上一个节点
- temp.next = temp.next.next
- 被删除的节点,不会有其它引用指向,将会被垃圾回收机制回收
代码:
public void delete(int id){
HeroNode temp = head;
boolean flag = false;//标识是否找到删除节点
while (true){
if (temp.next == null){
break;
}
if (temp.next.stu.id == id){
flag = true;
break;
}
temp = temp.next;
}
if (flag){
temp.next = temp.next.next;
}else {
System.out.println("要删除的"+id+"不存在");
}
}
效果图:

3.3 双向链表
3.3.1 双向链表介绍
- 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表
- 结构图

- 双向链表即每个节点有前置域和后置域。前置域指向上一个节点。后置节点指向下一个节点。
3.3.2 双向链表的添加
- 新节点的前置next域指向temp
- temp.next=新的节点
- 示意图

- 代码
public void add(DuLink duLink){
//因为head节点不能动,因此我们需要一个辅助遍历temp
DuLink temp = head;
//遍历链表,找到最后
while (true){
//找到链表的最后
if (temp.next==null){
break;
}
//如果没有找到最后,将temp后移
temp = temp.next;
}
//当退出while循环是,temp就指向了链表的最后
//将最后这节点的next指向新的节点
duLink.pro = temp;
temp.next = duLink;
}
3.3.3 双向链表的插入
- 双向链表的插入共四步,且有些顺序不能颠倒:
- 第一步:先把temp的下一个指向的节点先引用到新节点中。
- 第二步:将temp的next引用于新节点

public void headAdd(DuLink duLink){
//如果只有头结点
if(head.next==null){
head.next=duLink;
duLink.pro=head;
}else{
head.next.pro = duLink;
duLink.next = head.next;
head.next=duLink;
duLink.pro=head;
}
}
/**双向链表添加-尾插法*/
public void tailAdd(DuLink duLink){
DuLink temp = head;
while(true){
if(temp.next==null){
break;
}
temp = temp.next;
}
temp.next=duLink;
duLink.pro=temp;
}
3.3.4 双向链表的删除
- temp.next.pro = temp.pro;
- temp.pro.next = temp.next;
- 代码
/**双向链表的删除
* 删除某一学号的节点*/
public void delete(int no){
if(head.next==null){
System.out.println("列表为空");
return;
}
boolean flag=false;
DuLink temp = head.next;
while(true){
if(temp.stu.getNo()==no){
flag=true;
break;
}
if(temp.next==null){
flag=false;
break;
}
temp = temp.next;
}
if (flag){
temp.next.pro = temp.pro;
temp.pro.next = temp.next;
}else {
System.out.println("找不到学号为:"+no+"的节点");
}
}
3.3.5 双向链表的查询
/**双向链表的遍历*/
public void duLinkList(){
if(head.next==null){
System.out.println("列表为空");
return;
}
DuLink temp = head;
while(true){
if(temp.next==null) {
break;
}
temp = temp.next;
System.out.println(temp.toString());
}
}
3.3.6 双向链表的插入
/**双向链表的插入
* 插入到某个学号的后面*/
public void insert(DuLink duLink,int no){
if(head.next==null){
System.out.println("列表为空");
return;
}
boolean flag=false;
DuLink temp = head.next;
while(true){
if(temp.stu.getNo()==no){
flag=true;
break;
}
if(temp.next==null) {
break;
}
temp = temp.next;
}
if(flag){
temp.next.pro = duLink;
duLink.next = temp.next;
temp.next=duLink;
duLink.pro=temp;
}else {
System.out.println("找不到学号为:"+no+"的节点");
}
}
3.3.7 双向链表的修改
/**双向链表的修改
* 修改学好的全部数据*/
public void updata(Student stu,int no){
if(head.next==null){
System.out.println("列表为空");
return;
}
boolean flag=false;
DuLink temp = head.next;
while(true){
if(temp.stu.getNo()==no){
flag=true;
break;
}
if(temp.next==null){
flag=false;
break;
}
temp = temp.next;
}
if (flag){
temp.stu=stu;
}else {
System.out.println("找不到学号为:"+stu.getNo()+"的节点");
}
}
本文详细介绍了链表的基础概念,包括单链表的创建、节点操作(添加、排序)、双向链表的结构与操作(插入、删除、查询),并展示了实际代码示例。重点讲解了按学号自动排序和节点修改功能。

1万+

被折叠的 条评论
为什么被折叠?



