你真的会实现懂单向链表嘛?此文章教你手打一个单向链表

本文详细介绍了单链表的概念、类结构,包括哨兵节点的使用、如何在头尾插入和删除节点,以及根据索引获取和插入值的方法。
摘要由CSDN通过智能技术生成

什么是链表

  1. 链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,有一系列结点(地址)组成,结点可动态的生成。

  2. 结点包括两个部分:

    (1)存储数据元素的数据域(内存空间) 。

    (2)存储指向下一个结点地址的指针域 。

  3. 链表分为 :

    (1)单链表

    (2)双链表

    (3)单向循环链表

    (4)双向循环链表

本文就介绍一下如何编写一个单链表 ! ! !

类结构

大致样子

这是单向链表的大致样子 , Sentinel节点就是用于标识一个头节点的作用

在这里插入图片描述

代码写出一个节点的样子

public class SinglyLinkedList {
    // 哨兵节点,本身的值只作为一个标识,无其他实际意义,初始状态下一个节点为空
    private Node head = new Node(-1, null);

    // 内部类, 对使用者隐藏了内部的实现, 使用者只需要知道SinglyLinkedList即可
    private static class Node {
        int value;  // 存储数据的空间
        Node next;  // 指向下一个节点的指针

        public Node(int value, Node next) {
            this.value = value;
            this.next = next;
        }
    }
}

上面这串代码注意点很多喔 !!!

  1. Node类采用了内部类的实现方式 , 对使用者来说, 无需再调用Node类, 只需专注于使用SinglyLinkedList类即可
  2. 哨兵节点的存在只是作为一个标识, 也叫做哑元 , 用于简化链表边界的判断
  3. private修饰是必须存在的, 用于保护链表的数据安全性

addFirst方法(头节点插入)

在这里插入图片描述

需要改动的只有两个地方

  • 哨兵节点的next指向
  • 新插入节点的next指向

这就是链表插入数据效率快的情况及原因

    public void addFirst(int value){
        //存在两种情况, 根据哨兵节点的下一个节点进行判断
        Node next = head.next;
        Node newNode=null;
        //链表为空
        if (next==null){
            //直接把哨兵节点的下一个节点指向新创建的节点,新创建的节点的next节点为空
            newNode=new Node(value,null);
        }
        //链表非空
        else {
            //同样把哨兵节点的下一个接待你指向新创建的节点,只是新创建的next节点指向上一个头节点
            newNode=new Node(value,next);
        }
        head.next=newNode;
    }

loop方法(遍历链表)

在这里插入图片描述

这里采用了链表之外的节点pointer , 来记录这些需要遍历的节点

    public void loop(Consumer<Integer> consumer){
        for (Node pointer=head.next;pointer!=null;pointer=pointer.next){
            //这里采用了函数式接口, 让使用者完成方法的逻辑处理, 我们只是规定了使用者只能操作的内容
            consumer.accept(pointer.value);
        }
    }

addLast(尾节点插入)

在这里插入图片描述

需要改动的只有两个地方

  • 原尾节点的next指针指向新的节点
  • 新插入节点的next指向null

这就是链表插入数据效率慢的情况及原因, 因为链表越长 , 则链表的遍历到最后一个节点需要花费的时间越久.

    public Node findLast(){
        if (head.next==null){
            return null;
        }
        Node pointer;
        for ( pointer=head.next;pointer.next!=null;pointer=pointer.next){
            //此处只是为了让pointer指针到最后一个元素
        }
        return pointer;
    }
    public void addLast(int value){
        Node last = findLast();
        if (last==null){
            System.out.println("此时为空链表");
            head.next=new Node(value,null);
        }else {
            last.next=new Node(value,null);
        }
    }

get方法(根据索引获取节点的值)

此处使用了i变量与index的值进行比较遍历, 方便获取值

    public int get(int index){
        int i=0;
        for (Node pointer=head.next;pointer!=null;pointer=pointer.next,i++){
            if (index==i){
                return pointer.value;
            }java
        }
        return -1;
    }

insert(根据索引插入节点)

只需三件事

  1. 找目标索引上一个节点的位置
  2. 新插入的节点做为上一个节点的next
  3. 新插入的节点的next为原索引的值
    public Node findByIndex(int index){
        int i=0;
        for (Node pointer=head.next;pointer!=null;pointer=pointer.next,i++){
            if (index==i){
                return pointer;
            }
        }
        return null;
    }

    public void insert(int index,int value){
        Node byIndex = findByIndex(index-1);
        if (byIndex==null){
            head.next=new Node(value,null);
        }
        byIndex.next=new Node(value,findByIndex(index));
    }

remove(根据索引删除节点)

此处做了一个判断, 对头节点的情况进行了处理, 其他步骤依然是完成next指针的改变.

对于原节点不需要担心, Java会自动垃圾回收没有被引用的对象.

    public int remove(int index){
        if (index==0){
            Node byIndex = findByIndex(0);
            head.next=findByIndex(1);
            return byIndex.value;
        }
        Node byIndex = findByIndex(index-1);
        Node node = findByIndex(index);
        byIndex.next=node.next;
        return node.value;
    }

测试结果符合预期的结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木 木 水.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值