【C】初阶数据结构4 -- 双向循环链表
之前学习的单链表相比于顺序表来说,就是其头插和头删的时间复杂度很低,仅为O(1) 且无需扩容;但是对于尾插和尾删来说,由于其需要从首节点开始遍历找到尾节点,所以其复杂度为O(n)。那么有没有一种结构是能使得头插和头删的时间复杂度都为 O(1) 的呢?那么这个结构就是双向循环链表。
目录
1 链表的分类
2 双向循环带头链表的结构
1) 逻辑结构
2) 物理结构
3 双向循环带头链表操作的实现
1) 初始化和销毁
(1) 初始化
(2) 销毁
2) 头插与头删
(1) 头插
(2) 头删
3) 尾插和尾删
(1) 尾插
(2) 尾删
4) 在pos位置之前插入和删除pos节点
(1) 在pos位置之前插入
(2) 删除pos节点
5) 判空和查找
4 代码
5 顺序表与链表的对比
1 链表的分类
链表分类总共根据以下3个因素来分类:
1) 带头或者不带头2) 循环或者不循环3) 单向或者双向
其中带头的意思是:链表中有一个头节点,也叫哨兵位,这个头节点仅仅用来当做链表的开始节点,并不存储任何有效数据。有头节点的好处是插入数据时不必再判断链表为空的情况。所以带头节点的链表从物理结构上来说是不会为空链表的。
其中循环的意思是:链表最后一个节点并不指向NULL,而是指向开始节点,以此来达到循环的效果。所以找到循环链表的尾节点,并不是判断尾节点的next为不为NULL,而是看尾节点的next指针是否指向开始节点。
其中单或双向意思是:是否能够通过节点内部指针找到下一个节点或者前一个节点。只能找到下一个节点的链表就是单向链表;能够找到前一个和后一个节点的链表就是双向链表。
为了更好的理解不同链表的结构,在这里可以画一下双向不循环带头链表的结构:
按照以上因素,链表共分为 8 种,分别是:
单向不循环不带头链表 | 双向不循环不带头链表 |
---|---|
单向循环不带头链表 | 双向循环不带头链表 |
单向不循环带头链表 | 双向不循环带头链表 |
单项循环带头链表 | 双向循环带头链 |
所以之前单链表的全称应该是单向不循环不带头链表。
重点一 双向循环带头链表节点结构
2 双向循环带头链表的结构
1) 逻辑结构
有了之前分类的铺垫,双向循环带头链表(以下简称为双向链表)的逻辑结构就很好画出来了:
2) 物理结构
链表是由节点组成的,所以定义链表的物理结构也就是定义链表节点的结构,通过对逻辑结构的分析,可以发现双向链表的结构共有3个域组成,一个是存储数据的数据域(data),还有一个存储下一个节点地址的指针域(next),还有一个存储前一个节点地址的指针域(prev):
//定义数据类型
typedef int LTDataType;
//定义双向链表结点的结构
typedef struct ListNode
{LTDataType data;//结点里的数据struct ListNode* prev;//前驱指针,指向前一个结点struct ListNode* next;//后继指针,指向后一个结点
}LTNode;
同样的,双向链表并不一定只存储整型,所以要用 LTDataType 来 typedef 一下整型,以后如果要存储其他类型的数据,只需要改这一个地方就可以了。
重点二 双向循环带头链表的实现
3 双向循环带头链表操作的实现
对于双向链表,其常用的操作主要有初始化、销毁、头插、头删、尾插、尾删、在pos位置之后插入、删除pos节点、判空以及查找。
虽然双向链表比单链表的结构复杂,但是由于其结构的天然优势,其操作实现实现起来会比单链表简单很多,且不需要考虑链表为空的情况。
1) 初始化和销毁
(1) 初始化
对于双向链表的初始化,由于其结构的特殊性,必须保证是带头且循环,所以在初始化里面就要开辟一个节点,使这个节点成为链表的头节点,让其 next 指针和 prev 指针都指向自己,所以一个逻辑上为空的双向链表物理结构为:
这样才能保证其循环和带头的特性。
(2) 销毁
销毁的话也不是像单链表一样从头节点开始销毁,而是从头节点后面的节点开始销毁,因为最后一个节点的 next 指针是指向头节点的,由于其循环的特性,判断除头节点之外的节点是否都销毁了就是看遍历链表的指针是否指向头节点。
所以这里定义一个 pcur 指针指向头节点的下一个节点,然后循环判断 pcur 是否等于 phead(头节点的地址),在循环里面先保存 pcur 下一个节点的地址 next,然后释放当前节点,再让 pcur 指向下一个节点,最后释放头节点。
2) 头插与头删
(1) 头插
头插有一个需要注意的点:头插是在头节点的后面,头节点后面的第一个节点的前面插入,而不是在头节点的前面插入(在头节点前面插入相当于尾插)。
头插过程如图:
在头插改变指针指向的时候,有一个需要注意的点:一定要最后在 newnode 节点改变next 和 prev 指针指向之后,再改变 phead->next 节点的指向,因为如果先改变 phead->next 节点的指向,那么原来的 phead->next 就找不到了,newnode->next 指针也就没法指向下一个节点了。当然,如果事先保存了 phead->next 节点的地址,先改变谁的指向也就无所谓了。
我们再来看一下特殊情况,那就是只有一个头节点的情况(可以结合下面的代码):当只有一个头节点时,此时phead->next 与 phead->prev 都指向 phead,头插的时候只会改变指针的指向,也不会出现对NULL指针的解引用的特殊情况,所以对于只有一个头节点的双向链表也是可以的。
(2) 头删
既然是删除节点,就先要判断链表为不为空(链表中只剩一个头节点)。双向链表的头删如下图所示:
3) 尾插和尾删
(1) 尾插
在尾插这一接口的实现过程中,可以真正看到双向链表与单链表结构的区别带来的优势,在单链表里面,尾插的时间复杂度仍未O(n),而在双向链表里面,时间复杂度仅为O(1),只需改变指针的指向即可,尾插的过程如图所示:
同样的,尾插对于只有一个头节点的双向链表来说,也不需要特殊处理,因为仅仅改变指针的指向,也不存在对NULL指针的解引用,且逻辑也是可以的。
(2) 尾删
尾删需要先判断链表是否为空(即是否仅有一个头节点)。尾删的过程如图:
4) 在pos位置之前插入和删除pos节点
(1) 在pos位置之前插入
在pos位置之后插入数据,首先先要保证pos位置是有效的位置(即pos不为NULL)。在pos位置之后插入数据和头插、尾插一样,只需要改变指针的指向即可:先开辟一个新的节点 newnode,让 newnode->prev 指向 pos,newnode->next 指向 pos->next指向的节点,再让 newnode->next->prev 指向 newnode,pos->next 指向 newnode(这里就不画图了,逻辑比较简单,依照前两个插入画图即可)。
(2) 删除pos节点
既然是删除节点,那就需要判断链表为不为空。然后删除pos节点也只需改变指针的指向,然后释放pos节点即可。先让 pos->next->prev 指向 pos->prev,再让 pos->prev->next 指向 pos->next,然后释放 pos 即可。
但是删除完 pos 节点之后要把原来传给 LTErase函数(删除pos节点的函数)pos 形参的实参给置为NULL,因为pos节点释放之后,原来的形参就变为了野指针,使用会发生越界访问。
5) 判空和查找
这两个接口比较简单,判空只需要判断 phead->next(phead为指向头节点的指针)是否等于phead ;而查找的话只需要遍历链表,对比每个节点内的值是否是需要查找的值,如果是,返回该节点的地址;如果不是,那就继续判断下一个节点,直到遍历完整个链表,返回NULL。
查找时只需要有一点需要注意,就是判断是否遍历完链表的条件为 pcur (遍历链表时指向每个节点的指针变量)是否等于phead(指向头节点的指针),而不是 pcur 是否等于 NULL。
4 代码
1) List.h文件:
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>//定义数据类型
typedef int LTDataType;
//定义双向链表结点的结构
typedef struct ListNode
{LTDataType data;//结点里的数据struct ListNode* prev;//前驱指针,指向前一个结点struct ListNode* next;//后继指针,指向后一个结点
}LTNode;//初始化
LTNode* LTInit();
//销毁
void LTDestroy(LTNode* phead);
//打印
void LTPrint(LTNode* phead);
//判空
bool LTEmpty(LTNode* phead);
//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//头删
void LTPopFront(LTNode* phead);
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x);
//删除pos位置数据
void LTErase(LTNode* pos);
//查找数据
LTNode* LTFind(LTNode* phead, LTDataType x);
2) List.c文件:
#include"List.h"//开辟新结点
LTNode* buyNode(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc fail!\n");exit(1);}newnode->data = x;newnode->prev = newnode->next = newnode;return newnode;
}//初始化
LTNode* LTInit()
{//创建一个头节点,不存储任何有效数据LTNode* phead = (LTNode*)malloc(sizeof(LTNode));//要让头节点的前驱指针与后继指针都指向自己,才能循环phead->prev = phead->next = phead;return phead;
}
//销毁
void LTDestroy(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}//最后释放头结点free(phead);phead = NULL;
}
//打印
void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){printf("%d ", pcur->data);pcur = pcur->next;}printf("\n");
}
//判空
bool LTEmpty(LTNode* phead)
{//只需判断头结点的下一个结点是不是头节点return phead->next == phead;
}//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{//由于有头节点,所以不需判断头节点是否为空LTNode* newnode = buyNode(x);//phead phead->prev newnode 改变这三个结点指针的指向newnode->next = phead;newnode->prev = phead->prev;phead->prev->next = newnode;phead->prev = newnode;
}//尾删
void LTPopBack(LTNode* phead)
{//删除先判空assert(!LTEmpty(phead));//把要删除的结点设为del结点LTNode* del = phead->prev;//del->prev phead 改变这两个结点的指向del->prev->next = phead;phead->prev = del->prev;free(del);del = NULL;
}//头插
void LTPushFront(LTNode* phead, LTDataType x)
{//不是插入头节点,而是在头节点后面插入一个结点LTNode* newnode = buyNode(x);//phead newnode phead->next 改变这三个结点之间的指向newnode->prev = phead;newnode->next = phead->next;phead->next->prev = newnode;phead->next = newnode;
}//头删
void LTPopFront(LTNode* phead)
{//先判断是否为空assert(!LTEmpty(phead));LTNode* del = phead->next;phead->next = del->next;del->next->prev = phead;//释放del节点free(del);del = NULL;
}//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = buyNode(x);//pos newnode pos->nextnewnode->prev = pos;newnode->next = pos->next;pos->next->prev = newnode;pos->next = newnode;
}//删除pos位置数据
//删除完pos位置数据之后,要把原来实参位置置为NULL,否则原指针会变成野指针
void LTErase(LTNode* pos)
{assert(pos);//pos->prev pos pos->nextpos->prev->next = pos->next;pos->next->prev = pos->prev;free(pos);pos = NULL;
}//查找数据
LTNode* LTFind(LTNode* phead, LTDataType x)
{LTNode* pcur = phead->next;//这里必须判断pcur是否等于phead,不能判断pcur是否为NULLwhile (pcur != phead){if (pcur->data == x)return pcur;pcur = pcur->next;}return NULL;
}
3) test.c文件:
#include "List.h"void Test3()
{LTNode* phead = LTInit();//测试头插/* LTPushFront(phead, 1);LTPushFront(phead, 2);LTPushFront(phead, 3);LTPushFront(phead, 4);LTPrint(phead);*///测试头删/*LTPopFront(phead);LTPopFront(phead);LTPopFront(phead);LTPopFront(phead);*///LTPopFront(phead);//测试尾插LTPushBack(phead, 1);LTPushBack(phead, 2);LTPushBack(phead, 3);LTPushBack(phead, 4);LTPrint(phead);测试尾插//LTPopBack(phead);//LTPopBack(phead);//LTPopBack(phead);//LTPopBack(phead);//LTPopBack(phead);//LTPrint(phead);//测试查找LTNode* ret = LTFind(phead, 4);/*if (ret == NULL){printf("没找到!\n");}elseprintf("找到了!\n");*///测试在pos位置之前插入数据//LTInsert(ret, 6);LTErase(ret);LTPrint(phead);LTDestroy(phead);}
int main()
{Test3();return 0;
}
5 顺序表与链表的对比
最后,我们再来对比一下顺序表与链表。顺序表与链表作为数据结构中最基础的线性表,他们的差异还是挺大的,具体体现在以下几个方面:
不同点 | 顺序表 | 双向链表 |
---|---|---|
存储空间 | 数组,物理结构上是连续的 | 一个一个节点,物理结构上不连续 |
能否随机访问 | 可以,时间复杂度为O(1) | 不支持,需要从头遍历 |
插入数据或者删除数据效率对比 | 需要频繁挪动数据,复杂度为O(n) | 只需改变指针指向,复杂度为O(1) |
插入时开辟空间对比 | 满了需要扩容,且有时会造成空间的浪费 | 没有容量,按需申请。不会浪费空间 |
应用场景 | 元素高效存储和频繁访问 | 频繁插入和删除数据 |
相关文章:
【C】初阶数据结构4 -- 双向循环链表
之前学习的单链表相比于顺序表来说,就是其头插和头删的时间复杂度很低,仅为O(1) 且无需扩容;但是对于尾插和尾删来说,由于其需要从首节点开始遍历找到尾节点,所以其复杂度为O(n)。那么有没有一种结构是能使得头插和头删…...
【动态路由】系统Web URL资源整合系列(后端技术实现)【nodejs实现】
需求说明 软件功能需求:反向代理功能(描述:apollo、eureka控、apisix、sentinel、普米、kibana、timetask、grafana、hbase、skywalking-ui、pinpoint、cmak界面、kafka-map、nacos、gateway、elasticsearch、 oa-portal 业务应用等多个web资…...
解读 Flink Source 接口重构后的 KafkaSource
前言 Apache Kafka 和 Apache Flink 的结合,为构建实时流处理应用提供了一套强大的解决方案[1]。Kafka 作为高吞吐量、低延迟的分布式消息队列,负责数据的采集、缓冲和分发;而 Flink 则是功能强大的流处理引擎,负责对数据进行实时…...
一场始于 Selector Error 的拯救行动:企查查数据采集故障排查记
时间轴呈现事故进程 17:00:开发人员小李正在尝试利用 Python 爬虫从企查查(https://www.qcc.com)抓取公司工商信息。原本一切正常,但突然发现信息采集失败,程序抛出大量选择器错误。17:15:小李发现&#x…...
代码随想录刷题攻略---动态规划---子序列问题1---子序列
子序列(不连续)和子序列(连续)的问题 例题1: 最长递增子序列 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的…...
QEMU 搭建arm linux开发环境
Qemu 作为一款强大的开源虚拟化软件,为我们提供了一个便捷且经济实惠的方式来模拟各种硬件环境,从而在上面安装和学习 Linux 系统。本文将详细介绍如何使用 Qemu 搭建 Linux 学习环境, 环境准备 操作系统:建议使用 Ubuntu 20.04…...
PyQt组态软件 拖拽设计界面测试
PyQt组态软件测试 最近在研究PyQt,尝试写个拖拽设计界面的组态软件,目前实现的功能如下: 支持拖入控件,鼠标拖动控件位置 拖动控件边缘修改控件大小支持属性编辑器,修改当前选中控件的属性 拖动框选控件,点选控件 控…...
JAVA泛型介绍与举例
Java中,泛型用于编译阶段限制集合中元素的类型,或者限制类中某个属性的类型,编译过程中发生类型擦除,最终还是Object类型。 1. 集合中的泛型 集合默认可以存储任何类型的元素,即Object类型,当使用一个集合…...
JavaScript 内置对象-Math对象
在JavaScript中,Math 对象提供了一系列与数学相关的静态方法和属性,帮助开发者执行复杂的计算任务。无论是简单的算术运算还是高级的几何、统计计算,Math 对象都能提供强大的支持。本文将详细介绍 Math 对象的主要功能及其使用方法。 一、简…...
Ubuntu 22.04 Desktop企业级基础配置操作指南
一、网络配置 cd /etc/netplan vi 00-installer-config.yaml 设置如下所示: network:version: 2ethernets:eth0: # 替换为你的实际网络接口名称,如 ens33, enp0s3 等dhcp4: noaddresses:- 192.168.1.100/24 # 静态IP地址和子网掩码gateway4: 192.16…...
UE_C++ —— UObject Instance Creation
目录 一,UObject Instance Creation NewObject NewNamedObject ConstructObject Object Flags 二,Unreal Object Handling Automatic Property Initialization Automatic Updating of References Serialization Updating of Property Values …...
WPF的MVVMLight框架
在NuGet中引入该库: MVVMLight框架中的命令模式的使用: <StackPanel><TextBox Text"{Binding Name}"/><TextBox Text"{Binding Title}"/><Button Content"点我" Command"{Binding ShowCommand…...
【云安全】云原生- K8S kubeconfig 文件泄露
什么是 kubeconfig 文件? kubeconfig 文件是 Kubernetes 的配置文件,用于存储集群的访问凭证、API Server 的地址和认证信息,允许用户和 kubectl 等工具与 Kubernetes 集群进行交互。它通常包含多个集群的配置,支持通过上下文&am…...
binance python
binance-futures-connector 4.1.0 from binance.um_futures import UMFutures # U本位 USDT-M Futures /fapi/* # 币本位 COIN-M Delivery /dapi/* proxies { https: http://localhost:7890 } client UMFutures(proxiesproxies)apiKey"" apiSecret"" cl…...
LLaMA-Factory DeepSeek-R1 模型 微调基础教程
LLaMA-Factory 模型 微调基础教程 LLaMA-FactoryLLaMA-Factory 下载 AnacondaAnaconda 环境创建软硬件依赖 详情LLaMA-Factory 依赖安装CUDA 安装量化 BitsAndBytes 安装可视化微调启动 数据集准备所需工具下载使用教程所需数据合并数据集预处理 DeepSeek-R1 可视化微调数据集处…...
利用亚马逊云科技RDS for SQL Server配置向量数据存储
生成式人工智能(AI)正迎来又一个快速发展期,引起了开发者们的广泛关注。将生成式能力集成到商业服务和解决方案中变得非常重要。当前的生成式AI解决方案是机器学习和深度学习模型逐步进化迭代的结果。从深度学习到生成式AI的质变飞跃主要是由…...
ASP.NET Core SixLabors.ImageSharp v1.0 的图像实用程序类 web示例
这个小型实用程序库需要将 NuGet SixLabors.ImageSharp包(版本 1.0.4)添加到.NET Core 3.1/ .NET 6 / .NET 8项目中。它与Windows、Linux和 MacOS兼容。 这已针对 ImageSharp v3.0.1 进行了重新设计。 它可以根据百万像素数或长度乘以宽度来调整图像大…...
JVM 底层探秘:对象创建的详细流程、内存分配机制解析以及线程安全保障策略
文章目录 1. 类加载检查2. 内存分配① 指针碰撞② 空闲列表线程安全问题: 3. 内存空间初始化4. 对象头设置5. 对象初始化 当Java虚拟机遇到一条 new指令时,会执行以下步骤来创建对象: 1. 类加载检查 首先检查new指令的参数是否能在常量池中…...
SpringCloud框架下的注册中心比较:Eureka与Consul的实战解析
摘要 在探讨SpringCloud框架中的两种注册中心之前,有必要回顾单体架构与分布式架构的特点。单体架构将所有业务功能集成在一个项目中,优点是架构简单、部署成本低,但耦合度高。分布式架构则根据业务功能对系统进行拆分,每个模块作…...
应对DeepSeek总是服务器繁忙的解决方法
最近由于访问量过大,DeepSeek服务器官网经常弹出:“服务器繁忙,请稍后再试”的提示,直接卡成PPT怎么办?服务器繁忙直接看到视觉疲劳: 解决DeepSeek卡顿问题 DeepSeek使用卡顿问题,是因为访问量…...
C++ 实践扩展(Qt Creator 联动 Visual Studio 2022)
这里我们将在 VS 上实现 QT 编程,实现如下: 一、Vs 2022 配置(若已安装,可直接跳过) 点击链接:Visual Studio 2022 我们先去 Vs 官网下载,如下: 等待程序安装完成之…...
JENKINS(全面)
一.linux系统中JENKINS的安装 注意:安装jenkins需要安装jdk,而且具体版本的jenkins有相对应的jdk版本。可参考以下链接。 Redhat Jenkins 软件包https://pkg.jenkins.io/redhat-stable/https://pkg.jenkins.io/redhat-stable/https://pkg.jenkins.io/r…...
72.git指南(简单)
Git 操作指南 在开始之前,请确保你已经提前配置好 .gitignore 文件,以避免不必要的文件被 Git 跟踪。如果在初始化仓库后再配置 .gitignore 文件,之前添加的文件仍会被跟踪,需要手动移除。 如下例子忽略了文件夹及文件夹内所有内…...
LeetCode 232: 用栈实现队列
LeetCode 232: 用栈实现队列 题目描述 使用栈实现队列的操作。支持以下操作: MyQueue():初始化队列。push(x):将元素 x 推入队列。pop():从队列中移除元素。peek():返回队列头部的元素。empty():检查队列…...
C#关于静态关键词static详解
Demo代码: public class HomeController : Controller {private DateTime time1 DateTime.Now; // 实例字段private static DateTime time2 DateTime.Now; // 静态字段[HttpGet("index")]public async Task Index(){Console.WriteLine($"now&am…...
【Pico】使用Pico进行无线串流搜索不到电脑
使用Pico进行无线串流搜索不到电脑 官串方式:使用Pico互联连接电脑。 故障排查 以下来自官方文档 请按照以下步骡排除故障: 确认电脑和一体机连接了相同的路由器WiFi网络(相同网段) IP地址通常为192.168.XX,若两设备的IP地址前三段相同&…...
细说STM32F407单片机RTC的基本原理及闹钟和周期唤醒功能的使用方法
目录 一、RTC基础知识 1、 RTC的功能 2、RTC工作原理 (1)RTC的时钟信号源 (2)预分频器 (3)实时时钟和日历数据 (4)周期性自动唤醒 (5)可编程闹钟 &a…...
ES用脚本更新异常
因为需要向原有的es结构中增加一个检索字段,但因为历史es数据都没有该字段,需要批量刷新es的该字段,本地使用了脚本的方式进行刷新,在测试环境测试,出现了以下错误: 500 Internal Server Error: [{"e…...
Navicat导入海量Excel数据到数据库(简易介绍)
目录 前言正文 前言 此处主要作为科普帖进行记录 原先Java处理海量数据的导入时,由于接口超时,数据处理不过来,后续转为Navicat Navicat 是一款功能强大的数据库管理工具,支持多种数据库系统(如 MySQL、PostgreSQL、…...
C++学习
C对C语言的加强 1.命名空间(namespace) 为了避免,在大规模程序的设计中,以及在程序员使用各种各样的C库时,这些标识符的命名发送冲突。 标准C引入了关键字namespace,可以更好地控制标识符的作用域。 st…...
Linux Mem -- Where the mte store and check in the real hardware platform
目录 1 前言 2 MTE tag分类 3 Address tag 4 Memory tag 5 Tag Check 6 Cortex-A710 和 CI-700 系统示例: 1 前言 ARM的MTE允许分配、设置、比较一个 4bit的allocation tag 为16字节粒度的物理地址。当对MTE有一定了解后,应该会产生如下疑问&#…...
老牌软件,如今依旧坚挺
今天给大家介绍一个非常好用的老牌电脑清理软件,这个软件好多年之前就有人使用了。 今天找出来之后,发现还是那么的好用,功能非常强大。 Red Button 电脑清理软件 软件是绿色版,无需安装,打开这个图标就能直接使用了…...
springboot整合modbus实现通讯
springboot整合modbus4j实现tcp通讯 前言 本文基于springboot和modbus4j进行简单封装,达到开箱即用的目的,目前本方案仅实现了tcp通讯。代码会放在最后,按照使用方法操作后就可以直接使用 介绍 在使用本方案之前,有必要对modb…...
【java面试】线程篇
1.什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。 2.线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任…...
DeepSeek官方发布R1模型推荐设置
今年以来,DeepSeek便在AI领域独占鳌头,热度一骑绝尘。其官方App更是创造了惊人纪录,成为史上最快突破3000万日活的应用,这一成绩无疑彰显了它在大众中的超高人气与强大吸引力。一时间,各大AI及云服务厂商纷纷投身其中&…...
Vue CLI 配置与插件
Vue CLI 配置与插件 今天我们来聊聊 Vue CLI 的配置与插件。随着项目复杂度的增加,合理配置 Vue CLI 可以帮助我们更高效地管理项目,同时利用插件机制快速集成各种功能。下面我就和大家详细介绍如何配置 Vue CLI,以及如何使用和开发插件&…...
Spring Boot (maven)分页3.0版本 通用版
前言: 通过实践而发现真理,又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识,又从理性认识而能动地指导革命实践,改造主观世界和客观世界。实践、认识、再实践、再认识,这种形式,循环往…...
pip 与 conda 的故事
pip 换源 pip 官方源 -i https://pypi.python.org/simple pip 清华源 -i https://pypi.tuna.tsinghua.edu.cn/simple pip 阿里源 -i https://mirrors.aliyun.com/pypi/simple PyTorch 安装 pip3 install torch torchvision torchaudio pip3 install torch torchvision torchaud…...
清华大学KVCache.AI团队联合趋境科技联合的KTransformers开源项目为什么那么厉害
KTransformers是一个由清华大学KVAV.AI团队开发的开源项目,旨在优化大语言模型(LLM)的推理性能,特别是在有限显存资源下运行大型模型。以下是KTransformers的详细介绍: 1. 核心特点 高性能优化:KTransfor…...
DeepSeek 遭 DDoS 攻击背后:DDoS 攻击的 “千层套路” 与安全防御 “金钟罩”_deepseek ddos
当算力博弈升级为网络战争:拆解DDoS攻击背后的技术攻防战——从DeepSeek遇袭看全球网络安全新趋势 在数字化浪潮席卷全球的当下,网络已然成为人类社会运转的关键基础设施,深刻融入经济、生活、政务等各个领域。从金融交易的实时清算…...
4090单卡挑战DeepSeek r1 671b:尝试量化后的心得的分享
引言: 最近,DeepSeek-R1在完全开源的背景下,与OpenAI的O1推理模型展开了激烈竞争,引发了广泛关注。为了让更多本地用户能够运行DeepSeek,我们成功将R1 671B参数模型从720GB压缩至131GB,减少了80%ÿ…...
【动态路由】系统Web URL资源整合系列(后端技术实现)【apisix实现】
需求说明 软件功能需求:反向代理功能(描述:apollo、eureka控、apisix、sentinel、普米、kibana、timetask、grafana、hbase、skywalking-ui、pinpoint、cmak界面、kafka-map、nacos、gateway、elasticsearch、 oa-portal 业务应用等多个web资…...
【Elasticsearch】通过运行时字段在查询阶段动态覆盖索引字段
在 Elasticsearch 中,Override field values at query time是指通过运行时字段(runtime fields)在查询阶段动态覆盖索引字段的值,而无需修改原始索引数据。这种功能特别适用于以下场景: 1. 动态修改字段值:…...
【stm32】定时器
stm32f4xx: APB2 ----> TIM1,TIM8,TIM9,TIM10,TIM11 APB1 ----> TIM2,TIM3,TIM4,TIM5,TIM6,TIM7,TIM12,TIM13,TIM14 一、定时器介绍 1、基本定时器 1.1、TIM6 和 TIM7 的主要特性 ● 16 位自动重载递增计数器 ● 16 位可编程…...
滑动窗口算法篇:连续子区间与子串问题
1.滑动窗口原理 那么一谈到子区间的问题,我们可能会想到我们可以用我们的前缀和来应用子区间问题,但是这里对于子区间乃至子串问题,我们也可以尝试往滑动窗口的思路方向去进行一个尝试,那么说那么半天,滑动窗口是什么…...
华三交换机-链路聚合配置案例
目录 1.链路聚合简述:2.链路聚合的作用:3.链路聚合的模式:4.网络拓扑:5.实验需求:6.网络配置:6.1 链路聚合配置(静态聚合)6.1.1 链路聚合配置:6.1.2 查看链路聚合状态: 6.2 链路聚合配置(动态聚合)6.2.1 链路聚合配置:6.2.2 查看链路聚合状态: 7.网络连通性测试:(接…...
Qwen2-VL 的重大省级,Qwen 发布新旗舰视觉语言模型 Qwen2.5-VL
Qwen2.5-VL 是 Qwen 的新旗舰视觉语言模型,也是上一代 Qwen2-VL 的重大飞跃。 Qwen2.5-VL主要特点 视觉理解事物:Qwen2.5-VL不仅能够熟练识别花、鸟、鱼、昆虫等常见物体,而且还能够分析图像中的文本、图表、图标、图形和布局。 代理性&…...
关系数据库标准语言SQL
1.SOL称为结构化查询语言,它是由1974年由Boyce和Chamberlin提出的,1975年至1979年IBM公司的San Jose Research Laboratory研制了关系数据库管理系统的原型系统SystemR,并实现了这种语言。 2.SQL(Structured Ouery Language)称为结构化查询语言 3.SQL数…...
mysql8.0使用MGR实现高可用与利用MySQL Router构建读写分离MGR集群
MGR是MySQL Group Replication的缩写,即MySQL组复制。 在以往,我们一般是利用MySQL的主从复制或半同步复制来提供高可用解决方案,但这存在以下几个比较严重的问题: 主从复制间容易发生复制延迟,尤其是在5.6以前的版本…...
《AI大模型开发笔记》MoE模型技术对比(Mixtral,Qwen2-MoE,DeepSeek-v3)
MoE模型技术对比(Mixtral,Qwen2-MoE,DeepSeek-v3) MoE(混合专家)大模型进入爆发期!本期我们对比三大开源MoE LLM:Mixtral、Qwen2-MoE 和最新爆火的 DeepSeek-V3。从 2023 年 Mixtral 开启风潮,到 2024 年 DeepSeek-V3 让全球瞩目,MoE 模型到底经历了怎样的进化? De…...