带头双向循环链表:一种高效的数据结构
- 💓 博客主页:江池俊的博客
- ⏩ 收录专栏:数据结构探索
- 👉专栏推荐:✅cpolar ✅C语言进阶之路
- 💻代码仓库:江池俊的代码仓库
- 🔥编译环境:Visual Studio 2022
- 🎉欢迎大家点赞👍评论📝收藏⭐

文章目录
- 一、带头循环双向链表的概念及结构
- 二、使用带头双向循环链表的优势及注意事项
- 三、带头双向链表的创建
- ✨3.1 准备工作✨
- ✨3.2 创建返回链表的头结点✨
- ✨3.3 双向链表销毁✨
- ✨3.4 双向链表打印✨
- ✨3.5 双向链表尾插✨
- ✨3.6 双向链表尾删✨
- ✨3.7 双向链表头插✨
- ✨3.8 双向链表头删✨
- ✨3.9 双向链表查找✨
- ✨3.10 双向链表在pos的前面进行插入✨
- ✨3.11 双向链表删除pos位置的节点✨
- 四、源代码
- 🌅4.1 List.h 文件
- 🌅4.2 List.c 文件
- 🌅4.3 Test.c 文件
- 🌅4.4 测试结果
双向循环链表是一种复杂的数据结构,它结合了双向链表和循环链表的优点。与单向链表相比,双向链表可以双向遍历,而循环链表则可以在尾部链接到头部,形成一个闭环。这种数据结构在某些应用场景下非常有用,比如事件处理、图形界面、内存管理等。
一、带头循环双向链表的概念及结构
双向循环链表是一种特殊类型的链表,它由一系列节点组成,每个节点包含一个数据域和两个指针域。其中一个指针指向下一个节点,另一个指针指向前一个节点。在双向循环链表中,首节点的前一个节点是尾节点,尾节点的下一个节点是首节点,形成一个闭环。

二、使用带头双向循环链表的优势及注意事项
【优势】:
- 高效遍历:由于带头双向循环链表可以双向遍历,因此可以在O(1)时间内访问任何节点。
- 内存高效:与双向链表相比,带头双向循环链表不需要额外的内存来存储头部节点。
- 插入和删除操作高效:在带头双向循环链表中插入和删除节点时,只需调整指针即可,无需移动大量数据。
【注意事项】:
- 初始化:在创建带头双向循环链表时,需要正确初始化所有节点的指针。
- 异常处理:在进行插入、删除等操作时,需要处理指针异常情况,如空指针或无效指针。
- 内存管理:在使用带头双向循环链表时,需要正确管理内存,避免内存泄漏或野指针。
三、带头双向链表的创建
✨3.1 准备工作✨
将代码分成三个文件可以提高代码的可读性、可维护性和可重用性。具体来说,三个文件可以分别关注以下方面:
- 配置文件:用于存储应用程序的配置信息,如数据库连接信息、应用程序名称、应用程序版本等。该文件可以在应用程序的整个生命周期内进行维护和管理,并且可以轻松地与其他开发人员共享。
- 模块文件:用于存储应用程序的各个模块,如用户管理、订单管理、产品管理等。每个模块都可以单独维护和测试,并且可以在不同的应用程序中重复使用。这有助于降低代码冗余和提高代码的可重用性。
- 入口文件:用于定义应用程序的入口,如路由、请求处理等。该文件可以控制应用程序的整个流程,并且可以轻松地与其他开发人员共享。
通过将代码分成三个文件,可以更好地组织代码结构,使其更加清晰和易于维护。同时,这也使得代码更易于测试和调试,并且可以更好地支持代码重构和优化。

