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单向链表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java调用Hbase报错解决方法

    java调用Hbase报错解决方法

    这篇文章主要为大家介绍了java调用Hbase报错解决方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Android读取本地或网络图片并转换为Bitmap

    Android读取本地或网络图片并转换为Bitmap

    这篇文章主要为大家详细介绍了Android读取本地或网络图片,并转换为Bitmap,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • springboot如何获取相对路径文件夹下静态资源的方法

    springboot如何获取相对路径文件夹下静态资源的方法

    这篇文章主要介绍了springboot如何获取相对路径文件夹下静态资源的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-05-05
  • Spring Boot集成ElasticSearch实现搜索引擎的示例

    Spring Boot集成ElasticSearch实现搜索引擎的示例

    这篇文章主要介绍了Spring Boot集成ElasticSearch实现搜索引擎的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • Springboot整合Active消息队列

    Springboot整合Active消息队列

    这篇文章主要介绍了Springboot整合Active消息队列的步骤,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下
    2020-12-12
  • 最新log4j2远程代码执行漏洞(附解决方法)

    最新log4j2远程代码执行漏洞(附解决方法)

    Apache Log4j2 远程代码执行漏洞攻击代码,该漏洞利用无需特殊配置,经多方验证,Apache Struts2、Apache Solr、Apache Druid、Apache Flink等均受影响,本文就介绍一下解决方法
    2021-12-12
  • 一文详解SpringBoot Redis多数据源配置

    一文详解SpringBoot Redis多数据源配置

    Spring Boot默认只允许一种 Redis 连接池配置,且配置受限于 Lettuce 包,不够灵活,所以本文将为大家介绍如何自定义Redis配置方案实现多数据源支持,需要的可以参考下
    2024-11-11
  • Mybatis多线程下如何使用Example详解

    Mybatis多线程下如何使用Example详解

    这篇文章主要给大家介绍了关于Mybatis多线程下如何使用Example的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Mybatis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-12-12
  • Java中的8大基本数据类型详解

    Java中的8大基本数据类型详解

    这篇文章主要介绍了Java中8大基本数据类型的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • 微服务实战之怎样提升springboot服务吞吐量

    微服务实战之怎样提升springboot服务吞吐量

    这篇文章主要介绍了微服务实战之怎样提升springboot服务吞吐量方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08

最新评论