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

【数据结构】单向链表实现 超详细

目录

一. 单链表的实现

1.准备工作及其注意事项

1.1 先创建三个文件

1.2 注意事项:帮助高效记忆和理解

2.链表的基本功能接口

2.0 创建一个 链表

2.1 链表的打印

 3.链表的创建新节点接口

4.链表的节点插入功能接口

4.1 尾插接口

4.2 头插接口  

  4.3 指定位置 pos 之前 插入接口

 4.4 指定位置pos 之后 插入接口(推荐)

5.链表表的删除功能接口

5.1 尾删接口

5.2头删接口

5.3 删除 指定位置 pos 节点 接口

5.4 删除  指定位置 pos ==之后== 的一个 节点 接口

6.链表的  查找  接口

7.链表的  销毁  接口

二、总代码

SList.h

SList.c

test.c


前言:(受篇幅限制,为了划清知识模块,进行分章节讲解)

若想了解清楚 链表的概念和分类 

可以点击跳转 这一章节----> :【数据结构】链表的概念 及 分类 (使用比喻解释概念)


一. 单链表的实现

1.准备工作及其注意事项
1.1 先创建三个文件

 解释这三个文件的作用
 1、头文件SList.h  是来声明接口函数,定义链表,将几个公共用到的库函数集合起来
 2、源文件SList.c  是用来具体实现接口
 3、源文件test.c  用于接口的测试工作 ,即具体的使用场景

1.2 注意事项:帮助高效记忆和理解

1. 但凡是删除,必须 断言 链表不能为 空,避免传过来的是NULL指针 assert(*pphead);
2. 传递二级指针,要断言 不能为 NULL ,指针不能为空:assert(pphead);
3. 指定位置 pos 时,要确保pos存在:assert(pos);
4. (pphead)->next;  解引用前一定要加 括号,* 号 优先级 < 箭头操作符
5. 链表的所有插入接口:链表为空: 没有节点 就直接插入
6.要找 前一个节点 prev 或 后一个节点 next 时, 一定要确保 其本身存在!!!!
7.当指定位置 pos 刚好是 头节点时 就没有 prev 了

2.链表的基本功能接口
2.0 创建一个 链表
// 创建链表节点结构体
// 和顺序表创建原理相同,可以看我的 【顺序表】章节
typedef  int  SLDataType;
typedef struct SListNode
{SLDataType data;struct SListNode* next;
}SLTNode;
2.1 链表的打印
// 打印函数
//注意这里的 phead 仅表示单向链表传递过来的 第一个节点地址,不是 双向链表的带头节点 
void SLTPrint(SLTNode* phead)
{SLTNode* ptemp = phead;while (ptemp) // ptemp != NULL 说明为是有效的节点,则循环打印{printf("%d -> ", ptemp->data);ptemp = ptemp->next; // 更新 ptemp :保存下个节点的地址:遍历节点的关键}printf("NULL\n");
}
 3.链表的创建新节点接口
// 创建新节点函数:所有的插入接口,都需要 创建新节点
SLTNode* STLCreatNode(SLDataType x)
{// 先创建 一个 新节点SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));newNode->data = x;newNode->next = NULL;return newNode;
}
4.链表的节点插入功能接口
4.1 尾插接口

链表的尾插法
几种情况
1、链表非空:先找到尾节点,然后直接将尾节点 的 next 指向 新节点,(形成链接), 新节点 则 指向 NULL 变成 新的尾节点
2、链表为空:将头指针phead更新 成 新插入节点的地址,然后新节点 next 指向 NULL

// 注意:plist 头指针是 时刻更新为了指向头节点,当创建新的头节点后,要更新 plist ,而若要真正改变 plist 的值,需要传地址
// 传递过来的 头指针 &plist 是 一级指针 plist 的地址,要用 二级指针 pphead 来接收 ; 而 *pphead == plist 
// void SLTPushBack(SLTNode* phead, SLDataType x) // 错误写法:传值void SLTPushBack(SLTNode** pphead, SLDataType x)
{assert(pphead); // 传递过来的 一级指针的地址 二级指针 不能为 NULL// 先创建 一个 新节点SLTNode* newNode = STLCreatNode(x);// 1、链表为空if (*pphead == NULL){*pphead = newNode;return;}// 2、链表非空SLTNode* ptail = *pphead; // 因为要找 尾节点:干脆命名为 tail//本质是:找到尾节点的地址,而不是 尾节点的 nextwhile (ptail->next) {ptail = ptail->next;}ptail->next = newNode;
}

