Java(十八)---单链表


前言

在上一篇文章中我们学习了ArrayList顺序表的相关操作和模拟实现,ArrayList顺序表的底层使用数组进行维护的,由于其底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低,因此ArrayList不适合做任意位置插入和删除比较多的场景。因此:java集合中又引入了LinkedList,即链表结构。


1.链表的概念及结构

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。
在这里插入图片描述

由上面的图我们可以得知:每种链表都是由一个一个节点组成的,主要分为三类 有无头节点,是否循环以及 是单向的还是双向的,一共8种类型。
其中我们只学习2类,第一类是无头非循环单向链表。
第二种是无头非循环双向链表(Java中自带的链表)
下来我们来模拟一下单链表的相关操作。

2.单链表的创建

功能实现:

//无头单向非循环链表实现
//头插法
public void addFirst(int data);
//尾插法
public void addLast(int data);
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data);
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key);
//删除第一次出现关键字为key的节点
public void remove(int key);
//删除所有值为key的节点
public void removeAllKey(int key);
//得到单链表的长度
public int size();
public void clear();
public void display();

我们把上述功能放在IList接口里面,即使是以后学到的LinkList(双向链表)也要实现这些功能,这样的话,只需要使用重写接口即可,不需要在将这些方法放到类中实现。
Llist接口

public interface IList {
    //无头单向非循环链表实现
    //头插法
    public void addFirst(int data);
    //尾插法
    public void addLast(int data);
    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data);
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key);
    //删除第一次出现关键字为key的节点
    public void remove(int key);
    //删除所有值为key的节点
    public void removeAllKey(int key);
    //得到单链表的长度
    public int size();
    public void clear();
    public void display();
}

节点的创建:

public class MySingleList {
    static class ListNode{
        public int val;
        public ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }   
}

然后连接接口

public class MySingleList implements IList {
    static class ListNode{
        public int val;
        public ListNode next;

        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head;
    @Override
    public void addFirst(int data) {

    }

    @Override
    public void addLast(int data) {

    }

    @Override
    public void addIndex(int index, int data) {

    }

    @Override
    public boolean contains(int key) {
        return false;
    }

    @Override
    public void remove(int key) {

    }

    @Override
    public void removeAllKey(int key) {

    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public void clear() {

    }

    @Override
    public void display() {

    }
}

3.功能的实现

3.1.创建链表(create)(需要自己创建)

第一次看这个方法,可能比较糙,先这样写,等会写到3种add方法的时候,再用高级的方法。为等会测试display,size()等方法,做铺垫

 public void create(){
        ListNode node = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(3);
        ListNode node4 = new ListNode(4);
        head = node;
        node.next = node2;
        node2.next = node3;
        node3.next = node4;
    }

3.2.显示链表(display)

显示链表(display)的逻辑和获取节点个数(size() )以及 是否包含指定元素的节点(contains)一样。
在进行循环链表的时候,我们一般会在创建一个节点(cur)来代替head,让cur去循环链表而不是让head循环链表。
在这里插入图片描述

public void display() {
        ListNode cur = head;
        while (cur != null){
            System.out.print(cur.val+" ");
            cur = cur.next;
        }
        System.out.println();
    }

3.3.获取链表的个数( size() )

跟上面的逻辑如出一辙

 public int size() {
        ListNode cur = head;
        int count = 0;
        while (cur != null){
            count++;
            cur = cur.next;
        }
        return count;
    }

3.4.是否包含指定元素(contains)

public boolean contains(int key) {
        ListNode cur = head;
        while (cur != null){
            if(cur.val == key){
                return true;
            }
            cur = cur.next;
        }
        return false;       
    }

3.5.头插法(addFirst)

在这里插入图片描述
在进行插入和删除的时候,一定要注意只有一个head节点的情况,可能会进行分类讨论。

public void addFirst(int data) {
        ListNode node = new ListNode(data);
        node.next = head;
        head = node;
    }

3.6.尾插法(addLast)

在这里插入图片描述

 public void addLast(int data) {
        ListNode node = new ListNode(data);
        if(head == null){
            head = node;
            return;
        }
        ListNode cur = head;
        while (cur.next != null){
            cur = cur.next;
        }
        cur.next = node;
    }

3.7.在指定位置进行插入(addIndex)

在这里插入图片描述

    public void addIndex(int index, int data) {
        int len = size();
        if (index < 0 || index > len){
            throw new CheckPos("位置不合法...");
        }
        if (index == 0){
            addFirst(data);
            return;
        }
        if (index == len){
            addLast(data);
            return ;
        }
        ListNode node = new ListNode(data);
        ListNode cur = head;

        while (index - 1 != 0){
            cur = cur.next;
            index-- ;
        }
        node.next = cur.next;
        cur.next = node;
    }

为了将不合规的位置特殊标出一下,使用了异常。

public class CheckPos extends RuntimeException{
    public CheckPos(){
        super();
    }
    public CheckPos(String s){
        super(s);
    }

}

3.8.删除出现在第一次的指定元素的节点(remove)

@Override
    public void remove(int key) {
        if(head == null) {
            return;
        }
        if(head.val == key) {
            head = head.next;
            return;
        }
        ListNode cur = NodeOfKey(key);
        ListNode del = cur.next;
        cur.next = del.next;
    }

在这里插入图片描述

3.9.删除全部出现指定元素的节点(removeAllKey)

要求只遍历1遍,就可以清除指定元素的节点。
可以使用两个变量进行操作 (prev.cur)
在这里插入图片描述

private ListNode NodeOfKey(int key){
        ListNode cur = head;
        while (cur != null){
            if (cur.next.val == key){
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }
public void removeAllKey(int key) {
        if(head == null){
            return;
        }
        ListNode prev = head;
        ListNode cur = head.next;
        while (cur != null){
            if (cur.val == key){
                prev.next = cur.next;
                cur = cur.next;
            }else{
                prev = cur;
                cur = cur.next;
            }
        }
        if (head.val == key){
            head = head.next;
        }
    }

3.10.清空链表

在这里插入图片描述

@Override
    public void clear() {
        ListNode cur = head;
        while(cur != null){
            ListNode curN = null;
            cur = null;
            cur = curN;
        }
        head = null;
    }

下一篇我们来讲几道关于单链表的题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值