【javase基础】第十二篇:单链表框架搭建

👀作者简介:大家好,我是大杉。
🚩🚩 个人主页:爱编程的大杉
支持我:点赞+关注~不迷路🧡🧡🧡
✔系列专栏:javase基础⚡⚡⚡
(❁´◡`❁)励志格言:问题是怎样让工业的车轮继续转动,而又不增加世界上的财富。必须生产出货物来,却又必须不去将之分配。实践中,只能通过不断的战争才能达到这一目标。(from 《1984(纪念版)》)🤞🤞

在这里插入图片描述


一.单链表的构成及分类

1.构成

🔥🌀单链表由一个一个节点串联而成,每一个节点又由两部分组成,分为数字区域,和引用区域(存储下个节点的引用)
在这里插入图片描述

2.分类

分为带头节点的单链表和不带头节点的单链表
🌎带头节点的单链表
带头节点的单链表就是单独有一个节点作为整个单链表头,此时这个头的指向固定,永远为头部,不会被改变和删除
在这里插入图片描述🌎不带头节点的单链表

不带头节点的单链表中的头只是表示第一个节点,可以删除,删除后head指向下一个节点
在这里插入图片描述

3.代码搭建

明确一点:每一个节点都是一个对象

class Node
//自定义Node类型
{
    public int date;
    public Node next;
    public Node(int date)
    {
        this.date=date;
        this.next=null;
    }
}

二、头插法

🌎头插法顾名思义就是在单链表头节点的前面插入节点。

头插法时应该注意:是否是第一次插入。如果是第一次插入,此时单链表并没有节点元素。此时的head指向为空,只需将head指向插入的目标节点即可。

在这里插入图片描述🌎一定注意要先将node.next=this.head;因为如果先将head指向指向node则此时的头节点的位置已经发生改变,就会造成自己指向自己的情况,且会出现空指针异常
在这里插入图片描述

🌎代码实现

public void addFirst(int data)
    {
        Node node=new Node(data);
        if(this.head==null)
        {
            this.head=node;
            return;
            //void中的return只是使方法结束调用
        }
        node.next = this.head;
        this.head = node;

    }

三、尾插法

🌎尾插法就是在单链表末尾节点的后面插入节点

   public void addLast(int data)
    {
        Node node=new Node(data);
        Node cur=this.head;
        //没有节点时直接将head指向node
        if (this.head==null)
        {
            this.head=node;
            return;
        }
        //找到最后一个节点
        while (cur.next!=null)
        {
            cur=cur.next;
        }
        //最后一个节点的next域指向所要插入节点的引用
        cur.next=node;
    }

四.任意位置插入节点(遍历一遍)

🌎在任意位置要考虑是在头插入还是在尾插入,还是在中间部分插入。如果是在头或尾插入,直接调用上面的方法即可。如果是在中间插入,则需先找到插入位置的前一个节点,将前一个节点的next赋值给插入节点的next,再将前一个节点的next指向插入节点的引用
在这里插入图片描述

 //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data)
    {
        Node node=new Node(data);
        //头插
        if(index==0)
        {
            this.addFirst(data);
            return;
        }
        //尾插(size为求单链表长度的方法,下面会提到)
        if (index==this.size())
        {
            this.addLast(data);
            return;
        }
        //获得前一个节点的地址
        Node cur=searchIndex(index);
        //查找节点
        node.next=cur.next;
        cur.next=node;

    }
    private Node searchIndex(int index)
    {
        if(index<0||index>this.size())
        {
            throw new RuntimeException("index不合法");
        }
       Node cur=this.head;
     //在index位置插入,走index-1次可以走到它前一个节点
        while (index-1!=0)
        //从head开始运行index-1次找到index-1位置的引用
        {
            cur=cur.next;
            index--;
        }
        return cur;
    }

五.获得链表长度

在这里插入图片描述

 public int size()
    {
        int length=0;
        Node cur=this.head;
        while (cur!=null)
        {
            length++;
            cur=cur.next;
        }
        return length;

    }

六.查找关键字key是否在单链表当中

//查找是否包含关键字key是否在单链表当中
    public boolean contains(int key)
    {
        Node cur=this.head;
        while (cur!=null)
        {
            if (cur.date==key)
            {
                return true;
            }
                cur = cur.next;
        }
        return false;
    }

七.删除第一次出现关键字为key的节点

🌎要先找到所要删除节点的前一个节点,将前一个节点的next赋值为要删除节点的next,使它跳过要删除的节点直接指向下一个节点
在这里插入图片描述

public void remove(int key)
    {
    //head==null还没有添加节点,所以没有节点可以删除直接结束方法
        if (this.head==null)
        {
            return;
        }
        //第一个节点恰好是要删除的节点,直接让头节点后移指向下一个节点
        if(this.head.date==key)
        {
            this.head=this.head.next;
            return;
        }
        Node prev=getPrev(key);
        if (prev==null)
        {
            System.out.println("找不到此节点");
            return;
        }
        Node del=prev.next;
        prev.next=del.next;

    }
    private Node getPrev(int key)
    {
        Node prev=this.head;
        //prev.next==null的时候已经走到最后一个节点了,他后面没有节点了,
        //不可能是某个节点的前一个节点,无需再进入循环
        while (prev.next!=null)
        {
            if (prev.next.date==key)
            {
                return prev;
            }
            else
            {
                prev=prev.next;
            }
        }
        return null;
    }

八.删除所有值为key的节点(双指针思想)

前提:链表已经排好序

在节点已经排好序的情况下,相同的节点是紧挨着的。定义两个node(引用)类型,两两向后遍历。
在这里插入图片描述

//删除所有值为key的节点
    public void removeAllKey(int key)
    {
        Node prev=this.head;
        Node cur=this.head.next;
        while (cur!=null)
        {
            if (cur.date==key)
            {
            //删除cur
                prev.next=cur.next;
            }
            else
            {
            //向后推进
                prev=cur;
            }
            //向后推进
            cur=cur.next;
        }
        //排除头节点正好是要删除的节点的情况
        if (this.head.date==key)
        {
            this.head=this.head.next;
        }
    }

九.清除链表(jvm回收机制)

1.思路一:将所有的next域置为空(比较麻烦时间复杂度高)
2.思路二:直接将head.next置为空。
原因:jvm回收机制:jvm在回收内存的时候,当该对象没有人在引用他的时候。这个对象才会被回收。

在这里插入图片描述
将head置为空,下一个节点不被引用后被删除。下一个节点被删除,下下个节点就不会被引用进而被删除,这样会产生链式反应,将所有的节点删除。

十.功能整合


class Node
{
    public int date;
    public Node next;
    public Node(int date)
    {
        this.date=date;
        this.next=null;
    }
}
public class My_list {
    public Node head;
    //只是一个标识,第一次一开始什么也不指向,为null
    //第一次之后head不是null了已经指向新的node了
    //头插法
    public void addFirst(int data)
    {
        Node node=new Node(data);
        if(this.head==null)
        {
            this.head=node;
            return;
            //void中的return只是使方法结束调用
        }
        node.next = this.head;
        this.head = node;

    }
    //尾插法
   public void addLast(int data)
    {
        Node node=new Node(data);
        Node cur=this.head;
        if (this.head==null)
        {
            this.head=node;
            return;
        }
        while (cur.next!=null)
        {
            cur=cur.next;
        }
        cur.next=node;
    }
 //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data)
    {
        Node node=new Node(data);
        if(index==0)
        {
            this.addFirst(data);
            return;
        }
        if (index==this.size())
        {
            this.addLast(data);
            return;
        }
        //获得前一个节点的地址
        Node cur=searchIndex(index);
        //查找节点
        node.next=cur.next;
        cur.next=node;

    }
    private Node searchIndex(int index)
    {
        if(index<0||index>this.size())
        {
            throw new RuntimeException("index不合法");
        }
       Node cur=this.head;

        while (index-1!=0)
        //从head开始运行index-1次找到index-1位置的引用
        {
            cur=cur.next;
            index--;
        }
        return cur;
    }
//查找是否包含关键字key是否在单链表当中
    public boolean contains(int key)
    {
        Node cur=this.head;
        while (cur!=null)
        {
            if (cur.date==key)
            {
                return true;
            }
                cur = cur.next;
        }
        return false;
    }
    //得到单链表的长度
    public int size()
    {
        int length=0;
        Node cur=this.head;
        while (cur!=null)
        {
            length++;
            cur=cur.next;
        }
        return length;

    }
    private Node getPrev(int key)
    {
        Node prev=this.head;
        while (prev.next!=null)
        {
            if (prev.next.date==key)
            {
                return prev;
            }
            else
            {
                prev=prev.next;
            }
        }
        return null;
    }
//删除第一次出现关键字为key的节点
   public void remove(int key)
    {
        if (this.head==null)
        {
            return;
        }
        if(this.head.date==key)
        {
            this.head=this.head.next;
            return;
        }
        Node prev=getPrev(key);
        if (prev==null)
        {
            System.out.println("找不到此节点");
            return;
        }
        Node del=prev.next;
        prev.next=del.next;

    }
//删除所有值为key的节点
    public void removeAllKey(int key)
    {
        Node prev=this.head;
        Node cur=this.head.next;
        while (cur!=null)
        {
            if (cur.date==key)
            {
                prev.next=cur.next;
            }
            else
            {
                prev=cur;
            }
            cur=cur.next;
        }
        if (this.head.date==key)
        {
            this.head=this.head.next;
        }
    }

    public void display()
    {
        Node cur=this.head;
        while (cur!=null)
        {
            System.out.print(cur.date+" ");
            cur=cur.next;
        }

    }
    public void clear()
    {
        this.head=null;
    }
}

在这里插入图片描述

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 42
    评论
评论 42
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@Starry

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

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

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

打赏作者

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

抵扣说明:

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

余额充值