4.2 头插接口  

void SLTPushFront(SLTNode** pphead, SLDataType x)
{assert(pphead); // 传递过来的 一级指针的地址 二级指针 不能为 NULL// 先创建 一个 新节点SLTNode* newNode = STLCreatNode(x);newNode->next = *pphead; // 先将原本的 头指针放在 新节点的next*pphead = newNode; // 更新 头指针
}

  4.3 指定位置 pos 之前 插入接口

// 在指定位置节点pos 之前插入数据 
// 思路:找三个节点 :prev     newNode      next 
//                  前      本身新节点     后         为了找到 地址 才能将三者链接起来
// 注意:要找 前一个节点 prev 时, 一定要确保 其本身存在!!! 
// 当 pos 刚好是 头节点时 就没有 prev 了,特殊情况, 否则会因为找不到prev而 程序奔溃
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
{assert(pphead); // 指针不能为空assert(pos); // pos 不能为空assert(*pphead); // 链表不能为空: pos 是链表中 的一个有效节点,pos 不为空,链表也不能为 空// 创建新节点SLTNode* newNode = STLCreatNode(x);if (*pphead == pos){// 当 pos 刚好是 头节点时 就用 头插法:调用之前写的函数接口SLTPushFront(pphead, x);return;}SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}// 三者关联起来:  prev -> newNode -> posnewNode->next = pos;prev->next = newNode;
}
 4.4 指定位置pos 之后 插入接口(推荐)

// 在指定位置节点pos 之后插入数据: 注意一下错误写法: 和正确写法刚好相反
// 特点:有了 pos 就不需要 头节点了!!
void SLTInsertAfter(SLTNode*pos, SLDataType x)
{assert(pos); // pos 不能为空// 创建新节点SLTNode* newNode = STLCreatNode(x);newNode->next = pos->next;pos->next = newNode;
}
5.链表表的删除功能接口
5.1 尾删接口

// 链表的尾删法
// 思路:删除尾节点 以及  前一个节点 pre 的next 要置为 NULL
// 要注意 只有一个节点时,没有前置节点 pre!!!!
void SLTPopBack(SLTNode** pphead)
{assert(pphead); // 一级指针为plist 指向头节点,传递过来的 一级指针的地址二级指针不能为 NULLassert(*pphead); // 一级指针为plist 指向头节点, *pphead == plist 这个指针也不能为 NULL 不能为空链表// 链表非空// 链表只有一个节点时if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}// 链表有多个节点SLTNode* ptail = *pphead;SLTNode* prev = NULL; // 时刻更新保存 while(ptail->next){ prev = ptail;ptail = ptail->next;}prev->next = NULL;free(ptail);ptail = NULL;
}
5.2头删接口

// 链表的头删法
void SLTPopFront(SLTNode** pphead)
{assert(pphead); // 指针不能为空assert(*pphead); // 链表不能为空// 让第二个节点成为新的头节点// 将 旧的节点释放掉: 注意 要先将 第二个节点的地址  (*pphead) -> next  临时储存起来!!SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}
5.3 删除 指定位置 pos 节点 接口
// 删除pos 节点
// 删除 pos 节点后,还要 将 prev 和 next (pos的前后两个节点) 链接上!!: 比较麻烦
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead); // 指针不能为空assert(pos); // pos 不能为空assert(*pphead); // 链表不能为空: pos 是链表中 的一个有效节点,pos 不为空,链表也不能为 空//先 让 prev 链接上 next,后 free 释放掉 pos// 遇到 需要找 prev 的,一定要 检查是否存在 previf (*pphead == pos)//检查是否存在 prev{free(pos);*pphead = NULL;return;}SLTNode* prev = *pphead;while (prev->next != pos) // 找 前面节点 prev{prev = prev->next;}prev->next = pos->next; // 先赋值后 再free释放free(pos);pos = NULL;
}
 5.4 删除  指定位置 pos ==之后== 的一个 节点 接口

