Java 数据结构篇-实现双链表的核心API
🔥博客主页: 小扳_-CSDN博客
❤感谢大家点赞👍收藏⭐评论✍


文章目录
1.0 双链表的说明
1.1 双链表 - 创建
1.2 双链表 - 根据索引查找节点
1.3 双链表 - 根据索引插入节点
1.4 双链表 - 头插节点
1.5 双链表 - 尾插
1.6 双链表 - 根据索引来删除节点
1.7 头删节点
1.8 尾删节点
1.9 实现迭代器循环
2.0 双链表完整的实现代码
3.0 环形双链表的说明
3.1 环形双链表 - 创建
3.2 环形双链表 - 头插节点
3.3 环形双链表 - 尾插节点
3.4 环形双链表 - 头删节点
3.5 环形双链表 - 尾删节点
3.6 环形链表 - 根据值来删除节点
4.0 环形双链表完整的实现代码
1.0 双链表的说明
双链表是一种数据结构,其中每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。双链表可以在任意位置插入或删除节点,而不需要像单链表那样遍历整个链表来找到需要操作的位置。双链表可以用于实现栈、队列、以及其他需要快速插入和删除操作的数据结构。由于每个节点包含两个指针,双链表的内存占用量通常比单链表更大。
1.1 双链表 - 创建
把双链表封装成一个类,类中还需要封装一个节点类 Node,该节点类的成员有指向前一个节点的变量 Node prev,值 value ,指向后一个节点的变量 Node next 。
代码如下:
public class MyDoubleLists{private final Node hand;private final Node tail;private static class Node {public Node prev;public Node next;public int value;public Node(Node prev, int value, Node next) {this.prev = prev;this.next = next;this.value = value;}}public MyDoubleLists() {hand = new Node(null,0,null);tail = new Node(hand,-1,null);hand.next = tail;tail.prev = hand;}}注意外部类中,还需要定义头节点,尾节点,再利用外部类的构造器中就可以完成对头尾节点的初始化了。内部类中的节点类建议用静态来修饰。
1.2 双链表 - 根据索引查找节点
由于这个方法可以为其他几个方法提供服务,因此,把这个方法独立出来。实现思路为:开始的节点应为 hand,循环终止条件为:p == tail 当指向尾节点的那一刻就该结束循环了。还要加一个变量 i = -1 ,每一次循环结束要进行 i++ ,当 i == index 时,找到了该索引的节点,返回该节点即可,若循环结束还是没找到,就得返回 null 。
代码如下:
//根据索引查找节点private Node findNode(int index) {int i = -1;for (Node p = hand; p !=tail ; p = p.next,i++){if (i == index) {return p;}}return null;}这个方法一般不会对外开发,因此,加上 private 来修饰,当 i == -1 时,返回的时头节点,所以一开始的节点为 hand 。对外是索引从 0 开始才会存储值的,对于头节点存储什么值是不关心的。
1.3 双链表 - 根据索引插入节点
根据索引插入节点,提前需要准备好该节点的前一个节点 prev、该节点的后一个节点 next 。通过以上已经实现的方法来找到插入位置的前一个结点,prev = findNode(index - 1),后一个节点也就可以找到了,next = prev.next。
代码如下:
//根据索引插入节点public void insert(int index, int value) {Node p = findNode(index - 1);if (p == null){throw new RuntimeException("用索引访问失败");}Node prev = p;Node next = prev.next;Node insertNode = new Node(prev, value,next);prev.next = insertNode;next.prev = insertNode;}prev.next 指向新的节点,next.prev 指向上一个节点。新的节点的头节点的引用为 prev,尾节点为 next 。
1.4 双链表 - 头插节点
其实这个方法就比较简单了,这个就是根据索引 0 来插入节点的,就是一个索引等于0的特例,所以可以直接调用已经实现的 insert(0,int value) 方法。
代码如下:
//头插节点public void addFirst(int value) {insert(0,value);}
1.5 双链表 - 尾插
对尾部的操作是双链表的一个很大的优势,对尾部的查询、增加节点、删除节点效率都很快,因为对尾节点是有记录的,就不用从头开始来查找尾部节点了,直接可以得到。
实现方法的思路为:需要找到插入的前一个节点,插入的后一个节点肯定是尾节点,所以,可以通过 prev = tail.prev,来找到插入的前一个节点。
代码如下:
//尾插节点public void addLast(int value) {Node lats = tail;Node prev = lats.prev;Node addNode = new Node(prev,value,lats);prev.next = addNode;lats.prev = addNode;}新的节点的前一个节点为 prev ,后节点为 tail,prev.next 与 tail.prev 就要更改为指向新的节点了。
1.6 双链表 - 根据索引来删除节点
先通过已经实现的 findNode() 方法来找到该索引的节点,还有找到删除该节点的前一个节点与后一个节点。
代码如下:
//根据索引来删除节点public void remove(int index) {Node prev = findNode(index - 1);if (prev == null) {throw new RuntimeException("用索引来删除数据失败!");}Node remove = prev.next;if (remove == tail) {throw new RuntimeException("用索引来删除数据失败!");}Node next = remove.next;prev.next = next;next.prev = next;}接着就可以将要删除的前一个节点指向要删除的节点后一个节点,但是考虑两种情况,第一种,当要删除的节点没找到,就要抛出异常了。第二种,当发现要删除的节点为 tail 时需要抛出异常,总不能自己把自己的尾巴 "切了吧" 然而不用考虑是否把头节点删除,因为要删除的节点总是拿不到头节点。
1.7 头删节点
当索引为0时,就是头删,是 remove(0) 方法的一个特例。可以直接来调用根据索引来删除节点的方法。
代码如下:
//头删节点public void removeFirst() {remove(0);}
1.8 尾删节点
双链表尾删的效率是很高的,因为对尾节点是有记录的。
代码如下:
//尾删节点public void removeLast() {Node remove = tail.prev;if (remove == hand){throw new RuntimeException();}Node prev = remove.prev;prev.next = tail;tail.prev = prev;}需要找到三个节点,要删除的节点、删除节点的前一个节点、还有尾节点。需要注意的是,判断要删除的节点为头节点,需要抛出异常,总不能自己把自己的 " 头部 " 给切了吧。
1.9 实现迭代器循环
这个完成 Iterable 接口,创建新的该接口子类对象,重写两个方法即可。
代码如下:
//实现迭代器循环@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {Node p = hand.next;@Overridepublic boolean hasNext() {return p != tail;}@Overridepublic Integer next() {int value = p.value;p = p.next;return value;}};}需要注意的是,头节点的值是不用在乎的,所以遍历开始为 hand.next ,循环结束条件为,p == tail,遍历到尾节点就要终止了。
2.0 双链表完整的实现代码
import java.util.Iterator;public class MyDoubleLists implements Iterable<Integer>{private final Node hand;private final Node tail;private static class Node {public Node prev;public Node next;public int value;public Node(Node prev, int value, Node next) {this.prev = prev;this.next = next;this.value = value;}}public MyDoubleLists() {hand = new Node(null,0,null);tail = new Node(hand,-1,null);hand.next = tail;tail.prev = hand;}//根据索引查找节点private Node findNode(int index) {int i = -1;for (Node p = hand; p !=tail ; p = p.next,i++){if (i == index) {return p;}}return null;}//根据索引插入节点public void insert(int index, int value) {Node p = findNode(index - 1);if (p == null){throw new RuntimeException("用索引访问失败");}Node prev = p;Node next = prev.next;Node insertNode = new Node(prev, value,next);prev.next = insertNode;next.prev = insertNode;}//头插节点public void addFirst(int value) {insert(0,value);}//尾插节点public void addLast(int value) {Node lats = tail;Node prev = lats.prev;Node addNode = new Node(prev,value,lats);prev.next = addNode;lats.prev = addNode;}//根据索引来删除节点public void remove(int index) {Node prev = findNode(index - 1);if (prev == null) {throw new RuntimeException("用索引来删除数据失败!");}Node remove = prev.next;if (remove == tail) {throw new RuntimeException("用索引来删除数据失败!");}Node next = remove.next;prev.next = next;next.prev = next;}//头删节点public void removeFirst() {remove(0);}//尾删节点public void removeLast() {Node remove = tail.prev;if (remove == hand){throw new RuntimeException();}Node prev = remove.prev;prev.next = tail;tail.prev = prev;}//根据索引来查询数据public int get(int index) {Node find = findNode(index);if (find == null){throw new RuntimeException("根据该索引找不到数据");}return find.value;}//实现迭代器循环@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {Node p = hand.next;@Overridepublic boolean hasNext() {return p != tail;}@Overridepublic Integer next() {int value = p.value;p = p.next;return value;}};}}
3.0 环形双链表的说明
环形双链表是一种数据结构,它类似于双向链表,但是链表的最后一个节点指向第一个节点,形成一个环形结构。简单来说,先对比与一般的双链表,环形双链表就是头尾节点都是同一个节点。
3.1 环形双链表 - 创建
把环形双链表看成一个对象,该类中需要封装一个节点的内部类,对外不开放的,需要用限制修饰符来修饰。外部类中的成员变为 sentinel ,即作为头节点,也作为尾节点。
代码如下:
public class MyAnnularDoubleList{private final Node sentinel;private static class Node {public Node prev;public int value;public Node next;public Node(Node prev, int value, Node next) {this.prev = prev;this.value = value;this.next = next;}}public MyAnnularDoubleList() {sentinel = new Node(null,0,null);sentinel.prev = sentinel;sentinel.next = sentinel;}}在创建环形双链表时,在用无参构造器就可以先把 sentinel 初始化了。
3.2 环形双链表 - 头插节点
根据 next = sentinel.next 就可以得到插入点的下一个节点,就可以把新节点的指向的前一个节点来指向 sntinel,新节点的指向后一个节点来指向 next 。
这里需要考虑一种情况,假设,该环形双链表中就只有一个 sentinel 节点,以上阐述的思路还能不能用呢?答案时可以的,如果实在理解不了的话,可以把一个 sentinel 节点,想象成两个 sentinel 节点,效果都是一样的,都是指向自己嘛。
代码如下:
//头插节点public void addFirst(int value) {Node hand = sentinel;Node tail = sentinel.next;Node addNode = new Node(hand,value,tail);hand.next = addNode;tail.prev = addNode;}
3.3 环形双链表 - 尾插节点
根据 prev = sentinel.prev 来找到插入节点的前一个的节点,插入节点的后一个节点就是 sentinel ,新节点的指向前的节点为 prev,新节点的指向后的节点为 sentinel ,接着 prev.next 指向新节点,sentinel.prev 指向新节点。
代码如下:
//尾插节点public void addLast(int value) {Node prev = sentinel.prev;Node next = sentinel;Node addNode = new Node(prev,value,next);prev.next = addNode;next.prev = addNode;}同理,不需要额外考虑当节点只有一个时,以上代码依旧可以实现尾插节点。
3.4 环形双链表 - 头删节点
根据 remove = sentinel.next ,可以得到需要删除的节点,再由 next = remove.next,得到删除节点的后一个节点,这样三个节点后已知了,santinel.next 指向 next ,next.prev 指向sentinel ,剩下的没有被引用的节点(对象),会被 JVM 自动回收。
代码如下:
//头删节点public void removeFirst() {Node remove = sentinel.next;if (remove == sentinel) {throw new RuntimeException("删除失败!");}Node next = remove.next;sentinel.next = next;next.prev = sentinel;}需要注意的是,当删除的节点为 sentinel 需要抛出异常,但是个人感觉不加判断也可以,sentinel 根本不会被删除,即使只有 sentinel 一直被删除。
3.5 环形双链表 - 尾删节点
根据 remove = sentinel.prev 得到需要删除的节点,通过 prev = remove.prev 得到需要删除的前一个节点,prev.next 指向 sentinel,sentinel.prev 指向 prev 即可。
代码如下:
//尾删节点public void removeLast() {Node remove = sentinel.prev;Node prev = remove.prev;prev.next = sentinel;sentinel.prev = prev;}同样的,当删除的节点为 sentinel 需要抛出异常,但是个人感觉不加判断也可以,sentinel 根本不会被删除,即使只有 sentinel 一直被删除。
3.6 环形链表 - 根据值来删除节点
先独立一个方法,根据值来查询节点,一开始的循环节点为 sentinel.next ,对于 sentinel 里面的值是什么根本不在乎的。循环终止条件为:p == sentinel 已经转完一圈了。找到就返回该节点,找不到就返回 null 。删除的原理是一样的,得先找到三个节点,然后把前后节点直接关联起来。
代码如下:
//根据值来删除节点private Node findValue (int value) {for (Node p = sentinel.next; p != sentinel; p = p.next) {if (p.value == value) {return p;}}return null;}public void removeValue (int value) {Node remove = findValue(value);if (remove == null) {throw new RuntimeException("找不到该数据来删除相对应的节点");}Node prev = remove.prev;Node next = remove.next;prev.next = next;next.prev = prev;}需要注意的是,当接收到的节点为 null 时,需要抛出异常,找不到对应该值的节点。
4.0 环形双链表完整的实现代码
import java.util.Iterator;public class MyAnnularDoubleList implements Iterable<Integer>{private final Node sentinel;private static class Node {public Node prev;public int value;public Node next;public Node(Node prev, int value, Node next) {this.prev = prev;this.value = value;this.next = next;}}public MyAnnularDoubleList() {sentinel = new Node(null,0,null);sentinel.prev = sentinel;sentinel.next = sentinel;}//头插节点public void addFirst(int value) {Node hand = sentinel;Node tail = sentinel.next;Node addNode = new Node(hand,value,tail);hand.next = addNode;tail.prev = addNode;}//尾插节点public void addLast(int value) {Node prev = sentinel.prev;Node next = sentinel;Node addNode = new Node(prev,value,next);prev.next = addNode;next.prev = addNode;}//头删节点public void removeFirst() {Node remove = sentinel.next;if (remove == sentinel) {throw new RuntimeException("删除失败!");}Node next = remove.next;sentinel.next = next;next.prev = sentinel;}//尾删节点public void removeLast() {Node remove = sentinel.prev;Node prev = remove.prev;prev.next = sentinel;sentinel.prev = prev;}//根据值来删除节点private Node findValue (int value) {for (Node p = sentinel.next; p != sentinel; p = p.next) {if (p.value == value) {return p;}}return null;}public void removeValue (int value) {Node remove = findValue(value);if (remove == null) {throw new RuntimeException("找不到该数据来删除相对应的节点");}Node prev = remove.prev;Node next = remove.next;prev.next = next;next.prev = prev;}//实现迭代器@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {Node p = sentinel.next;@Overridepublic boolean hasNext() {return p != sentinel;}@Overridepublic Integer next() {int value = p.value;p = p.next;return value;}};} }

相关文章:
Java 数据结构篇-实现双链表的核心API
🔥博客主页: 小扳_-CSDN博客 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 双链表的说明 1.1 双链表 - 创建 1.2 双链表 - 根据索引查找节点 1.3 双链表 - 根据索引插入节点 1.4 双链表 - 头插节点 1.5 双链表 - 尾插 1.6 双链表 - 根据索引来…...
电脑如何截屏?一起来揭晓答案!
在数字时代,截屏已经成为我们日常生活和工作中的必备技能。无论是为了捕捉有趣的网络瞬间,保存重要信息,还是为了协作和教育,电脑截屏都是一个强大而方便的工具。本文将介绍三种电脑如何截屏的方法,以满足各种需求&…...
【实战-08】flink 消费kafka自定义序列化
目的 让从kafka消费出来的数据,直接就转换成我们的对象 mvn pom <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information …...
深入浅出 Django 异步编程
随着 Web 应用对性能的要求日益提高,异步编程成为了提升响应速度、提高系统吞吐量的重要手段。Django 作为一个成熟的 Python Web 框架,自 3.1 版本开始支持了异步编程。在本文中,我们将探讨 Django 异步编程的关键概念,并提供实际…...
力扣 138. 随机链表的复制
文章目录 1.解题思路2.代码实现 1.解题思路 在原先链表的每一个元素后面插入一个与前一个相同val的值的结点,然后由于是在原链表进行的操作,因此找每个random就变得很方便直接访问即可,此题目的精髓是cur1->randomp->random->next,看懂这串代码…...
STM32外部中断大问题
问题:一直进入中断,没有触发信号,也一直进入。 描述:开PA0为外部中断,刚刚很好,一个触发信号一个中断,中断函数没有丢,也没有抢跑,开PA1为外部中断也是,都很好…...
FPGA配置采集AR0135工业相机,提供2套工程源码和技术支持
目录 1、前言免责声明 2、AR0135工业相机简介3、我这里已有的 FPGA 图像处理解决方案4、设计思路框架AR0135配置和采集图像缓存视频输出 5、vivado工程1–>Kintex7开发板工程6、vivado工程1–>Zynq7100开发板工程7、上板调试验证8、福利:工程代码的获取 1、前…...
KubeSphere v3.4.0 部署K8S Docker + Prometheus + grafana
KubeSphere v3.4.0 部署K8S 1、整体思路2、修改linux主机名3、 离线安装3.1 问题列表3.2 执行命令成功列表 1、整体思路 将KubeSphere v3.4.0 安装包传输到其中一台机器修改Linux主机名(选取3台,修改为master01、master02、master03)安装官方…...
Codeforces Round 908 (Div. 2)题解
目录 A. Secret Sport 题目分析: B. Two Out of Three 题目分析: C. Anonymous Informant 题目分析: A. Secret Sport 题目分析: A,B一共打n场比赛,输入一个字符串由A和‘B’组成代表A赢或者B赢(无平局),因为题目说明这个人…...
Redis笔记 Redis主从同步
文章目录 Redis主从搭建主从架构主从数据同步原理全量同步增量同步repl_backlog原理 主从同步优化小结 Redis主从 搭建主从架构 单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。 主从数据…...
数据结构-Prim算法构造无向图的最小生成树
引子: 无向图如果是一个网,那么它的所有的生成树中必有一颗生成树的边的权值之和是最小的,我们称 这颗权值和最小的树为:“最小生成树”(MST)。 其中,一棵树的代价就是树中所有权值之和。 而…...
MFC串口通信(SerialPort)
目录 1、SerialPort类的介绍和使用: (1)、SerialPort类的功能介绍 (2)、SerialPort类提供接口函数的介绍 1)、InitPort函数 2)、控制串口监视线程函数 3)、获取事件,…...
Vim基本使用操作
前言:作者也是初学Linux,可能总结的还不是很到位 Linux修炼功法:初阶功法 ♈️今日夜电波:美人鱼—林俊杰 0:21━━━━━━️💟──────── 4:14 …...
【深蓝学院】手写VIO第8章--相机与IMU时间戳同步--作业
0. 题目 1. T1 逆深度参数化时的特征匀速模型的重投影误差 参考常鑫助教的答案:思路是将i时刻的观测投到world系,再用j时刻pose和外参投到j时刻camera坐标系下,归一化得到预测的二维坐标(这里忽略了camera的内参,逆深…...
Naocs配置中心配置映射List、Map、Map嵌套List等方式
一、配置映射List 1、常规逐个配置方式,示例如下: 代码: @Data @Configuration @ConfigurationProperties(prefix = "list-json-str") public class ConfListByJsonStr implements Serializable, InitializingBean {@ApiModelProperty("映射结果集")…...
如何通过CRM系统进行销售机会管理?
销售机会管理是在销售过程中对潜在客户的精细化管理,销售机会管理的本质是公司用于管理销售机会通用的工具和方法。对于希望建立长期客户关系的现代销售团队来说,CRM客户管理系统是必不可少的工具。那企业如何通过CRM系统进行销售机会管理? …...
解决idea启动tomcat控制台中文乱码
#1.tomcat日志中文乱码# 如图这种情况,一般在idea用tomcat跑一个web项目启动后tomcat日志在控制台打印出来会出现中文乱码的情况 解决方案1:tomcat的日志配置文件的编码修改,找到tomcat安装目录conf下的logging.properties,encod…...
vscode + cmake + opencv example
nice try on macos CMakeLists.txt cmake_minimum_required(VERSION 3.20) #添加OPENCV库 #指定OpenCV版本,代码如下 #find_package(OpenCV 3.3 REQUIRED) #如果不需要指定OpenCV版本,代码如下 find_package(OpenCV REQUIRED)#添加OpenCV头文件 includ…...
day57【动态规划】647.回文子串 516.最长回文子序列
文章目录 647. 回文子串516.最长回文子序列 647. 回文子串 力扣题目链接 代码随想录讲解 题意:给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的…...
分享vmware和Oracle VM VirtualBox虚拟机的区别,简述哪一个更适合我?
VMware和Oracle VM VirtualBox虚拟机的区别主要体现在以下几个方面: 首先两种软件的安装使用教程如下: 1:VMware ESXI 安装使用教程 2:Oracle VM VirtualBox安装使用教程 商业模式:VMware是一家商业公司,而…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
