当前位置: 首页 > news >正文

004——双向链表和循环链表

目录

双向链表

双向链表的初始化(与单链表类似)

增:

Ⅰ)头插法

Ⅱ)尾插法

Ⅲ)中间插入

整体代码示例:

 循环链表

循环单链表

​编辑 循环双链表


双向链表

不同于单链表,双向链表不仅可以往后指向,还可以往前指向,则双向链表是在单链表的基础上,每个结点增加一个指针域,这个指针域保存上一个结点的地址

pre指针域

(保存前一个结点的地址)

  数据域

    data

next指针域

(保存后一个结点的地址)

//双向链表的结构体
typedef struct Node {struct Node* pre;int data;struct Node* next;
}Node,*LinkList;

 由003——单链表可知,单链表分为带头结点的不带头结点的,双向链表也是同理(上图的是带头结点的)

双向链表的初始化
(与单链表类似)

LinkList InitLinkList() {Node* p = (Node*)malloc(sizeof(Node));//申请头结点if (p == NULL) {printf("空间分配失败\n");}else {//p->data	脏数据,不用管p->pre=p->next = NULL;//注意:该语句的执行方向是从右往左/*p->pre = NULL;p->next = NULL;*/}return p;
}
int main() {LinkList L = InitLinkList();
}

增:

双向链表中增加一个结点(数据)

Ⅰ)头插法

固定在头结点和首元结点之间插入一个结点(头结点之后)如下图的例子

为了方便分析,我们为示意图进行编号 

注意,在这里对数据进行处理时,我们不能使得这个线(单向的,无论是正向还是负向)断掉,比如像下面这种情况,就是错误

正确的顺序应该是先处理③和④,然后再处理①和②(顺序并不唯一)

 (下面代码并不完整)

//头插法:
LinkList HeadInsert(LinkList L, int k) {//先申请一个新的结点用来保存数据kNode* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败/n");}else {s->data = k;//将数据传给新申请的结点ss->pre = L;//3s->next = L->next;//4L->next= s;//1s->next->pre = s;//2}return L;
}

或者可以写成3421(还有其他写法)

        s->pre = L;
        s->next = L->next;
        L->next->pre = s;
        L->next = s;

此时还要考虑L为空的情况,因为这个时候的②是不存在的

所以在我们更改②这条线之前,需要进行一个判断

//头插法:
LinkList HeadInsert(LinkList L, int k) {//先申请一个新的结点用来保存数据kNode* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败/n");}else {s->data = k;//将数据传给新申请的结点ss->pre = L;//3s->next=L->next;//4L->next = s;//1if (s->next != NULL) {s->next->pre = s;//2}}return L;
}

Ⅱ)尾插法

从头结点开始遍历找到尾结点,在尾结点的后面插入新的结点(需要多维护一个pre)

//尾插法
LinkList RearInsert(LinkList L, int k) {Node* p = L;	//指针指p向头结点while (p->next != NULL) {p = p->next;}//循环结束后指针p指向最后一个结点//先申请一个新的结点用来保存数据kNode* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败\n");return L;}else {s->data = k;//将数据传给新申请的结点ss->next = p->next;s->pre = p;p->next = s;}return L;
}

Ⅲ)中间插入


