良辰当五日,“双向链表”还 (Java篇)

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言

而是理解过并总结出来通俗易懂的大白话,

小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.

🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

前言

小伙伴是不是在此之前学习过单向链表,什么是单向链表呢

用我们的专业术语就是: 单向不带头不循环链表

如果还不熟悉的小伙伴们可以点击下方链接进行学习哦 💖 💖 💖

单链表详解链接

而今天的主角是我们的双向链表,什么是双向链表呢,请听下文分解 💥 💥 💥

目录

  1. LinkedList
  2. 双向链表的实现
  3. LinedList 和 ArrayList 的异同

一. LinkedList

1. LinkedList 的简介

LinkedList 的底层是 双向链表结构
由于链表没有将元素存储在连续的空间 中,元素存储在单独的 节点 中,然后通过引用将 节点 连接起来了,因此在在任意位置 插入 或者 删除 元素时,不需要 搬移元素 ,效率比较 高 。

并且在我们Java的集合框架中,LinkedList 也实现了 List 接口

鱼式疯言

LinkedList 这个类有以下五个特点

  1. LinkedList 实现了 List 接口
  2. LinkedList 的底层使用了 双向链表
  3. LinkedList 没有实现 RandomAccess 接口,因此 LinkedList 不支持随机访问
  4. LinkedList 的任意位置 插入 和 删除 元素时效率比较高,时间复杂度为 O(1)
  5. LinkedList 比较适合任意位置插入的场景

了解了什么是 LinkedList 之后

宝子们是不是和小编一样对这个链表很感兴趣呢

下面来详细说明下他怎么使用吧 💕 💕 💕

1. 尾插数据

java 复制代码
public class TestLinked {

    public static void main(String[] args) {
        List<String> list=new LinkedList<>();

        list.add("钟少爷");
        list.add("郭男神");
        list.add("刘富帅");
        list.add("杰哥哥");

    }
}

这里利用 add() 对 链表 直接进行 尾插 数据

2.指定 index 插入数据

java 复制代码
public class TestLinked {

    public static void main(String[] args) {
        List<String> list=new LinkedList<>();

        list.add("钟少爷");
        list.add("郭男神");
        list.add("刘富帅");
        list.add(1,"杰哥哥");

    }
}

用 Java 重载 的特性,形成了 两个参数列表不同 的 add(),但方法名同名的方法,从而指定 index 插入数据

鱼式疯言

LinkedList 的 add() 方法是返回值类型是 boolean 类型
当插入 成功 时返回的是 true
插入 失败 返回是 false

3.删除 index 的数据

java 复制代码
public class TestLinked {

    public static void main(String[] args) {
        List<String> list=new LinkedList<>();

        list.add("钟少爷");
        list.add("郭男神");
        list.add("刘富帅");
        list.add(1,"杰哥哥");

        System.out.println(list.remove(3)); // 删除 "刘富帅"
        System.out.println(list.remove(0)); // 删除 "钟少爷"

    }
}

利用 List类 中 remove() 可以 删除数据 并带出该数据的 返回值

4.得到 index 数据

java 复制代码
public class TestLinked {

    public static void main(String[] args) {
        List<String> list=new LinkedList<>();

        list.add("钟少爷");
        list.add("郭男神");
        list.add("刘富帅");
        list.add(1,"杰哥哥");

        System.out.println("====== 删除数据 ========");

        System.out.println(list.remove(3)); // 删除 "刘富帅"
        System.out.println(list.remove(0)); // 删除 "钟少爷"

        System.out.println("======= 获取数据 ========");

        System.out.println(list.get(0));  // "郭男神"
        System.out.println(list.get(1));  // "刘富帅"
    }
}

我们可以利用 get() 根据我们输入的 index 得到我们需要的 数据 💥 💥 💥

java 复制代码
public class TestLinked {

    public static void main(String[] args) {
        List<String> list=new LinkedList<>();

        list.add("钟少爷");
        list.add("郭男神");
        list.add("刘富帅");
        list.add("吴富婆");
        list.add(1,"杰哥哥");

        System.out.println("====== 删除数据 ========");

        System.out.println(list.remove(3)); // 删除 "刘富帅"
        System.out.println(list.remove(0)); // 删除 "钟少爷"

        System.out.println("======= 获取数据 ========");

        System.out.println(list.get(0));  // "郭男神"
        System.out.println(list.get(1));  // "刘富帅"


        System.out.println("========= 修改数据 =========");
        System.out.println(list.set(0, "彭于晏"));
        System.out.println(list.get(0));
    }
}

