Java中的单向链表详解

 更新时间:2024年01月17日 10:37:33   作者:java-zh  
这篇文章主要介绍了Java中的单向链表详解,单向链表又叫单链表,是链表的一种,由节点构成,head指针指向第一个称为表头节点,而终止指向最后一个null指针,需要的朋友可以参考下

概述

单线链表:单向链表又叫单链表,是链表的一种。由节点构成,head指针指向第一个称为表头节点,而终止指向最后一个null指针

特点

  • 链表连接的方向都是单向的
  • 链表的访问要通过顺序从头部开始
  • 链表是使用指针进行构造的列表
  • 是由一个一个节点组成的链表,又称为节点链表
  • 每个节点都有指针成员变量指向链表中的下个节点

结构

可以比喻成火车,head是火车头data是火车厢,每一个火车厢的车厢next都拉着一个下一个车厢

优点

  • 单个节点的创建非常方便(增)
  • 节点的删除非常方便,不需要线性结构那样移动数据(删)

缺点

  • 只能冲头到位遍历,只能后续,无法找到前驱,也就是只能前进
  • 查询时搜索遍历需要遍历整个链表,在不好的情况下,可能需要道链尾才能找到
  • 链表需要维护next域,暂用内存

案例

创建一个单向列表

public class Node {
    //存储节点的值
    int val;
    //下一个节点地址
    Node next;
    public Node(int val) {
        this.val = val;
    }
    public Node(int val, com.study.data.linked.Node next) {
        this.val = val;
        this.next = next;
    }
}

测试

1、插头法,从头部上添加数据

输出结果:5->4->3->3->2->NULL

public class NodeTest {
    //实际存储的个数,相当于火车车厢的个数
    private int size;
    //第一个节点,相当于火车头
    private Node head;
    /**
     * 用来展示链表
     *
     * @return
     */
    public String showNode() {
        StringBuilder ret = new StringBuilder();
        Node node = head;
        while (node != null) {
            ret.append(node.val).append("->");
            // 继续访问下一节车厢
            node = node.next;
        }
        ret.append("NULL");
        return ret.toString();
    }
    //在头部上增加链数据(插头罚),如果链表为空,那么就是增加火车头
    public void addFirst(int data) {
        //要向链表中添加节点,要判断当前的链表是否为空,如果一个都没有,那么就要插入第一个节点
        Node node = new Node(data);
        if (size == 0) {
            head = node;
            size++;
        } else {
            //当前的火车已经存在节点了
            // 头部为上一个节点
            node.next = head;
            head = node;
            size++;
        }
    }
    public static void main(String[] args) {
        NodeTest test = new NodeTest();
        test.addFirst(2);
        test.addFirst(3);
        test.addFirst(3);
        test.addFirst(4);
        test.addFirst(5);
        System.out.println(test.showNode());
    }
}

2、插尾法(从尾部开始插入数据)

输出结果:2->3->3->4->5->NULL

public class NodeTest {
    //实际存储的个数,相当于火车车厢的个数
    private int size;
    //第一个节点,相当于火车头
    private Node head;
    /**
     * 用来展示链表
     *
     * @return
     */
    public String showNode() {
        StringBuilder ret = new StringBuilder();
        Node node = head;
        while (node != null) {
            ret.append(node.val).append("->");
            // 继续访问下一节车厢
            node = node.next;
        }
        ret.append("NULL");
        return ret.toString();
    }
    //插尾法,从尾部开始添加数据
    public void addLast(int data) {
        //要向链表中添加节点,要判断当前的链表是否为空,如果一个都没有,那么就要插入第一个节点
        Node node = new Node(data);
        if (size == 0) {
            head = node;
            size++;
        } else {
            //当前的火车已经存在节点了
            Node last = head;
            while (last.next != null) {
                last = last.next;
            }
            // 头部为上一个节点
            last.next = node;
            size++;
        }
    }
    public static void main(String[] args) {
        NodeTest test = new NodeTest();
        test.addLast(2);
        test.addLast(3);
        test.addLast(3);
        test.addLast(4);
        test.addLast(5);
        System.out.println(test.showNode());
    }
}

 3、在链表的中间插入位置

输出结果:5->4->4->3->3->2->NULL

图片详解