// 删除pos 之后的节点
// 直接 删除 pos 之后的 节点 pos->next  
// 先让 pos 和 pos -> next -> next 链接起来,后 删除 节点 pos -> next 
// 注意:像这类找 上一个节点 prev 或 找下一个节点 next :都需要 检查 是否存在 该节点
void SLTEraseBeind(SLTNode* pos)
{assert(pos); // pos 不能为空assert(pos->next); // 这个节点必须存在,否则该函数无意义! 链表至少要有两个节点// 三者的关联关系:pos    pos->next    pos->next->next// 注意:下面 先 pos->next = pos->next->next, 后 free(pos->next) 是不对的  // pos->next 已经更新,不是你所认为的原来的那个 中间节点了,因此要先 临时保存起来!!!SLTNode* temp = pos->next;pos->next = pos->next->next;free(temp);temp = NULL;
}
 6.链表的  查找  接口
// 链表的查找
SLTNode* SLTFind(SLTNode** pphead, SLDataType x)
{// 遍历链表assert(pphead); // 指针不能为空SLTNode* ptemp = *pphead;while (ptemp){if (ptemp->data == x) return ptemp; // 找到了就返回节点ptemp = ptemp->next;}// 没找到return NULL;
}
7.链表的  销毁  接口
// 销毁链表
// 一旦涉及到 动态内存申请,不要忘记销毁
void SListDestory(SLTNode** pphead)
{assert(pphead); // 指针不能为空assert(*pphead); // 链表不能为空,空的没必要销毁了// 顺序表是一段连续的空间,可以执行一次free全部销毁,而链表节点是独立的,需要遍历节点一个一个销毁// 不能直接 一个一个 free 下去,需要 保存 next 节点,才能找到下个节点!!!!SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}// 当所有节点销毁后,需要 将头指针 销毁*pphead = NULL;
}

二、总代码

SList.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>// 零、创建链表节点
typedef int SLDataType;
typedef struct SListNode
{SLDataType data;struct SListNode* next;
}SLTNode;// 一、打印函数: 这里用传址
void SLTPrint(SLTNode* ps);// 二、尾插法
void SLTPushBack(SLTNode** pphead, SLDataType x);// 三、头插法
void SLTPushFront(SLTNode** pphead, SLDataType x);// 四、尾删法
void SLTPopBack(SLTNode** pphead);// 五、头删法
void SLTPopFront(SLTNode** pphead);// 六、链表的查找
SLTNode* SLTFind(SLTNode** pphead, SLDataType x);// 七、指定位置 pos 之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLDataType x);// 八、指定位置 pos 之后 插入
void SLTInsertAfter(SLTNode* pos, SLDataType x);// 九、删除 指定 pos 节点
void SLTErase(SLTNode** pphead, SLTNode* pos);// 十、删除指定 pos 之后 的节点
void SLTEraseAfter(SLTNode* pos);// 十一、销毁链表
void SLTDestory(SLTNode** pphead);

SList.c