在此处我们可以通过 set() 修改 index 位置的值 , 并返回修改前 index 的值

5. 查找数据

java 复制代码
public class TestLinked {

    public static void main(String[] args) {
        List<String> list=new LinkedList<>();

        list.add("钟少爷");
        list.add("郭男神");
        list.add("刘富帅");
        list.add("吴富婆");
        list.add(1,"杰哥哥");

        System.out.println("====== 删除数据 ========");

        System.out.println(list.remove(3)); // 删除 "刘富帅"
        System.out.println(list.remove(0)); // 删除 "钟少爷"

        System.out.println("======= 获取数据 ========");

        System.out.println(list.get(0));  // "郭男神"
        System.out.println(list.get(1));  // "刘富帅"


        System.out.println("========= 修改数据 =========");
        System.out.println(list.set(0, "彭于晏"));
        System.out.println(list.get(0));


        System.out.println("=========查找数据=========");
        String s=new String("郭男神");
        if (list.contains(s)) {
            System.out.println("该数据的下标为:"+ list.indexOf(s));
        } else {
            System.out.println("未找到该数据,查找失败!");
        }
    }
}

在这段代码块中

我们通过 contains() 方法搜寻 LinkedList 是否含有该数据
如果存在就返回其 下标 值
不存在就打印 提示信息

鱼式疯言

contains 返回类型: Boolean ,
如果存在就返回 true
不存在就返回 false

说完了LinkedList 的主要方法,我们就不妨动手实现这个双向链表吧 💖 💖 💖

二.双向链表的实现

1. 基本框架

我们首先定义一个 内部类 ,我们可以通过 内部类 来实现我们的一个个 节点 的窗帘

java 复制代码
package linklist;
public class MyLinkedList extends AbLinkList{


    public static class  LinkedNode {
        public   LinkedNode prev;

        public  int val;
        public LinkedNode next;

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

并在 内部类 的前提下,我们有了前驱节点 prev 数据val 以及后驱节点 next

2.插入数据

<1>. 头插数据

java 复制代码
public void addFirst(int data) {
    LinkedNode node=new LinkedNode(data);
    if (isEmpty()) {
        head=last=node;
        return;
    }
    head.prev=node;
    node.next=head;
    head=node;

}

<2>. 尾插数据

java 复制代码
// 尾插数据
@Override
public void addLast(int data) {
    LinkedNode node=new LinkedNode(data);
    if (isEmpty()) {
        head=last=node;
        return;
    }

    last.next=node;
    node.prev=last;
    last=node;

}

<3>. index 插入数据

java 复制代码
public  void checkIndex(int index) throws IndexOutOfBoundsException{
    if (index<0 || index > size()) {
        throw  new IndexOutOfBoundsException("下标异常!");
    }
}



// 增加某位置的数据
@Override
public boolean addIndex(int index, int data) {
    try {
        checkIndex(index);
    } catch (IndexOutOfBoundsException e) {
        e.printStackTrace();
        return false;
    }

    if (index==0) {
        addFirst(data);
        return true;
    }

    if (index==size()) {
        addLast(data);
        return true;
    }
    LinkedNode cur=head;
    LinkedNode node=new LinkedNode(data);
    for (int i = 0; i < index; i++) {
        cur=cur.next;
    }


    cur.prev.next=node;
    node.prev=cur.prev;
    cur.prev=node;
    node.next=cur;

    return true;
}

3. 查找数据

java 复制代码
    // 坚持是否包含 key
    @Override
    public boolean contains(int key) {

        LinkedNode cur=head;
        for (int i = 0; i < size(); i++) {
            if (cur.val==key) {
                return true;
            }
            cur=cur.next;
        }

        return false;
    }

4. 删除数据

<1>. 移除 key 一个数据

java 复制代码
    // 移除一个 key 数据
    @Override
    public boolean remove(int key) {
        if (isEmpty()) {
            return false;
        }

        if (head.val==key) {
//            head.val=null;
            head=head.next;
            head.prev=null;
            return true;
        }

        if (last.val==key) {
//            last.val=null;
            last=last.prev;
            last.next=null;
            return true;
        }

        LinkedNode cur= head;
        while (cur !=null) {
            if (cur.val==key) {
//                cur.val=null;
                cur.prev.next=cur.next;
                cur.next.prev=cur.prev;
                return true;
            }

            cur=cur.next;

        }

        return false;
    }

<2>. 移除所有 key 的数据

java 复制代码
    // 移除所以 key 的数据
    @Override
    public void removeAllKey(int key) {


        LinkedNode cur= head.next;
        while (cur.next !=null) {
            if (cur.val==key) {
//                cur.val=null;
                cur.prev.next=cur.next;
                cur.next.prev=cur.prev;

            }
                cur=cur.next;


        }

        if (head.val==key) {
//            head.val=null;
            head=head.next;
            head.prev=null;
        }

        if (last.val==key) {
//            last.val=null;
            last=last.prev;
            last.next=null;
        }
    }

5. 其他处理

<1>. 获取链表大小

java 复制代码
// 双链表长度

@Override
public int size() {
    int count=0;
    LinkedNode cur=head;
    while (cur !=null) {
        count++;
        cur=cur.next;
    }

    return  count;
}

 

这里只需要遍历链表 N 次 得到链表大小

<2>. 释放链表

java 复制代码
  // 释放双链表
    @Override
    public void clear() {
        LinkedNode cur=head;
        while (cur !=null) {
           LinkedNode tmp=cur.next;
//           cur.val=null;
           cur=null;
           cur=tmp;

        }
        head=null;
    }

逻辑代码展示

<1>. main 函数代码

java 复制代码
package Testdmo4.one;

import java.util.LinkedList;
import java.util.List;

public class TestLinked {

