【数据结构】链表之LinkedList(无头双链表实现 + 详解 + 原码)

Hi~!这里是奋斗的明志,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~
🌱🌱个人主页:奋斗的明志
🌱🌱所属专栏:数据结构

在这里插入图片描述

📚本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为展示我的学习过程及理解。文笔、排版拙劣,望见谅。

在这里插入图片描述


文章目录

  • 前言
  • 一、什么是LinkedList?
  • 二、LinkedList的使用
    • 1.LinkedList的构造
    • 2.LinkedList的其他常用方法介绍
    • 3. LinkedList的遍历
  • 三、自己简单实现LinkedList
    • 1.接口
    • 2.MyLinkedList类
    • 3.异常类
    • 4.总结remove、removeAllKey方法
  • 四、总结(ArrayList和LinkedList的区别)


前言

LinkedList是无头双向非循环链表
学习链表的知识一定要 结合图,多画图,才能深刻理解

一、什么是LinkedList?

LinkedList官方文档

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

在这里插入图片描述
在集合框架中, LinkedList也实现了List接口,具体如下:

在这里插入图片描述
【说明】

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

二、LinkedList的使用

1.LinkedList的构造

方法解释
LinkedList()无参构造
public LinkedList(Collection<? extends E> c)使用其他集合容器中元素构造List

代码如下(示例):