代码实现

 //在链表的中间插入位置
    public void addIndex(int index, int data) {
        //判断边界条件,判断index的合法性
        if (index < 0 || index > size) {
            System.out.println("插入链表位置失败....");
            return;
        }
        if (index == 0) {
            // 从链表的头部开始插入
            addFirst(data);
            return;
        }
        //说明此时index合法,并且时在中间这个位置,此时需要知道index的前驱节点,单链表只能从前往后遍历
        //将要插入的链表值添加进去
        Node node = new Node(data);
        //获取到整个链表值
        Node result = head;
        for (int i = 0; i < index - 1; i++) {
            //移除大于index-1的头部数据
            result = result.next;
        }
        //将上面尾巴数据赋值过去,要注意这里时next,所以实际上是head的next,比如4 0 1 ,next的话是0 1
        //node的数据还是刚刚添加的数据,这个时候就会变成了data+result.next的数据
        node.next = result.next;
        //将result中的next对node进行替换,上面的node已经完成了拼接
        result.next = node;
        size++;
    }
    public static void main(String[] args) {
        NodeTest test = new NodeTest();
        test.addFirst(2);
        test.addFirst(3);
        test.addFirst(3);
        test.addFirst(4);
        test.addFirst(5);
        test.addIndex(2,4);
        System.out.println(test.showNode());
    }

4、获取下标中的数据

输出结果:4

 // 查询index节点上的数据
    public int get(int index) {
        if (index < 0 || index >= size) {
            System.out.println("获取链表位置index值失败...");
            return -1;
        }
        //获取到前一个节点
        Node node = head;
        for (int i = 0; i < index; i++) {
            node = node.next;
        }
        return node.val;
    }
    public static void main(String[] args) {
        NodeTest test = new NodeTest();
        test.addFirst(2);
        test.addFirst(3);
        test.addFirst(3);
        test.addFirst(4);
        test.addFirst(5);
        System.out.println(test.showNode());
        System.out.println("获取节点1的数据" + test.get(1));
    }

5、对链表中某个值进行替换

输出结果:5->4->0->3->2->NULL

//对下标的某个值进行替换
    public int set(int index, int data) {
        if (index < 0 || index >= size) {
            System.out.println("修改单链表中的数据失败");
            return -1;
        }
        Node node = head;
        for (int i = 0; i < index; i++) {
            node = node.next;
        }
        //需要替换位置的值
        int oldData = node.val;
        // 进行值替换
        node.val = data;
        return oldData;
    }
 
    public static void main(String[] args) {
        NodeTest test = new NodeTest();
        test.addFirst(2);
        test.addFirst(3);
        test.addFirst(3);
        test.addFirst(4);
        test.addFirst(5);
        test.set(2,0);
        System.out.println(test.showNode());
    }

6、判断链表是否包含某个值

输出:true

// 判断链表中是否包含元素data
    public boolean contains(int data) {
        Node node = head;
        while (node != null) {
            if (node.val == data) {
                System.out.println("找到了元素" + data);
                return true;
            }
            node = node.next;
        }
        System.out.println("没有找到元素" + data);
        return false;
    }
 
    public static void main(String[] args) {
        NodeTest test = new NodeTest();
        test.addFirst(2);
        test.addFirst(3);
        test.addFirst(3);
        test.addFirst(4);
        test.addFirst(5);
        System.out.println(test.contains(5));
        System.out.println(test.showNode());
    }

7、移除链表中第一个值

输出结果:4->3->3->2->NULL

//移除第一个值    public void removeFirst() {        if (size == 0) {            return;        }        Node node = head;        head = node.next;        node.next = null;        size--;    }    public static void main(String[] args) {        NodeTest test = new NodeTest();        test.addFirst(2);        test.addFirst(3);        test.addFirst(3);        test.addFirst(4);        test.addFirst(5);        test.removeFirst();        System.out.println(test.showNode());    }

8、通过下标移除对应的值

输出结果:5->4->3->2->NULL

//通过下标移除值
    public void removeIndex(int index) {
        if (index < 0 || index > size) {
            System.out.println("通过下标移除失败,下标异常");
        }
        if (index == 0) {
            removeFirst();
        } else {
            Node node = head;
            for (int i = 0; i < index - 1; i++) {
                node = head.next;
            }
            // node是待删除的头部节点,del就是你要删除的节点
            Node del = node.next;
            //将两个节点给连接起来
            node.next = del.next;
            del.next = null;
            size--;
        }
    }
 
    public static void main(String[] args) {
        NodeTest test = new NodeTest();
        test.addFirst(2);
        test.addFirst(3);
        test.addFirst(3);
        test.addFirst(4);
        test.addFirst(5);
        test.removeIndex(2);
        System.out.println(test.showNode());
    }

