Java之单链表篇!!! (无头单向非循环链表实现打印、头插、尾插、任意插入、查找、删除某一关键字、删除所有所选关键字、清空单链表等基本操作)

概念

首先对单链表的结构进行介绍,单链表是由很多个节点一个接一个串接起来的,每个节点包含两部分,数据部分和地址部分,我们这里讲的是无头的单链表,所以没有头节点,每个节点存储的是本身的数据和下一个节点的地址。
在这里插入图片描述
如图,每个节点对应下面的地址。那第一个节点的地址设置为0x111,节点中存储的数据为1,存储的下一个节点的地址为0x22,直到最后一个节点因为后面没有节点了所以存储的地址为null(空)。

对于单链表的操作具体有以下一些步骤,(单链表是一种类型,也是由一个一个的节点构成,所以我们在进行所有的操作的时候,首先定义一个节点类,这类呢要包括图上所示的数据、next两个属性,注:next保存地址,所以是一个引用)
在这里插入图片描述
在这里插入图片描述
== 定义的Node模板如下,整个单链表都是由一个一个的Node节点串接在一起==

在这里插入图片描述
刚开始的单链表是没有任何数据的,就像是一张白纸什么也没有,也没有地址,所以随用随插。
在这里插入图片描述

操作

1、 单链表的打印

在这里插入图片描述
首先定义一个引用类型cur,使其等于head,这时cur就指向了第一个节点,那cur=cur.next是把第一个节点中存储的第二个节点的地址赋给cur,以此类推直到cur为空,打印完最后一个节点。
拿上图举例。第一个节点的地址为0x111,head指向第一个节点的地址,使cur=head后cur中就是0x111第一个节点的地址,cur.next此时为0x222就是第二个节点的地址,cur=cur.next,就是将第二个节点的地址放入cur,此时cur中为0x222,以此类推直到cur中为空。

在这里插入图片描述

public void disPlay(){
        Node cur = this.head;
        while(cur!=null){
            System.out.print(cur.getData()+" ");
            cur = cur.getNext();
        }
    }

2、头插法

在这里插入图片描述
头插法,首先利用构造方法new一个新的节点,之后呢将原来的第一个定义为head的节点的地址放到刚刚新的节点的next中,然后 使原来指向第一个节点的head,现在指向新的第一个节点。

由上图的例子,新建一个节点node地址为0x456,里面的数据为5,然后将原来的第一个节点的地址0x111放入刚刚的新节点中(即node.next=0x111),这样就可以让现在的新节点指向原来的第一个节点,之后让原来指向第一个节点的head现在指向新的地址为0x456的节点,这样就实现了头插法。

当然上述情况是在单链表本来就有节点的情况下,那样就可以直接在第一个节点之前插入,但是如果一开始单链表为空的话,那就要添加判断条件让head直接指向我们新new的节点,这样我们所new的节点就直接为第一个节点。
在这里插入图片描述

 public void addFirst(int data){
        Node node = new Node(data);
        if(this.head == null){
            //单链表中无节点
            this.head = node;
            return;
        }

        node.setNext(this.head);
        this.head = node;

    }

3、尾插法

在这里插入图片描述
尾插法,首先 new一个新的节点,之后呢定义一个引用cur,让cur指向head,开始一直遍历到最后直到cur.next为空,这个时候cur指向的就是最后一个节点然后 将新new的节点地址放入到cur之中,这样新的节点就成为新的尾节点。
在这里插入图片描述

 public void addLast(int data){
        Node node = new Node(data);
        if(this.head == null){
            //单链表中无节点
            this.head = node;
            return;
        }
        Node cur = this.head;
        while(cur.getNext()!=null){
            cur = cur.getNext();
        }
        //此时cur指向最后一个节点
        cur.setNext(node);
    }

4、在任意位置插入,第一个数据节点为0号下标

首先在插入的时候进行判断,判断index是否合法,之后如果index为0,则直接进行头插,如果 index等于单链表长度则直接进行尾插。
在这里插入图片描述

在这里插入图片描述
== 设置一个方法得到prev,prev指向index前一个节点的地址。==
在这里插入图片描述
注意:这里一定要如图先将index的地址放入新节点中,之后再将新节点的地址放入原index的前一个地址,如果顺序错误先进行3步骤则会丢失后面的数据。
下图中应为findIndex(index)
在这里插入图片描述
在这里插入图片描述

