数据结构入门到入土——链表(1)
目录
一,顺序表表/ArrayList的缺陷
二,链表
三,链表的实现
四,与链表有关的题目练习(1)
1.删除链表中等于给定值 val 的所有节点
2.反转一个单链表
3.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点
4.输入一个链表,输出该链表中倒数第k个结点
5.将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
6.编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前
7.链表的回文结构
一,顺序表表/ArrayList的缺陷
在上期我们已经熟悉了ArrayList的使用,并且进行了简单模拟实现。通过源码我们知道ArrayList底层使用数组来存储元素。
二,链表
如果说顺序表其底层在物理意义上是一段连续的空间,那么链表便是是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。
顺序表是一段连续不可分的空间:

链表像一列火车一样,多个节点被串成一块具有连续性意义的结构,实际上各个节点都来自于不同的地址:




三,链表的实现
和上期顺序表一样,我们采用接口的方式实现:
接口部分:
// 1、无头单向非循环链表实现
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 AchieveList implements IList{static class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;//创建一个链表public void crateList() {ListNode node1 = new ListNode(12);ListNode node2 = new ListNode(34);ListNode node3 = new ListNode(56);ListNode node4 = new ListNode(78);ListNode node5 = new ListNode(99);node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;this.head = node1;}//头插法@Overridepublic void addFirst(int data) {ListNode node =new ListNode(data);node.next = this.head;this.head = node;}//尾插法@Overridepublic void addLast(int data) {ListNode cur = this.head;while (cur.next != null) {cur = cur.next;}ListNode node = new ListNode(data);cur.next = node;}//任意位置插入,第一个数据节点为0号下标@Overridepublic void addIndex(int index, int data) {ListNode node = new ListNode(data);ListNode cur = this.head;ListNode prev = this.head;if (index == 0) {node.next = cur;this.head = node;} else {int count = 0;while (count != index) {cur = cur.next;count++;}count = 0;while ((count+1) != index) {prev = prev.next;count++;}node.next = cur;prev.next = node;}}//查找是否包含关键字key是否在单链表当中@Overridepublic boolean contains(int key) {ListNode cur = this.head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}//删除第一次出现关键字为key的节点@Overridepublic void remove(int key) {if (head == null) {return;}ListNode cur = this.head;ListNode prev = this.head;int count = 1;while (cur.val != key) {if (count == size()) {return;}cur = cur.next;count++;}if (count == 1) {head = null;head = prev.next;} else {while (prev.next.val != key) {prev = prev.next;}prev.next = cur.next;}}//删除所有值为key的节点@Overridepublic void removeAllKey(int key) {ListNode cur = this.head;int count = 1;while (cur.next != null) {if (cur.val == key) {count++;}cur = cur.next;}for (int i = 0; i < count; i++) {remove(key);}}//得到单链表的长度@Overridepublic int size() {int count = 1;ListNode cur = this.head;if (cur == null) {return 0;}while (cur.next != null) {cur = cur.next;count++;}return count;}@Overridepublic void clear() {ListNode cur = this.head;while (cur.next != null) {head = null;head = cur.next;cur = cur.next;}head = null;}//打印链表@Overridepublic void display() {ListNode cur = this.head;if (head == null) {System.out.println("[" + "]");} else {System.out.print("[");while (cur != null) {if (cur.next == null) {System.out.println(cur.val + "]");} else {System.out.print(cur.val + " ");}cur = cur.next;}}} 四,与链表有关的题目练习(1)
1.删除链表中等于给定值 val 的所有节点
class Solution {public ListNode removeElements(ListNode head,int val) {if (head == null) {return null;}ListNode cur = head.next;ListNode prev = head;while (cur != null) {if (cur.val == val) {prev.next = cur.next;cur = cur.next;} else {cur = cur.next;prev = prev.next;}}if (head.val == val) {head = head.next;}return head;}} 2.反转一个单链表
思路:
现有如下链表:

定义cur = head.next

将head.next指向null

定义变量curNext = cur.next

将cur的下一个节点设为head

令cur = curNext;curNext = cur.next;
后以此思路循环

class Solution {public ListNode reverseList(ListNode head) {if (head == null) {return null;}if (head.next == null) {return head;}ListNode cur = head.next;head.next = null;while (cur != null) {ListNode curNext = cur.next;cur.next = head;head = cur;cur = curNext;}return head;}} 3.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点
思路:
定义如图两个变量fast和slow,且都等于head
令fast每次走两步,slow每次走一步。当fast==null或者fast.next === null时
此时slow的位置必定是中间节点
初:

移动一次:

移动两次:

末:

class Solution {public ListNode middleNode(ListNode head) {ListNode fast = head;ListNode slow = head;while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}return slow;}}
} 4.输入一个链表,输出该链表中倒数第k个结点
假设有以下链表:

要求倒数第k个节点,我们可以先定义fast和slow两个位于头节点的变量

假如K为3,我们就先令fast先走K-1步

然后令fast和slow一起走同样的步数,直到fast.next为null