9、删除指定元素的第一个节点

输出:5->4->3->2->NULL

//删除指定元素的第一个节点
    public void removeValueFirst(int data) {
        //先判断头节点情况,看看头节点是不是正好等于待删除节点
        if (head.val == data) {
            removeFirst();
        } else {
            //先找到待删除的节点
            Node node = head;
            while (node.next != null) {
                //找到待删除节点,找到了以后可以直接删除
                if (node.next.val == data) {
                    Node del = node.next;
                    node.next = del.next;
                    del.next = null;
                    size--;
                    break;
                } else {
                    node = node.next;
                }
            }
        }
    }
 
    public static void main(String[] args) {
        NodeTest test = new NodeTest();
        test.addFirst(2);
        test.addFirst(3);
        test.addFirst(3);
        test.addFirst(4);
        test.addFirst(5);
        test.removeValueFirst(3);
        System.out.println(test.showNode());
    }

10、删除链表中的所有节点

输出结果:5->4->2->NULL

//删除链表中包含值的所有节点
    public void removeValueAll(int data) {
        //判断头节点
        while (head != null && head.val == data) {
            removeFirst();
        }
        if (head == null) {
            System.out.println("当前节点已经为空了!");
            return;
        }
        //头节点处理完毕,并且链表不等于空
        Node node = head;
        while (node.next != null) {
            //12345
            if (node.next.val == data) {
                Node del = node.next;
                node.next = del.next;
                del.next = null;
                size--;
 
            } else {
                node = node.next;
            }
        }
 
    }
 
    public static void main(String[] args) {
        NodeTest test = new NodeTest();
        test.addFirst(2);
        test.addFirst(3);
        test.addFirst(3);
        test.addFirst(4);
        test.addFirst(5);
        test.removeValueAll(3);
        System.out.println(test.showNode());
    }

到此这篇关于Java中的单向链表详解的文章就介绍到这了,更多相关Java单向链表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Maven build 命令介绍的使用详解

    Maven build 命令介绍的使用详解

    这篇文章主要介绍了Maven build 命令介绍的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Java中的private、protected、public和default的区别(详解)

    Java中的private、protected、public和default的区别(详解)

    下面小编就为大家带来一篇Java中的private、protected、public和default的区别(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-11-11
  • SpringBoot集成drools的实现示例

    SpringBoot集成drools的实现示例

    本文主要介绍了SpringBoot集成drools的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Java8 Optional的详细使用教程

    Java8 Optional的详细使用教程

    这篇文章主要给大家介绍了关于Java8 Optional的详细使用教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • Spring Boot 项目搭建教程及注解

    Spring Boot 项目搭建教程及注解

    下面小编就为大家带来一篇Spring Boot 项目搭建教程及注解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Java实现心跳机制的方法

    Java实现心跳机制的方法

    这篇文章主要介绍了Java实现心跳机制的方法,文中讲解非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • 基于java HashMap插入重复Key值问题

    基于java HashMap插入重复Key值问题

    这篇文章主要介绍了基于java HashMap插入重复Key值问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Java猜数字游戏从思路到实现开发全过程

    Java猜数字游戏从思路到实现开发全过程

    猜数字游戏虽然简单,却涵盖了程序设计的基本要素,数据处理、流程控制、用户交互和异常处理,这篇文章主要介绍了Java猜数字游戏从思路到实现开发的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-10-10
  • Spring Web项目spring配置文件随服务器启动时自动加载

    Spring Web项目spring配置文件随服务器启动时自动加载

    这篇文章主要介绍了Spring Web项目spring配置文件随服务器启动时自动加载,加载spring的配置文件,并且只加载一次,从而提高程序效率。具体内容详情大家通过本文一起学习吧
    2018-01-01
  • 使用Sentinel自定义返回和实现区分来源方式

    使用Sentinel自定义返回和实现区分来源方式

    这篇文章主要介绍了使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04

最新评论