//在任意位置插入,第一个数据节点为0号下标
    public Node findIndex(int index){//找到prev
        int count = 0;
        Node cur = this.head;
        while (count < index-1){
            cur.setNext(cur.getNext());
            count++;
        }
        return cur;
    }
    public void addIndex(int index,int data){
        if(index<0||index>size()){
            throw new RuntimeException("输入位置不合法");
        }else if(index == 0){
            addFirst(data);
        }else if(index == size()){
            addLast(data);
        }else {
            Node node = new Node(data);
            Node prev = findIndex(index);
            node.setNext(prev.getNext());
            prev.setNext(node);
        }

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

    }

5、查找是否包含关键字key是否在单链表当中

在这里插入图片描述

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

6、删除第一次出现关键字为key的节点

删除关键字时首先要判断单链表之中是否存在这个关键字,其次判断这个关键字是否在第一个节点。之后按照常规的操作,先求出要删除的关键字的前驱

如下图中如果要删除2关键字就要求得存储2这个节点的前驱,将2这个节点的后继地址放入2的前驱的地址域就删除了2这个关键字节点。(这个地方存储1的节点不是第一个节点)
在这里插入图片描述
在这里插入图片描述

 //删除第一次出现关键字为key的节点
    private Node findPrev(int key){
        Node prev = this.head;
        while(prev.getNext()!=null){
            if(prev.getNext().getData() == key){
                return prev;
            }
            prev = prev.getNext();
        }
        return null;
    }
    public void remove(int key){
        if(this.head.getData() == key){
            this.head = this.head.getNext();
            return;
        }
        Node prev = findPrev(key);
        if(prev == null){
            System.out.println("没有这个节点!");
            return;
        }
        Node vel = prev.getNext();
        prev.setNext(vel.getNext());
    }

7、删除所有值为key的节点

一次性删除所有关键字key,首先定义两个引用prev和cur,cur为prev的后继,prev指向第一个节点,由下图举例,删除里面的所有的2,定义好两个引用之后,如果cur指向的节点的数值=2,则将cur向右移动即cur=cur.next,直到cur指向节点的数值不为2,如下图此时将值为4的节点地址放入prev的地址域,prev.next=cur,之后将prev移到cur位置,然后cur继续进行判断直到cur为空。当然如果第一个节点也需要删除的话只需添加判断条件之后将head指向下一个节点。
在这里插入图片描述
在这里插入图片描述

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

            }
            cur = cur.getNext();
        }
        if(this.head.getData() == key){
            this.head = this.head.getNext();
        }
    }

8、清空单链表

单链表的清空很简单,因为在单链表上储存的是对象。所以会存在内存泄漏,所以在不引用之后要对内存进行回收。

第一种:只要将指向第一个节点的head置空,这样就没有被引用的节点。

在这里插入图片描述

第二种:就是一个一个进行释放。

在这里插入图片描述
先利用循环将第一个节点之后的所有节点删除,定义del指向head.next,之后将dei.next放入head的next域之中,不断循环直到head的next域为空此时再最后删除第一个节点。
在这里插入图片描述

最后上代码!!!

class Node{
    private int data;
    private Node next; //利用引用类型储存地址,因为已经定义Node所以可以直接引用

    public Node(int data){
        this.data = data;
        this.next = null;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }


