基本概念
单链表就是用一组任意的存储单元来存放线性表中的数据,链表中的数据是以节点来显示的,节点主要由数据域和指针域组成。数据域用于存放数据,指针域由于存放指向下一个节点的地址。
作用
为什么要使用链表?
主要原因就是我们在使用数组的时候,数组在内存中开辟的是一段连续的存储单元,但如果此时我们的电脑内存不够的情况下,我们就无法使用数组来存放数据了;此时,我们就可以使用链表来存储数据,因为内存中很多时候都会存在分散的存储单元,链表可以将内存中分散的存储单元利用起来,最大程度上地使用内存空间,提高内存空间的使用率。
代码实现
定义链表中的节点
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;
}
public HeroNode() {
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + "}";
}
}
定义一个类来维护链表
这里需要知道,单链表一般都会单独创建一个节点,该节点不存放数据,只用于指向链表中真正存放数据的第一个节点,该节点我们称为头结点,链表中真正存放数据的第一个节点成为首元节点。
class SingleLinkedList {
//定义链表的头节点
private HeroNode head = new HeroNode();
//返回头节点
public HeroNode getHead() {
return head;
}
}
接下来在 SingleLinkedList
类中添加关于链表的相关操作
//添加节点到链表的最后
public void addNodeToLast(HeroNode node) {
//不修改头节点,需要一个临时变量来存放 head
HeroNode temp = head;
while(true) {
//找到最后一个节点 next == null
if (temp.next == null) {
break;
}
//没有找到最后一个节点,让temp指向其后一个节点,再进行循环判断
temp = temp.next;
}
//退出循环后,temp就指向了链表的最后一个元素
//将最后一个节点next指向要添加的节点
temp.next = node;
}
//显示链表(遍历)
public void listLinkedList() {
//判断链表是否为空
if (head.next == null) {
System.out.println("当前链表为空");
return;
}
//定义一个临时变量存放head节点
HeroNode temp = head.next;
while (temp != null) { //如果head等于空,就无需再遍历
//输出节点信息
System.out.println(temp);
//temp后移一位
temp = temp.next;
}
}
//根据节点的编号插入节点到链表的指定位置
public void addByOrder(HeroNode node) {
HeroNode temp = head;
boolean flag = false; //flag用于标识要添加的编号是否已经存在,默认为false
//寻找要添加节点的前一个节点
while (true) {
if (temp.next == null) {
//遍历到最后一个节点
break;
}
if (temp.next.no > node.no) {
//找到要插入的位置的前一个节点:temp
break;
} else if (temp.next.no == node.no) {
//要添加的编号已经存在
flag = true;
break;
}
//temp后移
temp = temp.next;
}
//判断flag
if (flag) {
System.out.println("要添加的节点编号("+ node.no +")已存在~~");
return;
}
//插入到链表的后边,temp的后面
node.next = temp.next;
temp.next = node;
}
//将节点添加到指定位置
public void addToIndex(HeroNode node, int findIndex) {
HeroNode temp = head;
int index = 1;
//开始遍历
while(true) {
if (temp.next == null) {
//temp为最后一个节点
break;
}
if (index == findIndex) {
//找到要插入的位置
break;
}
//temp后移
temp = temp.next;
//位置后移
index++;
}
//添加节点到temp的后面
node.next = temp.next;
temp.next = node;
}
//修改节点信息,根据编号修改
public void update(HeroNode newNode) {
//判断队列是否为空
if (head.next == null) {
System.out.println("当前队列为空");
return;
}
HeroNode temp = head;
boolean flag = false; //是否找到该节点
while(true) {
if (temp == null) {
break; //已经遍历完链表
}
if (temp.no == newNode.no) {
//找到要修改的节点
flag = true;
break;
}
//temp后移,遍历
temp = temp.next;
}
//判断flag的值
if (flag) {
temp.name = newNode.name;
temp.nickName = newNode.nickName;
} else {
//没有找到
System.out.println("没有找到编号为" + newNode.no + "的节点");
}
}
//删除指定位置的节点
public void deleteByIndex(int findIndex) {
//判断链表是否为空
if (head.next == null) {
System.out.println("当前链表为空~~");
return;
}
int index = 1; //用来记录当前节点的前一个节点的位置,目前 1 代表 head节点
boolean flag = false; //标识是否找到节点
HeroNode temp = head;
//遍历链表,找到要删除位置节点的前一个节点
while(true) {
if (temp.next == null) {
//找到最后一个节点
break;
}
if (index == findIndex) {
//找到要删除节点的前一个结点
flag = true;
break;
}
//temp后移
temp = temp.next;
//位置后移
index++;
}
//判断flag的值,为真进行删除
if (flag) {
temp.next = temp.next.next;
} else {
System.out.println("该元素不存在");
}
}
在main方法中测试
public static void main(String[] args) {
//测试
HeroNode node1 = new HeroNode(1, "索尔", "雷神");
HeroNode node2 = new HeroNode(2, "罗伯特", "钢铁侠");
HeroNode node3 = new HeroNode(3, "韦恩", "蝙蝠侠");
HeroNode node4 = new HeroNode(4, "彼得", "蜘蛛侠");
SingleLinkedList singleLinkedList = new SingleLinkedList();
//添加到最后
// singleLinkedList.addNodeToLast(node1);
// singleLinkedList.addNodeToLast(node2);
// singleLinkedList.addNodeToLast(node3);
// singleLinkedList.addNodeToLast(node4);
//添加节点到指定位置
// singleLinkedList.addToIndex(node1, 1);
// singleLinkedList.addToIndex(node2, 1);
// singleLinkedList.addToIndex(node3, 2);
// singleLinkedList.addToIndex(node4, 2);
//按编号添加
singleLinkedList.addByOrder(node1);
singleLinkedList.addByOrder(node4);
singleLinkedList.addByOrder(node2);
singleLinkedList.addByOrder(node3);
singleLinkedList.listLinkedList();
System.out.println("----------------------------------");
//修改节点
singleLinkedList.update(new HeroNode(2, "托尼斯塔克", "钢铁侠"));
singleLinkedList.listLinkedList();
System.out.println("----------------------------------");
//删除节点
singleLinkedList.deleteByIndex(4);
singleLinkedList.listLinkedList();
System.out.println("节点个数:" + SingleLinkedList.getLength(singleLinkedList.getHead()));
}
测试结果
F:\Java\jdk-11\bin\java.exe "-javaagent:F:\IntelliJ IDEA 2022.1.2\lib\idea_rt.jar=55256:F:\IntelliJ IDEA 2022.1.2\bin" -Dfile.encoding=UTF-8 -classpath F:\java\代码\data-struct\queue\target\classes cn.hypig.linked.SingleLinkedListDemo
HeroNode{no=1, name='索尔', nickName='雷神}
HeroNode{no=2, name='罗伯特', nickName='钢铁侠}
HeroNode{no=3, name='韦恩', nickName='蝙蝠侠}
HeroNode{no=4, name='彼得', nickName='蜘蛛侠}
----------------------------------
HeroNode{no=1, name='索尔', nickName='雷神}
HeroNode{no=2, name='托尼斯塔克', nickName='钢铁侠}
HeroNode{no=3, name='韦恩', nickName='蝙蝠侠}
HeroNode{no=4, name='彼得', nickName='蜘蛛侠}
Process finished with exit code 0