public static void main(String[] args) {
// 构造一个空的LinkedListList<Integer> list1 = new LinkedList<>();List<String> list2 = new ArrayList<>();list2.add("JavaSE");list2.add("JavaWeb");list2.add("JavaEE");
// 使用ArrayList构造LinkedListList<String> list3 = new LinkedList<>(list2);System.out.println(list3);}

在这里插入图片描述

2.LinkedList的其他常用方法介绍

方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List subList(int fromIndex, int toIndex)截取部分 list

代码如下(示例):

public static void main(String[] args) {LinkedList<Integer> list = new LinkedList<>();list.add(1);   // add(elem): 表示尾插list.add(2);list.add(3);list.add(4);list.add(5);list.add(6);list.add(7);System.out.println(list.size());System.out.println(list);// 在起始位置插入0list.add(0, 0);  // add(index, elem): 在index位置插入元素elem System.out.println(list);list.remove();        // remove(): 删除第一个元素 , 内部调用的是removeFirst()list.removeFirst();    // removeFirst(): 删除第一个元素 list.removeLast();    // removeLast():  删除最后元素list.remove(1);  // remove(index): 删除index位置的元素 System.out.println(list);
// contains(elem): 检测elem元素是否存在 ,如果存在返回true ,否则返回falseif (!list.contains(1)) {list.add(0, 1);}list.add(1);System.out.println(list);System.out.println(list.indexOf(1));   // indexOf(elem): 从前往后找到第一个elem的位置  System.out.println(list.lastIndexOf(1));  // lastIndexOf(elem): 从后往前找第一个1的位置 int elem = list.get(0);    // get(index): 获取指定位置元素list.set(0, 100);         // set(index, elem): 将index位置的元素设置为elem System.out.println(list);
// subList(from, to): 用list中[from, to)之间的元素构造一个新的LinkedList返回List<Integer> copy = list.subList(0, 3);System.out.println(list);System.out.println(copy);list.clear();               // 将list中元素清空 System.out.println(list.size());
}

在这里插入图片描述


3. LinkedList的遍历

代码如下(示例):

public static void main(String[] args) {LinkedList<Integer> list = new LinkedList<>();list.add(1);   // add(elem): 表示尾插list.add(2);list.add(3);list.add(4);list.add(5);list.add(6);list.add(7);System.out.println(list.size());
// foreach遍历for (int e : list) {System.out.print(e + " ");}System.out.println();
// 使用迭代器遍历---正向遍历ListIterator<Integer> it = list.listIterator();while (it.hasNext()) {System.out.print(it.next() + " ");}System.out.println();
// 使用反向迭代器---反向遍历ListIterator<Integer> rit = list.listIterator(list.size());while (rit.hasPrevious()) {System.out.print(rit.previous() + " ");}System.out.println();
}

在这里插入图片描述


三、自己简单实现LinkedList

1.接口

代码如下(示例):

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

2.MyLinkedList类

代码如下(示例):

import java.util.List;public class MyLinkedList implements IList {static class ListNode {public int val;public ListNode next;public ListNode prev;public ListNode(int val) {this.val = val;}}public ListNode head;public ListNode last;/*** 打印链表* 跟单链表一样* 遍历链表 从头走到尾*/@Overridepublic void display() {ListNode cur = head;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}System.out.println();}/*** 统计链表的个数** @return*/@Overridepublic int size() {int count = 0;ListNode cur = head;while (cur != null) {count++;cur = cur.next;}return count;}/*** 判断链表是否有 key 值** @param key* @return*/@Overridepublic boolean contains(int key) {if (head == null) {return false;}ListNode cur = head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}/*** 头插法* 头插节点之前要实例化该节点** @param data*/@Overridepublic void addFirst(int data) {ListNode node = new ListNode(data);//当链表为空//此时头节点为空 没有前驱//而 实例化的数据有前驱if (head == null) {head = node;last = node;} else {//任何数据插入,都要先绑后面node.next = head;head.prev = node;head = node;}}/*** 尾插法** @param data*/@Overridepublic void addLast(int data) {ListNode node = new ListNode(data);if (head == null) {head = node;last = node;} else {last.next = node;node.prev = last;//last 向后走last = node;}}/*** 在指定位置 插入数据** @param index* @param data*/@Overridepublic void addIndex(int index, int data) {//首先先检查index位置是否合法if (index < 0 || index > this.size()) {throw new IndexException("双向链表插入index位置不合法" + index);}if (index == 0) {addFirst(data);return;}if (index == this.size()) {addLast(data);return;}ListNode node = new ListNode(data);ListNode cur = findIndex(index);//中间位置插入node.next = cur;cur.prev.next = node;node.prev = cur.prev;cur.prev = node;}private ListNode findIndex(int index) {ListNode cur = head;while (index != 0) {cur = cur.next;index--;}return cur;}/*** 删除 一个key** @param key*/@Overridepublic void remove(int key) {//双向链表删除谁,就找到谁ListNode cur = head;while (cur != null) {if (cur.val == key) {if (cur == head) {head = head.next;if (head != null) {head.prev = null;} else {//只有一个节点,还是删除的节点last = null;}} else {if (cur.next != null) {cur.next.prev = cur.prev;cur.prev.next = cur.next;} else {//删除尾巴结点cur.prev.next = cur.next;last = last.prev;}}return;}cur = cur.next;}}/*** 删除所有的 key** @param key*/@Overridepublic void removeAllKey(int key) {//双向链表删除谁,就找到谁ListNode cur = head;while (cur != null) {if (cur.val == key) {if (cur == head) {head = head.next;if (head != null) {head.prev = null;} else {//只有一个节点,还是删除的节点last = null;}} else {if (cur.next != null) {cur.next.prev = cur.prev;cur.prev.next = cur.next;} else {//删除尾巴结点cur.prev.next = cur.next;last = last.prev;}}}cur = cur.next;}}@Overridepublic void clear() {this.head = null;this.last = null;}
}

3.异常类

代码如下(示例):

public class IndexException extends RuntimeException{public IndexException() {}public IndexException(String message) {super(message);}
}

4.总结remove、removeAllKey方法

在这里插入图片描述

四、总结(ArrayList和LinkedList的区别)


不同点ArrayListLinkedList
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持: O(N)
头插需要搬移元素,效率低O(N)只需修改引用的指向,时间复杂度为O(1)
插入空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入和删除频繁

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3267512.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

让你的程序有记忆功能。

目录 环境 代码 环境 大语言模型&#xff1a; gpt-40-mini Mem0: Empower your AI applications with long-term memory and personalization OpenAPI-Key: Mem0-Key&#xff1a; 代码 import osfrom dotenv import load_dotenv from openai import OpenAI from m…

ili9341数据手册中的常用命令

一.设置液晶显示窗口 根据液晶屏的要求&#xff0c;在发送显示数据前&#xff0c;需要先设置显示窗口确定后面发送的像素数据的显示区域。下面的0x2A和0x2B分别对应的是y轴与x轴的命令。 /********** ILI934 命令 ********************************/ #define CMD_SetCoor…

【深度学习】LLaMA-Factory 大模型微调工具, 大模型GLM-4-9B Chat ,微调与部署 (2)

文章目录 数据准备chat评估模型导出模型部署总结 资料&#xff1a; https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md https://www.53ai.com/news/qianyanjishu/2015.html 代码拉取&#xff1a; git clone https://github.com/hiyouga/LLaMA-Factory.git cd …

Qt SQLite数据库编程学习总结

到此为止&#xff0c;就使用Qt进行SQLite数据库的操作&#xff0c;做一次总结 1. Qt中数据库操作的相关概念和类 Qt 数据库编程相关基本概念https://blog.csdn.net/castlooo/article/details/140497177 2.表的只读查询--QSqlQueryModel QSqlQueryModel单表查询的使用总结htt…

AI驱动的在线面试系统:技术革新与初步面试的新体验

一、引言 在数字化和智能化的时代背景下&#xff0c;人工智能&#xff08;AI&#xff09;技术正日益渗透到各行各业&#xff0c;为人们的生活和工作带来前所未有的变革。其中&#xff0c;AI驱动的在线面试系统&#xff0c;凭借其高效、便捷、公正等特性&#xff0c;逐渐成为企业…

示例:WPF中如何处理TabControl页面绑定ItemsSource切换TabItem时UI数据没有持久保存的问题

一、目的&#xff1a;在WPF开发过程中&#xff0c;经常用到TabControl&#xff0c;也会遇到类似问题&#xff0c;用TabControl绑定数据源ItemsSource时&#xff0c;切换TabItem时&#xff0c;UI上的数据没有持久保存&#xff0c;本文介绍一种处理方式&#xff0c;可以做到缓存页…

Elasticsearch概念及ELK安装

1、Elasticsearch是什么 它是elastic技术栈中的一部分。完整的技术栈包括&#xff1a; Elasticsearch&#xff1a;用于数据存储、计算和搜索 Logstash/Beats&#xff1a;用于数据收集 Kibana&#xff1a;用于数据可视化 整套技术栈被称为ELK&#xff0c;经常用来做日志收集…

海康4G摄像头接入自定义程序

1.使用【萤石云视频】APP添加摄像头&#xff0c;在设置中关闭视频加密 2.打开萤石云&#xff0c;进入控制台 3.设备管理中可以看到添加的设备 4.添加一个应用&#xff0c;即可获取AppKey、Secret、AccessToken 5.根据文档中的说明获取播放地址&#xff0c;这里是我生成的播放…

单证不一致清关难题 | 国际贸易综合服务平台 | 箱讯科技

什么是单证一致&#xff1f; 单证一致出口方所提供的所有单据要严格符合进口方开证银行所开信用证的要求&#xff0c;或者说出口方制作和提供的所有与本项货物买卖有关的单据&#xff0c;与进口方申请开立的信用证对单据的要求完全吻合&#xff0c;没有矛盾。 添加图片注释&am…

本地搭建rtmp拉流

本地搭建rtmp拉流 可按照步骤来 关注公众号&#xff1a;城羽海 更多有趣实用教程 下载地址: 从微信公众号发送关键词 rtmp可获取下载地址 文章目录 本地搭建rtmp拉流 可按照步骤来 关注公众号&#xff1a;城羽海 更多有趣实用教程 拿到之后如图所下&#xff1f;二、配置obs文…

构建查询洞察 UI

本文字数&#xff1a;2631&#xff1b;估计阅读时间&#xff1a;7 分钟 作者&#xff1a;Bucky Schwarz 本文在公众号【ClickHouseInc】首发 我们最近发布了 Query Insights 的初步实现&#xff0c;为 ClickHouse Cloud 用户提供了一种便捷的方法来查看和解释查询日志。该功能对…

Python --NumPy库基础方法(1)

NumPy Numpy(Numerical Python) 是科学计算基础库&#xff0c;提供大量科学计算相关功能&#xff0c;比如数据统计&#xff0c;随机数生成等。其提供最核心类型为多维数组类型&#xff08;ndarray&#xff09;&#xff0c;支持大量的维度数组与矩阵运算&#xff0c;Numpy支持向…

mysql语法介绍

MySQL 语法主要基于 SQL&#xff08;Structured Query Language&#xff09;标准&#xff0c;用于管理和操作关系型数据库。以下是一些基本的 MySQL 语句&#xff1a; 1.创建数据库&#xff1a; CREATE DATABASE database_name; 1.选择数据库&#xff1a; USE database_name;…

科研绘图系列:R语言组合堆积图(stacked barplot with multiple groups)

介绍 通常堆积图的X轴表示样本,样本可能会存在较多的分组信息,通过组合堆积图和样本标签分组信息,我们可以得到一张能展示更多信息的可发表图形。 加载R包 knitr::opts_chunk$set(warning = F, message = F) library(tidyverse) library(cowplot) library(patchwork)导入…

springcloud RocketMQ 客户端是怎么走到消费业务逻辑的 - debug step by step

springcloud RocketMQ &#xff0c;一个mq消息发送后&#xff0c;客户端是怎么一步步拿到消息去消费的&#xff1f;我们要从代码层面探究这个问题。 找的流程图&#xff0c;有待考究。 以下我们开始debug&#xff1a; 拉取数据的线程&#xff1a; PullMessageService.java 本…

云盘高速视觉检测机,如何提高螺丝件的检测效率?

螺纹螺丝钉是一种常见的螺纹结构紧固件&#xff0c;通常由金属制成&#xff0c;具有螺旋状的螺纹结构。这种螺丝钉旨在通过旋入螺纹孔或材料中&#xff0c;实现可靠的固定连接。 螺纹螺丝钉具有螺旋状的螺纹结构&#xff0c;使其能够轻松旋入金属或其他硬质材料。主要用于金属…

UDP的报文结构及其注意事项

1. 概述 UDP&#xff08;User Datagram Protocol&#xff09;是一种无连接的传输层协议&#xff0c;它提供了一种简单的数据传输服务&#xff0c;不保证数据的可靠传输。在网络通信中&#xff0c;UDP通常用于一些对实时性要求较高、数据量较小、传输延迟较低的应用&#xff0c…

NLP基础知识2【各种大模型的注意力】

注意力 传统Attention存在的问题优化方向变体有哪些现在的主要变体集中在KVMulti-Query AttentionGrouped-query AttentionFlashAttention 传统Attention存在的问题 上下文约束速度慢&#xff0c;显存占用大&#xff08;因为注意力考虑整体信息&#xff0c;所以每一个位置都要…

【大模型】基于LoRA微调Gemma大模型(1)

文章目录 一、LoRA工作原理1.1 基本原理1.2 实现步骤 二、LoRA 实现2.1 PEFT库&#xff1a;高效参数微调LoraConfig类&#xff1a;配置参数 2.2 TRL库SFTTrainer 类 三、代码实现3.1 核心代码3.2 完整代码 参考资料 大模型微调技术有很多&#xff0c;如P-Tuning、LoRA 等&#…

狗都能看懂的Actor-Critic强化学习算法讲解

Review Policy Gradient 上面的公式是Policy Gradient的更新函数&#xff0c;这个式子是指在 s t s_t st​时刻采取了 a t a_t at​&#xff0c;计算出对应发生的概率 p θ p_\theta pθ​&#xff0c;然后计算在采取了这个 a t a_t at​之后&#xff0c;所得到的reward有多大。…