#include"SList.h"// 一、打印函数: 这里用传址
void SLTPrint(SLTNode* phead)
{SLTNode* ptemp = phead;while (ptemp) //  ptemp != NULL 表示为有效节点 {printf("%d -> ", ptemp->data);ptemp = ptemp->next;}printf("NULL\n");
}// 创建节点函数
SLTNode* SLTCreatNode(SLDataType x)
{SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));newNode->data = x;newNode->next = NULL;return newNode;
}
// 二、尾插法
void SLTPushBack(SLTNode** pphead, SLDataType x)
{assert(pphead);// 创建新节点SLTNode* newNode = SLTCreatNode(x);// 链表为空: 没有节点 就直接插入if (*pphead == NULL){*pphead = newNode;return;}// 链表非空:找尾节点SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}ptail->next = newNode;
}// 三、头插法
void SLTPushFront(SLTNode** pphead, SLDataType x)
{assert(pphead);// 创建新节点SLTNode* newNode = SLTCreatNode(x);// 先 链接 第一个节点,  没有第一个节点就是 NULL,也可以直接给 newNode->next,后更新 *ppheadnewNode->next = *pphead;*pphead = newNode;
}// 四、尾删法
void SLTPopBack(SLTNode** pphead)
{assert(pphead);assert(*pphead);// 先找尾节点 和 前置节点 prev,后删除+链接// 当只有一个 节点时if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}// 当有 两个 节点 及以上SLTNode* ptail = *pphead;SLTNode* prev = NULL;while (ptail->next){prev = ptail;ptail = ptail->next;}prev->next = NULL;free(ptail);ptail = NULL;
}// 五、头删法
void SLTPopFront(SLTNode** pphead)
{assert(pphead);assert(*pphead);// 让 *pphead 指向第二个节点,free 掉第一个SLTNode* next = (*pphead)->next; // 一定要加 括号,* 号 优先级 < 箭头操作符 free(*pphead);*pphead = next;
}// 六、链表的查找
SLTNode* SLTFind(SLTNode** pphead, SLDataType x)
{assert(pphead);// 遍历SLTNode* ptemp = *pphead;while (ptemp){if (ptemp->data == x) return ptemp;ptemp = ptemp->next;}return NULL;
}// 七、指定位置 pos 之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
{assert(pphead);assert(pos);assert(*pphead);// 涉及到三个节点: prev    newNode   pos// 创建新节点SLTNode* newNode = SLTCreatNode(x);if (*pphead == pos)// 无 prev 的情况{SLTPushFront(pphead, x);return;}SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}newNode->next = pos;prev->next = newNode;
}// 八、指定位置 pos 之后 插入(推荐!)
void SLTInsertAfter(SLTNode* pos, SLDataType x)
{assert(pos);// 创建新节点SLTNode* newNode = SLTCreatNode(x);newNode->next = pos->next;pos->next = newNode;
}// 九、删除 指定 pos 节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);assert(*pphead);// 关系三个节点:prev    pos    next// 先找 prevSLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;
}// 十、删除指定 pos 之后 的节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next); // 注意  pos->next 这个必须存在// 关系三个节点: pos      pos->next     pos->next->next// 另一种可能:     pos      pos->next     NULLif (pos->next->next == NULL){free(pos->next);pos->next = NULL;return;}// 直接销毁  pos->next  会找不到 pos->next->next,先保存SLTNode* ptemp = pos->next->next;free(pos->next);pos->next = NULL;pos->next = ptemp;
}// 十一、销毁链表
void SLTDestory(SLTNode** pphead)
{assert(pphead);// 遍历销毁if (*pphead == NULL)return;SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}// 别忘了将 头指针销毁!!!*pphead = NULL;
}

test.c

#include"SList.h"void SLTest1()
{// 零、创建 链表SLTNode* plist = NULL;// 二、尾插法SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4); // 1 -> 2 -> 3 -> 4 -> NULLprintf("测试尾插:");SLTPrint(plist);// 三、头插法SLTPushFront(&plist, 5);SLTPushFront(&plist, 6); // 6 -> 5 -> 1 -> 2 -> 3 -> 4 -> NULLprintf("测试头插:");SLTPrint(plist);// 四、尾删法SLTPopBack(&plist);SLTPopBack(&plist); // 6 -> 5 -> 1 -> 2 -> NULLprintf("测试尾删:");SLTPrint(plist);// 五、头删法SLTPopFront(&plist);SLTPopFront(&plist); // 1 -> 2 -> NULLprintf("测试头删:");SLTPrint(plist);// 六、链表的查找SLTNode* FindRet = SLTFind(&plist, 2);printf("测试查找:");if (FindRet) printf("找到了\n");else printf("没找到\n");// 七、指定位置 pos 之前插入SLTNode* FindRet1 = SLTFind(&plist, 2);SLTNode* FindRet2 = SLTFind(&plist, 1);SLTInsert(&plist, FindRet1, 200);SLTInsert(&plist, FindRet2, 100);// 100 -> 1 -> 200 -> 2 -> NULLprintf("测试指定位置之前插入:");SLTPrint(plist);// 八、指定位置 pos 之后 插入(推荐!)SLTNode* FindRet3 = SLTFind(&plist, 2);SLTInsertAfter(FindRet3, 200); // 100 -> 1 -> 200 -> 2 -> 200 -> NULLprintf("测试指定位置之后插入:");SLTPrint(plist);// 九、删除 指定 pos 节点SLTNode* FindRet4 = SLTFind(&plist, 1);SLTErase(&plist, FindRet4);// 100 -> 200 -> 2 -> 200 -> NULLprintf("测试删除指定节点:");  SLTPrint(plist);// 十、删除指定 pos 之后 的节点SLTNode* FindRet5 = SLTFind(&plist, 200); // 注意如果 通过 Find 函数 找 节点,节点中有重复数据,返回 第一个遇到的SLTEraseAfter(FindRet5);// 100 -> 200 -> 200 -> NULLprintf("测试删除指定节点:"); SLTPrint(plist);//
}
int main()
{SLTest1();return 0;
}