#pragma once#include <stdio.h>
#include <stdlib.h>
#include <assert.h>// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{LTDataType data; //节点存储的数据元素struct ListNode* next; //指向前驱节点struct ListNode* prev; //指向后继节点
}ListNode; //双链表结构//几大接口
// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
✨3.2 创建返回链表的头结点✨
动态申请一个节点作为双向链表的头节点。并将头节点的
prev指向自己,next也指向自己,表明这是一个双向链表,且链表为空。
// 创建返回链表的头结点.
ListNode* ListCreate()
{ListNode* head = (ListNode*)malloc(sizeof(ListNode));if (head == NULL){perror("ListCreate --> malloc");return;}head->data = -1;head->prev = head;head->next = head;return head;
}
✨3.3 双向链表销毁✨
从链表的第二个节点开始,逐个释放链表中的节点,直到回到头节点并释放头节点的内存空间。这样做可以确保链表中的所有节点都被正确释放,防止内存泄漏。
// 双向链表销毁
void ListDestory(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->next;while (cur != pHead){ListNode* next = cur->next;free(cur);cur = next; }free(pHead);printf("双链表销毁成功!\n");
}
✨3.4 双向链表打印✨
// 双向链表打印
void ListPrint(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->next;printf("哨兵位 <--> ");while (cur != pHead){printf("%d <--> ", cur->data);cur = cur->next;}printf("哨兵位\n");
}
✨3.5 双向链表尾插✨
在进行插入节点之前,无论是头插还是尾插都需要申请一个新的节点,于是可以把此步骤成一个函数,减少代码的冗余。
//申请一个节点
ListNode* CreateLTNode(LTDataType x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if (newnode == NULL){perror("CreateLTNode --> malloc");return;}newnode->data = x;newnode->prev = NULL;newnode->next = NULL;return newnode;
}
- 首先,创建一个新的节点
newnode,并将数据x存储在其中。- 将
newnode的prev指针指向当前链表的第一个节点pHead的前一个节点,即pHead->prev。- 将
newnode的next指针指向当前链表的第一个节点pHead。- 将当前链表的第一个节点
pHead的前一个节点的next指针指向新节点newnode。- 将当前链表的第一个节点
pHead的prev指针指向新节点newnode。通过以上步骤,新节点被插入到双向链表的尾部,并且链表中的其他节点仍然保持其原始顺序和链接关系。这样做可以确保新节点被正确地添加到链表中,并且不会破坏链表的结构。
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* newnode = CreateLTNode(x);//pHead pHead->prev newnodenewnode->prev = pHead->prev; newnode->next = pHead;pHead->prev->next = newnode;pHead->prev = newnode;
}
✨3.6 双向链表尾删✨
- 首先,获取链表的最后一个节点
tail,它应该是头节点pHead的前一个节点(即pHead->prev)。- 接着,获取最后一个节点的前一个节点
tailPrev。- 将头节点
pHead的prev指针指向最后一个节点的前一个节点tailPrev,从而将最后一个节点从链表中间删除。- 将最后一个节点的前一个节点的
next指针指向头节点pHead,从而将头节点和最后一个节点连接起来。- 最后,释放最后一个节点的内存空间。
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{assert(pHead);assert(pHead->next!=pHead);//链表不能为空ListNode* tail = pHead->prev;ListNode* tailPrev = tail->prev;// pHead tailPrev tailpHead->prev = tailPrev;tailPrev->next = pHead;free(tail);
}
✨3.7 双向链表头插✨
- 首先,创建一个新的节点
newnode,并将数据x存储在其中。- 将新节点的
prev指针指向当前链表的第一个节点pHead。- 将新节点的
next指针指向当前链表的第一个节点的下一个节点,即pHead->next。- 将当前链表的第一个节点的
next指针指向新节点newnode。- 将当前链表的第一个节点的下一个节点的
prev指针指向新节点newnode。通过以上步骤,新节点被插入到双向链表的头部,并且链表中的其他节点仍然保持其原始顺序和链接关系。这样做可以确保新节点被正确地添加到链表中,并且不会破坏链表的结构。
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* newnode = CreateLTNode(x);ListNode* rear = pHead->next;pHead->next = newnode;newnode->prev = pHead;newnode->next = rear;rear->prev = newnode;
}
✨3.8 双向链表头删✨
- 首先,获取链表的第一个节点
cur,它应该是头节点pHead的下一个节点(即pHead->next)。- 将头节点的
next指针指向第一个节点的下一个节点,从而将第一个节点从链表中间删除。- 将第一个节点的下一个节点的
prev指针指向头节点pHead,从而将头节点和第一个节点连接起来。- 最后,释放第一个节点的内存空间。
// 双向链表头删
void ListPopFront(ListNode* pHead)
{assert(pHead);assert(pHead->next != pHead);ListNode* cur = pHead->next;pHead->next = cur->next;cur->next->prev = pHead;free(cur);
}
✨3.9 双向链表查找✨
- 首先,从链表的第二个节点开始(即
pHead->next),遍历链表的每个节点。- 对于每个节点,检查其存储的数据是否与要查找的数据
x相等。- 如果找到了匹配的节点,则返回该节点。
- 如果遍历完整个链表都没有找到匹配的节点,则返回空指针(
NULL)。
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* cur = pHead->next;while (cur != pHead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;//如果没找到,返回空
}
✨3.10 双向链表在pos的前面进行插入✨
- 首先,创建一个新的节点
newnode,并将数据x存储在其中。- 获取要插入位置的前一个节点
_prev。- 将前一个节点的
next指针指向新节点newnode。- 将新节点的
prev指针指向前一个节点_prev。- 将新节点的
next指针指向当前节点pos。- 将当前节点的
prev指针指向新节点newnode。通过以上步骤,新节点被插入到指定位置的前面,并且链表中的其他节点仍然保持其原始顺序和链接关系。这样做可以确保新节点被正确地添加到链表中,并且不会破坏链表的结构。
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newnode = CreateLTNode(x);ListNode* _prev = pos->prev;// _prev newnode pos_prev->next = newnode;newnode->prev = _prev;newnode->next = pos;pos->prev = newnode;
}
✨3.11 双向链表删除pos位置的节点✨
- 首先,确保要删除的节点
pos不是空指针。- 获取要删除节点的前一个节点
_prev和后一个节点rear。- 将前一个节点的
next指针指向后一个节点,从而将要删除的节点从链表中间删除。- 将后一个节点的
prev指针指向前一个节点,从而将前一个节点和后一个节点连接起来。- 释放要删除的节点的内存空间。
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{assert(pos);ListNode* _prev = pos->prev;ListNode* rear = pos->next;_prev->next = rear;rear->prev = _prev;free(pos);
}
四、源代码
🌅4.1 List.h 文件
#pragma once#include <stdio.h>
#include <stdlib.h>
#include <assert.h>// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{LTDataType data; //节点存储的数据元素struct ListNode* next; //指向前驱节点struct ListNode* prev; //指向后继节点
}ListNode; //双链表结构// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
🌅4.2 List.c 文件
#define _CRT_SECURE_NO_WARNINGS 1#include "List.h"//申请一个节点
ListNode* CreateLTNode(LTDataType x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if (newnode == NULL){perror("CreateLTNode --> malloc");return;}newnode->data = x;newnode->prev = NULL;newnode->next = NULL;return newnode;
}
// 创建返回链表的头结点.
ListNode* ListCreate()
{ListNode* head = (ListNode*)malloc(sizeof(ListNode));if (head == NULL){perror("ListCreate --> malloc");return;}head->data = -1;head->prev = head;head->next = head;return head;
}
// 双向链表销毁
void ListDestory(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->next;while (cur != pHead){ListNode* next = cur->next;free(cur);cur = next; }free(pHead);printf("双链表销毁成功!\n");
}
// 双向链表打印
void ListPrint(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->next;printf("哨兵位 <--> ");while (cur != pHead){printf("%d <--> ", cur->data);cur = cur->next;}printf("哨兵位\n");
}
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* newnode = CreateLTNode(x);//pHead pHead->prev newnodenewnode->prev = pHead->prev; newnode->next = pHead;pHead->prev->next = newnode;pHead->prev = newnode;
}
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{assert(pHead);assert(pHead->next!=pHead);//链表不能为空ListNode* tail = pHead->prev;ListNode* tailPrev = tail->prev;// pHead tailPrev tailpHead->prev = tailPrev;tailPrev->next = pHead;free(tail);
}
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* newnode = CreateLTNode(x);ListNode* rear = pHead->next;pHead->next = newnode;newnode->prev = pHead;newnode->next = rear;rear->prev = newnode;
}
// 双向链表头删
void ListPopFront(ListNode* pHead)
{assert(pHead);assert(pHead->next != pHead);ListNode* cur = pHead->next;pHead->next = cur->next;cur->next->prev = pHead;free(cur);
}
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* cur = pHead->next;while (cur != pHead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;//如果没找到,返回空
}
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newnode = CreateLTNode(x);ListNode* _prev = pos->prev;// _prev newnode pos_prev->next = newnode;newnode->prev = _prev;newnode->next = pos;pos->prev = newnode;
}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{assert(pos);ListNode* _prev = pos->prev;ListNode* rear = pos->next;_prev->next = rear;rear->prev = _prev;free(pos);
}
🌅4.3 Test.c 文件
#define _CRT_SECURE_NO_WARNINGS 1#include "List.h"void Test1()
{ListNode* plist = ListCreate();//尾插1、2、3ListPushBack(plist, 1);ListPushBack(plist, 2);ListPushBack(plist, 3);ListPrint(plist);//头插5、4ListPushFront(plist, 5);ListPushFront(plist, 4);ListPrint(plist);//查找元素3,找到返回节点地址,没找到返回空ListNode* pos = ListFind(plist, 3);if (pos){printf("找到了\n");}else{printf("没找到\n");}//在3前面插入30ListInsert(pos, 30);ListPrint(plist); //删除3if (pos){ListErase(pos);pos = NULL;}ListPrint(plist);//尾删两次ListPopBack(plist);ListPopBack(plist);ListPrint(plist);//头删两次ListPopFront(plist);ListPopFront(plist);ListPrint(plist);//销毁链表ListDestory(plist);plist = NULL;
}int main()
{Test1();return 0;
}
🌅4.4 测试结果