    public int getData() {
        return data;
    }
    public void setData(int data) {
        this.data = data;
    }
}
//组成单链表
 public class MyLineList {

    public Node head; //定义一个头节点
    public MyLineList(){
        this.head = null;       //设置头节点为空,也可以不设置
    }
    //打印单链表
    public void disPlay(){
        Node cur = this.head;
        while(cur!=null){
            System.out.print(cur.getData()+" ");
            cur = cur.getNext();
        }
    }
    //头插法
    public void addFirst(int data){
        Node node = new Node(data);
        if(this.head == null){
            //单链表中无节点
            this.head = node;
            return;
        }

        node.setNext(this.head);
        this.head = node;

    }
    //尾插法
    public void addLast(int data){
        Node node = new Node(data);
        if(this.head == null){
            //单链表中无节点
            this.head = node;
            return;
        }
        Node cur = this.head;
        while(cur.getNext()!=null){
            cur = cur.getNext();
        }
        //此时cur指向最后一个节点
        cur.setNext(node);
    }
    //在任意位置插入,第一个数据节点为0号下标
    public Node findIndex(int index){//找到prev
        int count = 0;
        Node cur = this.head;
        while (count < index-1){
            cur.setNext(cur.getNext());
            count++;
        }
        return cur;
    }
    public void addIndex(int index,int data){
        if(index<0||index>size()){
            throw new RuntimeException("输入位置不合法");
        }else if(index == 0){
            addFirst(data);
        }else if(index == size()){
            addLast(data);
        }else {
            Node node = new Node(data);
            Node prev = findIndex(data);
            node.setNext(prev.getNext());
            prev.setNext(node);
        }
    }
    public int size(){
        int count = 0;
        Node cur = this.head;
        while (cur!=null){
            count++;
            cur = cur.getNext();
        }
        return count;
    }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        Node cur = this.head;
        while (cur!=null){
            if(cur.getData() == key){
                return true;
            }
            cur = cur.getNext();
        }
        return false;
    }
    //删除第一次出现关键字为key的节点
    private Node findPrev(int key){
        Node prev = this.head;
        while(prev.getNext()!=null){
            if(prev.getNext().getData() == key){
                return prev;
            }
            prev = prev.getNext();
        }
        return null;
    }
    public void remove(int key){
        if(this.head.getData() == key){
            this.head = this.head.getNext();
            return;
        }
        Node prev = findPrev(key);
        if(prev == null){
            System.out.println("没有这个节点!");
            return;
        }
        Node vel = prev.getNext();
        prev.setNext(vel.getNext());
    }
    //删除所有值为key的节点
    public void removeAllKey(int key){
        Node prev = this.head;
        Node cur = prev.getNext();
        while(cur!=null){
            if(cur.getData() == key){
                prev.setNext(cur.getNext());
            }else{
                prev = cur;

            }
            cur = cur.getNext();
        }
        if(this.head.getData() == key){
            this.head = this.head.getNext();
        }
    }
    //清空单链表
    public void clear(){
        this.head = null;/*
        while(this.head.getNext()!=null){
            Node del = this.head.getNext();
            this.head.setNext(del.getNext());
        }
        this.head = null;*/
    }

}
class Demo{
    public static void main(String[] args) {
        MyLineList myLineList = new MyLineList();
        myLineList.addLast(1);
        myLineList.addLast(2);
        myLineList.addLast(3);
        myLineList.addLast(3);
        myLineList.addLast(3);
        myLineList.addLast(6);
        myLineList.addLast(7);
        myLineList.addFirst(10);
        myLineList.addIndex(2,99);
        System.out.println("三种方法插入后结果:");
        myLineList.disPlay();
        System.out.println();
        System.out.println("查找是否存在10这个数据");
        System.out.println(myLineList.contains(10));
        System.out.println("删除单链表里面的数据10之后:");
        myLineList.remove(10);
        myLineList.disPlay();
        System.out.println();
        System.out.println("删除单链表里面所有的3之后:");
        myLineList.removeAllKey(3);
        myLineList.disPlay();
        System.out.println();
        System.out.println("清空单链表之后打印:");
        myLineList.clear();
        System.out.println();
        myLineList.disPlay();
    }
}

测试:

class Demo{
    public static void main(String[] args) {
        MyLineList myLineList = new MyLineList();
        myLineList.addLast(1);
        myLineList.addLast(2);
        myLineList.addLast(3);
        myLineList.addLast(3);
        myLineList.addLast(3);
        myLineList.addLast(6);
        myLineList.addLast(7);
        myLineList.addFirst(10);
        myLineList.addIndex(2,99);
        System.out.println("三种方法插入后结果:");
        myLineList.disPlay();
        System.out.println();
        System.out.println("单链表长度:");
        System.out.println(myLineList.size());
        System.out.println("查找是否存在10这个数据");
        System.out.println(myLineList.contains(10));
        System.out.println("删除单链表里面的数据10之后:");
        myLineList.remove(10);
        myLineList.disPlay();
        System.out.println();
        System.out.println("删除单链表里面所有的3之后:");
        myLineList.removeAllKey(3);
        myLineList.disPlay();
        System.out.println();
        System.out.println("清空单链表之后打印:");
        myLineList.clear();
        System.out.println();
        myLineList.disPlay();
    }
}

在这里插入图片描述

计算单链表长度:

在这里插入图片描述

结果:

三种方法插入后结果:
10 99 1 2 3 3 3 6 7 
单链表长度:
9
查找是否存在10这个数据
true
删除单链表里面的数据10之后:
99 1 2 3 3 3 6 7 
删除单链表里面所有的3之后:
99 1 2 6 7 
清空单链表之后打印:
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值