此时slow对应的位置就是所求的倒数第K个节点
public class Solution {public ListNode FindKthToTail(ListNode head,int k) {if (head == null) {return head;}if (k <= 0 && head != null ) {return null;}ListNode fast = head;ListNode slow = head;for (int i = 0; i < k-1; i++) {fast = fast.next;//处理K太大的问题if (fast == null) {return null;}}while (fast.next != null) {fast = fast.next;slow = slow.next;}return slow;}} 5.将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
思路:
先有以下两个有序链表需要被合并为一个有序链表

定义一个newH节点

将head1.val与head2.val进行比较,较小令它等于tmpH且令它等于它的下一个节点,tmpH为newH的下一个节点
如上图head1.val<head2.val,故发生以下变化

接着对head1.val与head2.val进行比较
head2.val更小

继续比较
head1.val更小

继续比较
head2.val更小

……
当其中有一个数组比较完了的时候,此时只需令tmpH.next为另一个head即可

最后返回newH.next即可
class Solution {public ListNode mergeTwoLists(ListNode head1, ListNode head2) {ListNode newH = new ListNode(-1);ListNode tmpH = newH;while (head1 != null && head2 != null) {if (head1.val < head2.val) {tmpH.next = head1;tmpH = tmpH.next;head1 = head1.next;} else {tmpH.next = head2;tmpH = tmpH.next;head2 = head2.next;}}if (head1 != null) {tmpH.next = head1;}if (head2 != null) {tmpH.next = head2;}return newH.next;}} 6.编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前
使用cur遍历顺序表
当cur.val<给定的值x时就让它进入链表1
当cur.val>=给定的值x时就让它进入链表2
最后将链表2的尾部插在链表1的头部,返回链表2

public class Partition {public ListNode partition(ListNode pHead, int x) {ListNode cur = pHead;ListNode tmpH1 = new ListNode(-1);ListNode tmpH2 = new ListNode(-1);ListNode head1 = tmpH1;ListNode head2 = tmpH2;while (cur != null) {if (cur.val < x) {head2.next = cur;head2 = head2.next;} else {head1.next = cur;head1 = head1.next;}cur = cur.next;}tmpH2 = tmpH2.next;tmpH1 = tmpH1.next;head2.next = tmpH1;head1.next = null;if (tmpH2 == null) {return tmpH1;}if (tmpH1 == null) {return tmpH2;}return tmpH2;}} 7.链表的回文结构
通过以上快慢指针的方式找到链表的中间节点

翻转


当slow和fast相遇时停止

public class PalindromeList {public boolean chkPalindrome(ListNode A) {if (A == null || A.next == null) {return true;}ListNode fast = A;ListNode slow = A;//找中间位置while (fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}ListNode cur = slow.next;//翻转while (cur != null) {ListNode curNext = cur.next;cur.next = slow;slow = cur;cur = curNext;}ListNode right = slow;ListNode left = A;//从前到后 从后到前while (left.next != right.next ) {if (left.val != right.val) {return false;}if (left.next == right){return true;}left = left.next;right = right.next;}return true;}} 相关文章:
数据结构入门到入土——链表(1)
目录 一,顺序表表/ArrayList的缺陷 二,链表 三,链表的实现 四,与链表有关的题目练习(1) 1.删除链表中等于给定值 val 的所有节点 2.反转一个单链表 3.给定一个带有头结点 head 的非空单链表…...
MySQL C API的使用
MySQL C API的使用 介绍及使用 MySQL C API(也称为 MySQL Connector/C)是用于与 MySQL 数据库交互的 C 语言 API。它提供了一组函数和结构体,允许你在 C 程序中连接到 MySQL 数据库服务器,并执行查询、插入、更新等数据库操作。…...
JavaScript防御性编程
简单聊一下防御性编程,初衷是开发人员为了防止自己被裁员,而将代码编写为只有自己能看懂。如何只有自己能看懂?方法多种多样,但不能将简单问题复杂化,比如:编写一堆无效的逻辑关系,或将业务复杂…...
微信预约小程序制作指南:从小白到专家
在当今的数字时代,微信小程序已经成为了一种非常流行的应用方式。预约功能更是成为了许多小程序的核心功能之一。如果你也想为你的小程序添加预约功能,以下步骤将会对你有所帮助。 一、进入乔拓云网后台 乔拓云网是一个在线小程序开发平台,你…...
向量数据库:Milvus
特性 Milvus由Go(63.4%),Python(17.0%),C(16.6%),Shell(1.3%)等语言开发开发,支持python,go,java接口(C,Rust,c#等语言还在开发中),支持单机、集群部署,支持CPU、GPU运算。Milvus 中的所有搜索和查询操作都在内存中执行…...
亚马逊国际商品详情 API:获取特定商品详细信息的实践
随着电子商务的飞速发展,亚马逊作为全球最大的在线零售商之一,提供了丰富的商品详情 API,使得第三方开发者能够轻松地获取亚马逊网站上的商品信息。本文将介绍如何使用亚马逊国际商品详情 API(Amazon Product Advertising API&…...
MSB30M-ASEMI小贴片整流桥MSB30M
编辑:ll MSB30M-ASEMI小贴片整流桥MSB30M 型号:MSB30M 品牌:ASEMI 封装:UMSB-4 最大平均正向电流:3A 最大重复峰值反向电压:1000V 产品引线数量:4 产品内部芯片个数:4 产品…...
Redis启动方式
redis三种启动方式 1.直接启动 进入redis根目录,执行命令: #加上‘&’号使redis以后台程序方式运行 ./redis-server & 2.通过指定配置文件启动 可以为redis服务启动指定配置文件,例如配置为/etc/redis/6379.conf 进入redis根目录&#x…...
TEMU 新手小白必看!2024入驻流程/入驻类目/入驻资料等详细流程讲解
2023 TEMU 可谓是赚足眼球,流量持续上涨,2024年相信不少卖家们已经跃跃欲试,但大陆卖家如何入驻TEMU?哪些品类适合入驻?又有哪些入驻要求和资料?别急,今天东哥就一一给大家详细讲解,…...
【C语言】数组
一维数组的创建和初始化 数组是一组相同类型元素的集合。 数组的创建 //数组的创建方式:type_t arr_name [const_n];//type_t 是指数组的元素类型//const_n 是一个常量表达式,用来指定数组的大小数组创建的实例: 数组创建ÿ…...
常见测试技术都有哪些?
测试技术是用于评估系统或组件的方法,目的是发现它是否满足给定的要求。系统测试有助于识别缺口、错误,或与实际需求不同的任何类型的缺失需求。测试技术是测试团队根据给定的需求评估已开发软件所使用的最佳实践。这些技术可以确保产品或软件的整体质量…...
Spring事务控制
1.事务介绍 1.1什么是事务? 当你需要一次执行多条SQL语句时,可以使用事务。通俗一点说,如果这几条SQL语句全部执行成功,则才对数据库进行一次更新,如果有一条SQL语句执行失败,则这几条SQL语句全部不进行执…...
swaggerUI不好用,试试这个openapiUI?
title: swaggerUI不好用,试试这个openapiUI? date: 2024-01-08 categories: [tool] tags: [openapi,工具] description: 基于swaggger2, openapi3规范的UI文档 1.背景 由于长期使用 swaggerUI 工具,它的轻量风格个人觉得还是不错的,但是它…...
嵌入式物联网项目开发实战例程-STM32F103系列之外围器件代码
开发STM32F103很好的参考例程,轻松实现各类外围器件的开发。持续更新中,欢迎关注及收藏。 0001基于STM32F103单片机GPIO实现控制LED灯闪烁的程序代码.zip 0002基于STM32F103单片机GPIO实现按键KEY的检测程序代码.zip 0003基于STM32F103单片机GPIO实现外部…...
Docker Compose--部署SpringBoot项目--实战
原文网址:Docker Compose--部署SpringBoot项目--实战-CSDN博客 简介 本文用实战介绍Docker Compose部署SpringBoot项目。 ----------------------------------------------------------------------------------------------- 分享Java真实高频面试题,…...
单电阻FOC算法实现永磁同步电机的调整步骤和设置
本文档介绍了使用 单电阻FOC 算法实现永磁同步电机(Permanent Magnet Synchronous Motor,PMSM)调整所需的步骤和设置。由于不同电机存在参数差异,因此需针对不同的电机和负载对该算法进行调整。该电机库已经在在落地扇和空净等风机…...
化学DS-1040 Tosylate 抑制剂 1335138-89-0科研用途
化合物1219962-49-8是一种小分子化合物,分子式为C15H25N3O4,相对分子质量为305.37。该化合物为白色至灰白色粉末,不溶于水,易溶于有机溶剂,如甲醇、乙醇等。 AT791是一种与细胞周期调控相关的蛋白激酶,参与…...
PaddlePaddle初使用
模型导出与预测 # -c 后面设置训练算法的yml配置文件 # -o 配置可选参数 # Global.pretrained_model 参数设置待转换的训练模型地址,不用添加文件后缀 .pdmodel,.pdopt或.pdparams。 # Global.save_inference_dir参数设置转换的模型将保存的地址。pytho…...
【FPGA】分享一些FPGA数字信号处理相关的书籍
在做FPGA工程师的这些年,买过好多书,也看过好多书,分享一下。 后续会慢慢的补充书评。 【FPGA】分享一些FPGA入门学习的书籍【FPGA】分享一些FPGA协同MATLAB开发的书籍 【FPGA】分享一些FPGA视频图像处理相关的书籍 【FPGA】分享一些FPGA高速…...
深度解析JavaScript面试热点:事件循环、上下文、箭头函数、变量作用域与ES6模块
JavaScript面试中经常涉及到事件循环、上下文、箭头函数、变量作用域以及ES6模块等核心概念。通过清晰的代码示例,我们深入讨论这些主题,揭示其中的关键细节。 事件循环(Event Loop) JavaScript开发者每天都与事件循环打交道&am…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