相关文章:
带头双向循环链表:一种高效的数据结构
💓 博客主页:江池俊的博客⏩ 收录专栏:数据结构探索👉专栏推荐:✅cpolar ✅C语言进阶之路💻代码仓库:江池俊的代码仓库🔥编译环境:Visual Studio 2022🎉欢迎大…...
C++基础 -34- 输入输出运算符重载
输出运算符重载格式 ostream & operator<<(ostream &out,person a) {cout << a.a << endl;return out; }举例输出运算符重载 #include "iostream"using namespace std;class person {public:person(int a):a(a){}int a; };ostream &…...
MimicGen论文分析与资料汇总
MimicGen论文分析与资料汇总 前言论文分析相关资料汇总 前言 论文分析 相关资料汇总 Paper:MimicGen: A Data Generation System for Scalable Robot Learning using Human Demonstrations mimicgen.github 破局利刃!英伟达合成数据新成果:为机器人造…...
JAVA-每一页PDF转图片
结论:1、iText几乎找不到如何PDF转图片的信息,但能找到获取到PDF里面的图片并保存下来的信息;2、PDF box满大街都是参考代码(下面会附上一个作为参考);3、收费的库使用起来更简单,但就是要收费&…...
VS安装QT VS Tools编译无法通过
场景: 项目拷贝到虚拟机内部后,配置好相关环境后无法编译,安装QT VS Tools后依旧无法编译,查找资料网上说的是QT工具版本不一致导致的,但反复试了几个版本后依旧无法编译通过。错误信息如下: C:\Users\Ad…...
【C语言之 CJson】学CJson看这一篇就够了
文章目录 前言一、下载CJson二、创建一个json2.1 创建json对象cJSON类型详解 2.2 创建键值对2.3 添加嵌套的 JSON 对象2.4 添加数组创建数组添加元素到数组添加数组到obj 2.5 将 JSON 对象转为字符串2.6 释放内存2.7 示例代码 三、解析json3.1 解析json root3.2 把一个key解析出…...
使用Java语言实现字母之间的大小写转换
这个类的作用为实现字母之间的大小写转换,通过加减32来完成。 输入的代码 import java.util.Scanner; public class WordChangeDemo {public static void main(String[] args){try (Scanner in new Scanner(System.in)) {System.out.println("请输入您要进…...
Docker的数据持久化;Docker网络;Dockerfile编写
Docker的数据持久化;Docker网络;Dockerfile编写; 文章目录 Docker的数据持久化;Docker网络;Dockerfile编写;**Docker的数据持久化**1)将本地目录映射到容器里2)数据卷3)将…...
OpenHarmony亮相MTSC 2023 | 质量效率共进,赋能应用生态发展
11月25日,MTSC 2023第十二届中国互联网测试开发大会在深圳登喜路国际大酒店圆满举行。大会以“软件质量保障体系和测试研发技术交流”为主要目的,旨在为行业搭建一个深入探讨和交流的桥梁和平台。OpenAtom OpenHarmony(简称“OpenHarmony”&a…...
windows11 调整鼠标灵敏度方法
首先 我们打开电脑设置 或者在 此电脑/此计算机/我的电脑 右击选择属性 然后 有的电脑 左侧菜单中 直接就有 设备 然后在设备中直接就可以找到 鼠标 选项 调整光标速度即可 如果操作系统和我的一样 可以直接搜索鼠标 然后 选择 鼠标设置 然后 调整上面的鼠标指针速度即可...
贪心算法个人见解
目录 基本思想: 贪心算法的步骤: 示例: 贪心算法(Greedy Algorithm)是一种基于贪心策略的算法范式,它在每一步选择中都采取当前状态下的最优选择,而不考虑全局最优解。贪心算法通常适用于那些…...
Win中Redis部署与配置
1.下载msi版本 下载传送门 2.双击next-->next安装安装 3.密码配置以及开机自启 在配置文件中配置相应配置进行配置密码以及端口和ip port 6379指定 Redis 监听端口,默认端口为 6379,作者在自己的一篇博文中解释了为什么选用 6379 作为默认端口&…...
vue el-button 封装及使用
使用了 Element UI 中的 el-button 组件,并对其进行了封装和定制。 创建组件index.vue (src/common-ui/button/index.vue) <template><el-buttonclass"h-button":type"type":icon"hIcon":disabled"disabled"clic…...
QT之QMediaPlayer的用法
QT之QMediaPlayer的用法 成员函数例程 成员函数 1)setMedia(const QMediaContent &media, QIODevice *stream nullptr) 设置要播放的媒体内容,其中参数media指定了媒体内容,stream参数指定了用于读取媒体的输入设备(如文件流࿰…...
TCP_报文格式解读
报文格式 header部分字段含义解析 固定字段 对于header中固定部分字段含义,见之前的blog《TCP报文分析》; 对部分字段含义补充说明 Data Offset:4bit,tcp header的长度,单位:32bit(4字节&…...
C语言面试之旅:掌握基础,探索深度(面试实战之c语言关键词下篇)
一.枚举( enum) 枚举是 C 语言中的一种基本数据类型,用于定义一组具有离散值的常量,它可以让数据更简洁,更易读。枚举类型通常用于为程序中的一组相关的常量取名字,以便于程序的可读性和维护性。定义一个枚…...
Java学习第十三天
Java多态 多态是同一个行为具有多个不同表现形式或形态的能力。 多态就是同一个接口,使用不同的实例而执行不同操作 多态性是对象多种表现形式的体现。 多态的优点 1. 消除类型之间的耦合关系2. 可替换性3. 可扩充性4. 接口性5. 灵活性6. 简化性 多态存在的三个…...
【Delphi】实现彩色日志显示框(TRichEdit Helper)
目录 一、前言 二、实现方法 1. 第一步 2. 第二步 3. 第三步 三、主程序代码 四、下载 1. 可执行程序 2. 程序源代码 一、前言 在用Delphi做日常开发的时候,经常需要显示程序运行的日志,一般我们会使用TMemo,使用起来简单,…...
Elasticsearch 优化查询中获取字段内容的方式,性能提升5倍!
1、背景 集群配置为:8 个 node 节点,16 核 32G,索引 4 分片 1 副本。应用程序的查询逻辑是按经纬度排序后找前 200 条文档。 1、应用对查询要求比较高,search 没有慢查询的状态。 2、集群压测性能不能上去,cpu 使用未打…...
图像批量设计软件Retrobatch Pro mac中文版功能特色
Retrobatch Mac是一款灵活的批量图像处理工具。用户可以自由创建Workflow来实现相应的功能,这些Workflow能取代大量的重复劳动,提高生产力。Retrobatch Mac的一般操作是从左边栏拖动相应动作到工作区形成节点(Nodes),节…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