完。

若上述文章有什么错误,欢迎各位大佬及时指出,我们共同进步!

相关文章:

【数据结构】单向链表实现 超详细

目录 一. 单链表的实现 1.准备工作及其注意事项 1.1 先创建三个文件 1.2 注意事项&#xff1a;帮助高效记忆和理解 2.链表的基本功能接口 2.0 创建一个 链表 2.1 链表的打印 3.链表的创建新节点接口 4.链表的节点插入功能接口 4.1 尾插接口 4.2 头插接口 4.3 指定位…...

Opencc4j 开源中文繁简体使用介绍

Opencc4j Opencc4j 支持中文繁简体转换&#xff0c;考虑到词组级别。 Features 特点 严格区分「一简对多繁」和「一简对多异」。 完全兼容异体字&#xff0c;可以实现动态替换。 严格审校一简对多繁词条&#xff0c;原则为「能分则不合」。 词库和函数库完全分离&#xff0c…...

vue 下载二进制文件

文章目录 概要技术细节 概要 vue 下载后端返回的二进制文件流 技术细节 import axios from "axios"; const baseUrl process.env.VUE_APP_BASE_API; //downLoadPdf("/pdf/download?pdfName" res .pdf, res); export function downLoadPdf(str, fil…...

数据结构之堆排序