//中间插入
//首先需要一个查找函数,并且返回该结点的地址
Node* find(LinkList L, int k) {Node* p = L->next;while (p != NULL && p->data != k) {//出现NULL->data!=k会报错,所以这两项的顺序不可以颠倒p = p->next;}return p;//要么为空,要么保存所要数据
}
//中间插入的函数
Node* MidInsert(LinkList L, int x, int k) {//在元素x后面插入数据kNode* p = find(L, x);if (p == NULL) {printf("数据%d不存在,无法找到插入位置,插入失败\n", x);return L;}Node* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败,插入失败\n");return L;}else {s->data = k;s->next = p->next;p->next = s;if (s->next != NULL) {s->next->pre = s;}}return L;
}

删除如下面图示

修改后的结果

 

//删除
LinkList Delete(LinkList L, int k) {if (L->next == NULL) {printf("空链表,删除失败\n");return L;}//找到k所在的结点pNode* p = find(L, k);if (p == NULL) {printf("数据%d不存在,删除失败\n");return L;}//删除p->pre->next = p->next;if (p->next != NULL) {p->next->pre = p->pre;}//防止p成为空指针free(p);p = NULL;return L;}

修改代码与单链表是相同的

//修改
LinkList Replace(LinkList L, int x, int k) {Node* p = find(L, x);if (p == NULL) {printf("数据%d不存在,无法找到修改位置,修改失败\n", x);return L;}else {p->data = k;}return L;
}

查找代码与单链表是相同的

Node* find(LinkList L, int k) {Node* p = L->next;while (p != NULL && p->data != k) {//出现NULL->data!=k会报错,所以这两项的顺序不可以颠倒p = p->next;}return p;//要么为空,要么保存所要数据
}

整体代码示例:

#include<stdio.h>
#include<stdlib.h>
//双向链表的结构体
typedef struct Node {struct Node* pre;int data;struct Node* next;
}Node,*LinkList;LinkList InitLinkList() {Node* p = (Node*)malloc(sizeof(Node));//申请头结点if (p == NULL) {printf("空间分配失败\n");}else {//p->data	脏数据,不用管p->pre=p->next = NULL;//注意:该语句的执行方向是从右往左/*p->pre = NULL;p->next = NULL;*/}return p;
}//头插法:
LinkList HeadInsert(LinkList L, int k) {//先申请一个新的结点用来保存数据kNode* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败/n");}else {s->data = k;//将数据传给新申请的结点ss->pre = L;//3s->next=L->next;//4L->next = s;//1if (s->next != NULL) {s->next->pre = s;//2}}return L;
}//尾插法
LinkList RearInsert(LinkList L, int k) {Node* p = L;	//指针指p向头结点while (p->next != NULL) {p = p->next;}//循环结束后指针p指向最后一个结点//先申请一个新的结点用来保存数据kNode* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败\n");return L;}else {s->data = k;//将数据传给新申请的结点ss->pre = p;//3s->next = p->next;//4p->next = s;//1if (s->next != NULL) {s->next->pre = s;//2}}return L;
}//中间插入
//首先需要一个查找函数,并且返回该结点的地址
Node* find(LinkList L, int k) {Node* p = L->next;while (p != NULL && p->data != k) {//出现NULL->data!=k会报错,所以这两项的顺序不可以颠倒p = p->next;}return p;//要么为空,要么保存所要数据
}
//中间插入的函数
Node* MidInsert(LinkList L, int x, int k) {//在元素x后面插入数据kNode* p = find(L, x);if (p == NULL) {printf("数据%d不存在,无法找到插入位置,插入失败\n", x);return L;}Node* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败,插入失败\n");return L;}else {s->data = k;s->next = p->next;p->next = s;if (s->next != NULL) {s->next->pre = s;}}return L;
}//修改
LinkList Replace(LinkList L, int x, int k) {Node* p = find(L, x);if (p == NULL) {printf("数据%d不存在,无法找到修改位置,修改失败\n", x);return L;}else {p->data = k;}return L;
}//删除
LinkList Delete(LinkList L, int k) {if (L->next == NULL) {printf("空链表,删除失败\n");return L;}//找到k所在的结点pNode* p = find(L, k);if (p == NULL) {printf("数据%d不存在,删除失败\n");return L;}//删除p->pre->next = p->next;if (p->next != NULL) {p->next->pre = p->pre;}//防止p成为空指针free(p);p = NULL;return L;}void show(LinkList L) {Node* p = L->next;while (p != NULL){printf("%d\t", p->data);p = p->next;}
}int main() {LinkList L = InitLinkList();L = HeadInsert(L, 10);L = HeadInsert(L, 22);L = HeadInsert(L, 16);L = HeadInsert(L, 45);L = RearInsert(L, 77);L = MidInsert(L, 77,99);L = Delete(L, 10);show(L);return 0;}

运行结果

 循环链表

循环单链表

循环链表只需要让最后一个结点的指针域指向头结点

 那么循环链表和单链表几乎没有太大差异,只是在为空的一些位置改成头结点

#include<stdio.h>
#include<stdlib.h>
typedef struct Node {int data;		//该节点的数据struct Node* next;		
}Node,*LinkList;//初始化一个带头结点的空的循环链表
LinkList InitLinkList() {Node* s = (Node*)malloc(sizeof(Node));//申请头结点if (s == NULL) {printf("空间分配失败\n");}else {//s->data	脏数据,不用管s->next = s;//改变。。。。。。。。。。。。}return s;
}//头插法:
LinkList HeadInsert(LinkList L, int k) {//先申请一个新的结点用来保存数据kNode* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败/n");}else {s->data = k;//将数据传给新申请的结点ss->next = L->next;L->next = s;}return L;
}//尾插法
LinkList RearInsert(LinkList L, int k) {Node* p = L;	//指针指p向头结点while (p->next != L) {//改变。。。。。。。。。。。。p = p->next;}//循环结束后指针p指向最后一个结点//先申请一个新的结点用来保存数据kNode* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败\n");return L;}else {s->data = k;//将数据传给新申请的结点ss->next = p->next;//改变。。。。。。。。。。。。p->next = s;}return L;
}//中间插入
//首先需要一个查找函数,并且返回该结点的地址
Node* find(LinkList L, int k) {Node* p = L->next;while (p!=L && p->data != k) {//改变。。。。。。。。。。。。
//出现NULL->data!=k会报错,所以这两项的顺序不可以颠倒p = p->next;}return p;//要么为空,要么保存所要数据
}
//中间插入的函数
Node* MidInsert(LinkList L, int x, int k) {//在元素x后面插入数据kNode* p = find(L, x);if (p == L) {//改变。。。。。。。。。。。。printf("数据%d不存在,无法找到插入位置,插入失败\n",x);return L;}Node* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败,插入失败\n");return L;}else {s->data = k;s->next = p->next;p->next = s;}return L;
}//修改
LinkList Replace(LinkList L, int x, int k) {Node* p = find(L, x);if (p == L) {//改变。。。。。。。。。。。。printf("数据%d不存在,无法找到修改位置,修改失败\n", x);return L;}else {p->data = k;}return L;
}//删除
LinkList Delete(LinkList L, int k) {if (L->next == L) {//改变。。。。。。。。。。。。printf("数据%d不存在,删除失败\n", k);return L;}//找到k所在的结点p和上一个结点Node* pre = L;Node* p = L->next;while (p!=L&&p->data!=k)//改变。。。。。。。。。。。。{pre = p;p = p->next;}if (p == L) {//改变。。。。。。。。。。。。printf("数据%d不存在,删除失败\n", k);return L;}pre->next = p->next;free(p);p = NULL;//防止p成为野指针return L;
}void show(LinkList L) {Node* p = L->next;while (p!= L)//改变。。。。。。。。。。。。{printf("%d\t", p->data);p = p->next;}
}
int main() {LinkList L = NULL;L = InitLinkList();L=HeadInsert(L,10);L = HeadInsert(L, 8);L = RearInsert(L, 15);L = MidInsert(L, 5, 55);L=Replace(L, 8, 88);L = Delete(L, 8);show(L);return 0;
}

运行结果:

 循环双链表

循环双链表与之同理


#include<stdio.h>
#include<stdlib.h>
//双向链表的结构体
typedef struct Node {struct Node* pre;int data;struct Node* next;
}Node, * LinkList;LinkList InitLinkList() {Node* p = (Node*)malloc(sizeof(Node));//申请头结点if (p == NULL) {printf("空间分配失败\n");}else {//p->data	脏数据,不用管//	p->next=p->pre=p;p->next = p;p->pre = p;}return p;
}//头插法:
LinkList HeadInsert(LinkList L, int k) {//先申请一个新的结点用来保存数据kNode* s = (Node*)malloc(sizeof(Node));if (s == NULL) {printf("空间分配失败/n");}else {s->data = k;//将数据传给新申请的结点ss->pre = L;//3s->next = L->next;//4L->next = s;//1s->next->pre = s;//2}return L;
}//尾插法
LinkList RearInsert(LinkList L, int k) {Node* s = (Node*)malloc(sizeof(Node));if (s == NULL){printf("空间分配失败\n");return L;}s->data = k;//找尾节点Node* p = L;while (p->next != L){p = p->next;}s->next = p->next;s->pre = p;p->next = s;s->next->pre = s;return L;
}//中间插入
//首先需要一个查找函数,并且返回该结点的地址
Node* find(LinkList L, int k) {//查找数据k所在的节点,并且返回该节点的地址 Node* p = L->next;while (p != L && p->data != k){p = p->next;}return p;
}
//中间插入的函数
Node* MidInsert(LinkList L, int x, int k) {//数据x后插入数据k Node* s = (Node*)malloc(sizeof(Node));if (s == NULL){printf("空间分配失败\n");return L;}s->data = k;//找x所在节点 Node* p = find(L, x);if (p == L){printf("数据%d不存在,插入失败\n", x);return L;}s->pre = p;//3s->next = p->next;//4p->next = s;//1s->next->pre = s;//2return L;}//修改
LinkList Replace(LinkList L, int x, int k) {Node* p = find(L, x);if (p == L) {printf("数据%d不存在,无法找到修改位置,修改失败\n", x);return L;}else {p->data = k;}return L;
}//删除
LinkList Delete(LinkList L, int k) {if (L->next == L){printf("空链表,删除失败\n");return L;}//找k所在的节点pNode* p = find(L, k);if (p == L){printf("数据%d不存在,删除失败\n", k);return L;}//删除:p->pre->next = p->next;p->next->pre = p->pre;free(p);p = NULL;return L;
}void show(LinkList L) {Node* p = L->next;while (p != L){printf("%d\t", p->data);p = p->next;}
}int main() {LinkList L = InitLinkList();L = HeadInsert(L, 10);L = HeadInsert(L, 22);L = HeadInsert(L, 16);L = HeadInsert(L, 45);L = RearInsert(L, 77);L = MidInsert(L, 77, 99);L = Delete(L, 10);show(L);return 0;}

 运行结果:

相关文章:

004——双向链表和循环链表

目录 双向链表 双向链表的初始化&#xff08;与单链表类似&#xff09; 增&#xff1a; Ⅰ&#xff09;头插法 Ⅱ&#xff09;尾插法 Ⅲ&#xff09;中间插入 删 改 查 整体代码示例&#xff1a; 循环链表 循环单链表 ​编辑 循环双链表 双向链表 不同于单链表&…...

framebuffer帧缓存

framebuffer:帧缓冲&#xff0c;帧缓存 Linux内核为显示提供的一套应用程序接口。&#xff08;驱动内核支持&#xff09; framebuffer本质上是一块显示缓存&#xff0c;往显示缓存中写入特定格式的数据就意味着向屏幕输出内容。framebuffer驱动程序控制LCD显示设备&#xff0…...

24_竞赛中的高效并查集

菜鸟&#xff1a;老鸟&#xff0c;我最近在做一个与社交网络相关的项目&#xff0c;需要频繁地检查两个用户是否属于同一个群组。但我发现每次检查都很耗时&#xff0c;性能很差。你有什么建议吗&#xff1f; 老鸟&#xff1a;你可以试试使用并查集&#xff08;Union-Find&…...

新手c语言讲解及题目分享(十七)--运算符与表达式专项练习

本文主要讲解c语言的基础部分&#xff0c;运算符与表达式的学习&#xff0c;在这一部分中&#xff0c;往往有许多细节的东西需要去记住。当各种运算符一起用时&#xff0c;就会存在优先级的关系&#xff0c;本文末尾有各种运算符的优先级顺序表。 参考书目和推荐学习书目&#…...

香帅的金融学讲义:深入剖析与解读

香帅的金融学讲义&#xff1a;深入剖析与解读 金融学&#xff0c;这个看似高深复杂的学科&#xff0c;实则与我们的生活息息相关。从个人理财到国家宏观经济政策&#xff0c;金融学无处不在。那么&#xff0c;如何更好地理解金融学呢&#xff1f;今天&#xff0c;我们就来借助…...

java基础-IO(6)转换流InputStreamReader、OutputStreamWriter

引入&#xff1a; 从第一节可知&#xff0c;流分为两类&#xff1a;字节流和字符流&#xff0c;转换流就是在两者之间进行转换。 字节流转换为字符流&#xff1b; 字符流转换为字节流。 字符集 字符集&#xff1a;定义了可用字符及其对应的数字编码的集合。常见的字符集有UT…...

使用Azure Devops Pipeline将Docker应用部署到你的Raspberry Pi上

文章目录 1. 添加树莓派到 Agent Pool1.1 添加pool1.2 添加agent 2. 将树莓派添加到 Deployment Pool2.1 添加pool2.2 添加target 3. 添加编译流水线3.1 添加编译命令3.2 配置触发器 4. 添加发布流水线4.1 添加命令行4.2 配置artifact和触发器 5. 完成 1. 添加树莓派到 Agent P…...

91、K8s之ingress上集

一、Ingress service模式&#xff1a; loadbalance NodePort&#xff1a;每个节点都会有一个指定的端口 30000-32767 内网 clusterip&#xff1a;默认模式&#xff0c;只能pod内部访问 externalName&#xff1a;需要dns提供域名 1.1、对外提供服务的ingress service&…...

NISP 一级 | 2.1 密码学

关注这个证书的其他相关笔记&#xff1a;NISP 一级 —— 考证笔记合集-CSDN博客 通过上一章的学习&#xff0c;我们知道了&#xff0c;网络安全的 CIA 模型&#xff0c;而本期学习的“密码学”&#xff0c;则能为 CIA 模型提供很好的技术支持&#xff1a; 面临的攻击威胁所破坏…...

深度学习速通系列:混淆矩阵是什么

混淆矩阵&#xff08;Confusion Matrix&#xff09;是一种评估分类模型性能的工具&#xff0c;尤其在监督学习中用于分析分类结果。它通过一个矩阵的形式&#xff0c;将模型的预测结果与实际标签进行比较&#xff0c;从而可以清晰地看到模型在各个类别上的表现。以下是混淆矩阵…...

综合评价 | 基于熵权-变异系数-博弈组合法的综合评价模型(Matlab)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 根据信息熵的定义&#xff0c;对于某项指标&#xff0c;可以用熵值来判断某个指标的离散程度&#xff0c;其信息熵值越小&#xff0c;指标的离散程度越大&#xff0c; 该指标对综合评价的影响&#xff08;即权重&…...

模板与泛型编程笔记(一)

1. 推荐书籍 《C新经典 模板与泛型编程》难得的很容易看得懂的好书&#xff0c;作者讲技术不跳跃&#xff0c;娓娓道来&#xff0c;只要花点时间就能看懂。 2. 笔记 模板为什么要用尖括号&#xff1f;因为便于编译器解析&#xff0c;可以将模板和普通函数声明分开。其实尖括…...

ubuntu 和windows用samba服务器实现数据传输

1&#xff0c;linux安装samba服务器 sudo apt-get install samba samba-common 2&#xff0c;linux 配置权限&#xff0c;修改目录权限&#xff0c;linux下共享的文件权限设置。 sudo chmod 777 /home/lark -R 3. 添加samba用户 sudo smbpasswd -a lark 4&#xff0c;配置共享…...

NISP 一级 | 3.2 网络安全威胁

关注这个证书的其他相关笔记&#xff1a;NISP 一级 —— 考证笔记合集-CSDN博客 网络安全威胁主要来自攻击者对网络及信息系统的攻击&#xff0c;攻击者可以通过网络嗅探、网络钓鱼、拒绝服务、远程控制、社会工程学等网络攻击手段&#xff0c;获得目标计算机的控制权&#xff…...

【技术实践】MySQL分表分库全解析:从理论到实战

文章目录 【技术实践】MySQL分表分库全解析&#xff1a;从理论到实战1. 引言1.1 MySQL数据库面临的挑战1.2 分表分库的概念与优势 2. MySQL分表分库的基本原理2.1 水平分表2.2 垂直分表2.3 水平分库2.4 分表分库的选择标准 3. 实现分表分库的技术方案3.1 中间件解决方案3.2 自定…...

动手学深度学习(一)简介+预备知识+基础知识(上)

一、简介 1、机器学习 机器学习研究如何使用经验改善计算机系统的性能。 2、表征学习 表征学习是机器学习的一类&#xff0c;研究的是&#xff0c;如何自动学习出数据合适的表示方式&#xff0c;更好地由输入得到正确的输出。 3、深度学习 深度学习是具有多级表示的表征学…...

dubbo 服务消费原理分析之应用级服务发现

文章目录 前言一、MigrationRuleListener1、迁移状态模型2、Provider 端升级3、Consumer 端升级4、服务消费选址5、MigrationRuleListener.onRefer6、MigrationRuleHandler.doMigrate6、MigrationRuleHandler.refreshInvoker7、MigrationClusterInvoker.migrateToApplicationFi…...

QT如何在对话框中插入表格

在Qt中&#xff0c;如果你想要在对话框中插入表格&#xff0c;通常会使用QTableWidget或QTableView结合QStandardItemModel&#xff08;对于QTableView&#xff09;或直接在QTableWidget中操作。这里&#xff0c;我将介绍如何使用QTableWidget在对话框中插入表格&#xff0c;因…...

如何使用SSHFS通过SSH挂载远程文件系统?

SHFS&#xff08;SSH 文件系统&#xff09;是一款功能强大的工具&#xff0c;它允许用户通过 SSH 挂载远程文件系统&#xff0c;从而提供一种安全便捷的方式来访问远程文件&#xff0c;就像访问本地文件一样。本文将引导您完成使用 SSHFS 挂载远程文件系统的过程&#xff0c;为…...

SEELE 框架是

SEELE 框架是一个相对新颖的组织管理和优化框架&#xff0c;旨在帮助团队或企业更好地实现目标。它的核心思想是通过科学的管理方法来提升组织的执行力和决策能力。以下是对 SEELE 框架的详细讲解&#xff0c;包括定义、内容、实施步骤、实施策略以及推荐的实践方法和工具。 一…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...