前言
本篇文章是Java数据结构与算法系列的第三篇文章,经过前面两篇关于队列的学习之后,我们现在开始学习链表。
个人博客网站:http://lzmweb.cn,欢迎大家前来观看!
认识链表
链表是一种常用的数据结构,它是用于存储数据的。链表,顾名思义他就是一个表,而且数据是以链式存储的,通过各个节点连接起来,这样就成了一个链表。链表是一个有序的列表,一个链表中包含很多节点,每个节点都会有自己的数据域和next指针,next指针指向下一个节点。
链表的各个节点不一定是连续存储的,它是比较抽象的,通过next指针去连接。而链表分为单链表和双链表,下面我将会在本篇文章中详细介绍!
单链表
首先来认识下单链表,单链表其实就是一个单向的链表,如下图所示,链表中有一个头节点,头节点的next指向a1;a1中会有自己的数据,然后a1的next也会指向a2,后面以此类推,链表最后的a3的next就会指向null。
下面我们就开始去玩一下链表,我们使用链表去做一些简单的增删查改操作来了解链表。
- 首先创建一个节点类,节点类中必须有自己的值和next,每个对象就是一个节点。如下面的代码,定义了一个HeroNode,HeroNode中包含自己的属性值还有HeroNode类型的next变量,这个next就是用于指向下一个节点。
//定义一个HeroNode,每个对象就是一个节点
class HeroNode{
public int no;
public String name;
public String nickedName;
public HeroNode next;
public HeroNode(int no, String name, String nickedName) {
this.no = no;
this.name = name;
this.nickedName = nickedName;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickedName='" + nickedName + '\'' +
'}';
}
}
- 现在可以去写一些增删查改的方法了,首先是添加方法。写方法之前要先把头节点定义好,头节点是不能动的,不然整个链表就可能会产生变化。实现增加方法其实很简单,要先遍历整个链表。遍历使用一个临时节点去代替头节点,去辅助遍历,那么这里就定义了一个temp节点,再写一个while循环去遍历整个链表,如果temp.next == null的话就可以跳出循环了,因为已经找到了最后一个节点,否则就继续后移。最后退出while循环后就将temm.next = heroNode即可,这样就完成了添加。
//定义SingleLinkedList管理英雄
class SingleLinkedList{
//初始化头结点,头结点不能动,不用存放具体的数据
private HeroNode head = new HeroNode(0,"","");
//添加节点到单向链表
//不考虑编号顺序,找到当前链表的最后节点,将最后的节点的next指向新的节点
public void add(HeroNode heroNode){
HeroNode temp = head;//引用了head对象,辅助head
//遍历链表,找到最后
while (true){
//找到链表的最后
if (temp.next == null){
break;
}
//如果没有找到最后,那就将temp后移
temp = temp.next;
}
//当退出了while循环,temp已经找到了最后一个
temp.next = heroNode;
}
}
- 接下来开始写删除方法,删除方法是根据HeroNode中的no属性来进行删除的。实现删除的思路很简单,如下图所示,首先要先找到要删除的节点。那这个节点是怎么找到的呢?因为我们是要根据no来进行删除的,我们就需要找到眼删除的节点的前一个节点。如下图所示,假如我们要删除a2,那就要找到先找到a1的位置,判断条件是a1.next.no = no,这样就找到了位置。下一步就简单了,因为要删除的是a2,所以直接将a1指向a3即可,这样a2就会被垃圾回收机制回收,到这里就完成删除了。
代码实现:
//删除节点
public void delete(int no){
HeroNode temp = head;
boolean flag = false;//表示是否找到要删除的前一个节点
while (true){
if (temp.next==null){
break;
}
if (temp.next.no == no){
flag = true;//找到了
}
temp = temp.next;//后移
}
//判断flag
if (flag){//找到
temp.next = temp.next.next;
}else {
System.out.println("没找到该节点");
}
}
- 接下来完成修改方法,修改方法也很简单,首先根据传入的HeroNode节点的no去查找,然后再进行修改就行了,那么这里我就直接上代码就好了,因为实现起来也不难。
//根据no来修改
public void update(HeroNode heroNode){
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==heroNode.no){
flag = true;
break;
}
temp = temp.next;
}
//根据flag判断是否找到
if (flag){
temp.name = heroNode.name;
temp.nickedName = heroNode.nickedName;
}else {//没有找到
System.out.println("没有找到");
}
}
总结
单链表其实很简单,需要注意的地方就是在遍历的时候,记得使用一个临时头节点temp去代替head遍历。在下一篇文章中我会对单链表的内容进行扩展,介绍一些比较常见题目!