对于几个元素的关键字序列{K1&#xff0c;K2&#xff0c;…&#xff0c;Kn}&#xff0c;当且仅当满足下列关系时称其为堆&#xff0c;其中 2i 和2i1应不大于n。 { K i ≤ K 2 i 1 K i ≤ K 2 i 或 { K i ≥ K 2 i 1 K i ≥ K 2 i {\huge \{}^{K_i≤K_{2i}} _{K_i≤K_{2i1}} …...

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之ScrollBar组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之ScrollBar组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、ScrollBar组件 鸿蒙&#xff08;HarmonyOS&#xff09;滚动条组件ScrollBar&…...

读论文:DiffBIR: Towards Blind Image Restoration with Generative Diffusion Prior

DiffBIR 发表于2023年的ICCV&#xff0c;是一种基于生成扩散先验的盲图像恢复模型。它通过两个阶段的处理来去除图像的退化&#xff0c;并细化图像的细节。DiffBIR 的优势在于提供高质量的图像恢复结果&#xff0c;并且具有灵活的参数设置&#xff0c;可以在保真度和质量之间进…...

基于微信小程序的新生报到系统的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…...

分享一下 uniapp 打包安卓apk

首先需要安装 Java 环境&#xff0c;这里就不做解释了 第二步&#xff1a;打开 mac 终端 / cmd 命令行工具 使用keytool -genkey命令生成证书 keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore *testalias 是证书别名&am…...

DevOps落地笔记-21|业务价值:软件发布的最终目的

上一课时介绍如何度量软件的内部质量和外部质量。在外部质量中&#xff0c;我们提到用户满意度是衡量软件外部质量的关键因素。“敏捷宣言”的第一条原则规定&#xff1a;“我们最重要的目标&#xff0c;是通过持续不断的及早交付有价值的软件使用户满意”。从这一点也可以看出…...

【动态规划】【前缀和】【数学】2338. 统计理想数组的数目

作者推荐 【动态规划】【前缀和】【C算法】LCP 57. 打地鼠 本文涉及知识点 动态规划汇总 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LeetCode:2338. 统计理想数组的数目 给你两个整数 n 和 maxValue &#xff0c;用于描述一个 理想…...

【已解决】onnx转换为rknn置信度大于1,图像出现乱框问题解决

前言 环境介绍&#xff1a; 1.编译环境 Ubuntu 18.04.5 LTS 2.RKNN版本 py3.8-rknn2-1.4.0 3.单板 迅为itop-3568开发板 一、现象 采用yolov5训练并将pt转换为onnx&#xff0c;再将onnx采用py3.8-rknn2-1.4.0推理转换为rknn出现置信度大于1&#xff0c;并且图像乱框问题…...

多路服务器技术如何处理大量并发请求?

在当今的互联网时代&#xff0c;随着用户数量的爆炸性增长和业务规模的扩大&#xff0c;多路服务器技术已成为处理大量并发请求的关键手段。多路服务器技术是一种并行处理技术&#xff0c;它可以通过多个服务器同时处理来自不同用户的请求&#xff0c;从而显著提高系统的整体性…...

SpringBoot - 不加 @EnableCaching 标签也一样可以在 Redis 中存储缓存?

网上文章都是说需要在 Application 上加 EnableCaching 注解才能让缓存使用 Redis&#xff0c;但是测试发现不用 EnableCaching 也可以使用 Redis&#xff0c;是网上文章有问题吗&#xff1f; 现在 Application 上用了 EnableAsync&#xff0c;SpringBootApplication&#xff0…...

Linux------命令行参数

目录 前言 一、main函数的参数 二、命令行控制实现计算器 三、实现touch指令 前言 当我们在命令行输入 ls -al &#xff0c;可以查看当前文件夹下所有文件的信息&#xff0c;还有其他的如rm&#xff0c;touch等指令&#xff0c;都可以帮我们完成相应的操作。 其实运行这些…...

LLM少样本示例的上下文学习在Text-to-SQL任务中的探索

导语 本文探索了如何通过各种提示设计策略&#xff0c;来增强大型语言模型&#xff08;LLMs&#xff09;在Few-shot In-context Learning中的文本到SQL转换能力。通过使用示例SQL查询的句法结构来检索演示示例&#xff0c;并选择同时追求多样性和相似性的示例可以提高性能&…...

双非本科准备秋招(19.2)—— 设计模式之保护式暂停

一、wait & notify wait能让线程进入waiting状态&#xff0c;这时候就需要比较一下和sleep的区别了。 sleep vs wait 1) sleep 是 Thread 方法&#xff0c;而 wait 是 Object 的方法 2) sleep 不需要强制和 synchronized 配合使用&#xff0c;但 wait 强制和 s…...

使用SpringMVC实现功能

目录 一、计算器 1、前端页面 2、服务器处理请求 3、效果 二、用户登陆系统 1、前端页面 &#xff08;1&#xff09;登陆页面 &#xff08;2&#xff09;欢迎页面 2、前端页面发送请求--服务器处理请求 3、效果 三、留言板 1、前端页面 2、前端页面发送请求 &…...

spring aop实现接口超时处理组件

文章目录 实现思路实现代码starter组件 实现思路 这里使用FutureTask&#xff0c;它通过get方法以阻塞的方式获取执行结果&#xff0c;并设定超时时间&#xff1a; public V get() throws InterruptedException, ExecutionException ;public V get(long timeout, TimeUnit un…...

c++设计模式之装饰器模式

作用 为现有类增加功能 案例说明 class Car { public:virtual void show()0; };class Bmw:public Car { public:void show(){cout<<"宝马汽车>>"<<endl;} };class Audi:public Car { public:void show(){cout<<"奥迪汽车>>&q…...

WordPress如何实现随机显示一句话经典语录?怎么添加到评论框中?

我们在一些WordPress网站的顶部或侧边栏或评论框中&#xff0c;经常看到会随机显示一句经典语录&#xff0c;他们是怎么实现的呢&#xff1f; 其实&#xff0c;boke112百科前面跟大家分享的『WordPress集成一言&#xff08;Hitokoto&#xff09;API经典语句功能』一文中就提供…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...