    public static void main(String[] args) {
        List<String> list=new LinkedList<>();

        list.add("钟少爷");
        list.add("郭男神");
        list.add("刘富帅");
        list.add("吴富婆");
        list.add(1,"杰哥哥");

        System.out.println(list);

        System.out.println("====== 删除数据 ========");

        System.out.println(list.remove(3)); // 删除 "刘富帅"
        System.out.println(list.remove(0)); // 删除 "钟少爷"

        System.out.println("======= 获取数据 ========");

        System.out.println(list.get(0));  // "郭男神"
        System.out.println(list.get(1));  // "刘富帅"


        System.out.println("========= 修改数据 =========");
        System.out.println(list.set(0, "彭于晏"));
        System.out.println(list.get(0));


        System.out.println("=========查找数据=========");
        String s=new String("郭男神");
        if (list.contains(s)) {
            System.out.println("该数据的下标为:"+ list.indexOf(s));
        } else {
            System.out.println("未找到该数据,查找失败!");
        }
    }
}

<2>. 接口代码

java 复制代码
package linklist;

public abstract class AbLinkList {
     //头插法
     public  abstract void addFirst(int data);

     //尾插法
     public abstract void addLast(int data);

     //任意位置插入,第一个数据节点为0号下标
     public abstract boolean addIndex(int index,int data);

     //查找是否包含关键字key是否在单链表当中
     public abstract boolean contains(int key);

     //删除第一次出现关键字为key的节点
     public abstract boolean remove(int key);

     //删除所有值为key的节点
     public abstract void removeAllKey(int key);

     //得到双链表的长度
     public abstract int size();

     // 打印双链表
     public abstract void display();

     // 释放双链表
     public abstract void clear();

}

三. LinedList 和 ArrayList 的异同

鱼式疯言

总之一句话:

顺序表啥都 连续 ,链表只是 物理空间不连续。
顺序表适合访问 和 尾插 和 尾删 ,链表适合 任意插入 和 删除

若有感兴趣的小伙伴可以优化我们的数据类型哦 💖 💖 💖

总结

  1. LinkedList : 理解LinkedList 的底层就是我们的双向链表
  2. 双向链表的实现: 我们用前后引用和内部类的实现了我们的链表
  3. LinedList 和 ArrayList 的异同: 清楚了 LinkedList 和 ArrayList 的各自的优势和使用场景

可谓收获颇丰啊 💖 💖 💖 💖

如果觉得小编写的还不错的咱可支持 三连 下 ==(定有回访哦) == , 不妥当的咱请评论区 指正
希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编 创作 的最大 动力 💖 💖 💖

相关推荐
小羊没烦恼!5 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里5 天前
java中的继承和多态的区别
java
小羊没烦恼!5 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕5 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码5 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖5 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时5 天前
01-06-A-JVM排查实战详解
java·jvm
vipxieliang5 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
m0_547486665 天前
《数据结构教程》全套 PPT课件2026
数据结构
ba_pi5 天前
mysql 查询所有表名并授权
java