【数据结构】线性表--链表
【数据结构】线性表--链表
- 一.前情回顾
- 二.链表的概念
- 三.链表的实现
- 1.链表结点的结构:
- 2.申请新结点函数:
- 3.尾插函数:
- 4.头插函数:
- 5.尾删函数:
- 6.头删函数:
- 7.在指定结点之前插入:
- 8.在指定结点之后插入:
- 8.删除指定结点:
- 9.查找函数:
- 10.销毁链表:
- 四.全部源代码实现
- 1.头文件(声明动态顺序表的结构,操作等,起到目录作用):
- 2.源文件(具体实现各种操作):
- 3.测试文件(测试各个函数的功能)
- 五.单链表和顺序表的对比
- 1.存储分配方式
- 2.时间性能
- 3.空间性能
- 4.总结
一.前情回顾
上篇文章讲述了动态顺序表及其实现,我们知道了动态顺序表在物理结构上是连续的,因此我们也认识到它的缺点:
①如果空间不足需进行增容,付出一定的性能消耗,并且可能存在一定的空间浪费。
②在进行某些插入或删除操作时,需要大量移动数据。这是因为相邻数据元素在物理存储结构上也是连续存储的,中间没有空隙。
因此本篇文章将讲述线性表的另一种表示方法:链表。
二.链表的概念
链表,即线性表的链式实现,指用一组任意连续或者不连续的存储单元存储数据,通过指针像链条一样链结各个元素的一种存储结构。
如图所示:
因此,对于每个数据元素,除了要存储自身信息,也要存储后继(下一个)数据元素的信息。这两部分合起来被称为结点。
每个结点包含两个域,一个是数据域:存储数据元素的信息;另一个是指针域:存储后继元素的位置信息。n个结点链结成一个链表。如图所示:
对于线性表,总要有头有尾,我们把链表中第一个结点的存储位置叫做头指针,最后一个结点置为NULL。由于每个结点的指针域只包含一个指向后继位置的指针,因此该链表又称单链表(单向链表)。
三.链表的实现
1.链表结点的结构:
在C语言中用结构体指针来存储后继结点的信息。
typedef int SLDataType;//结点的结构体
typedef struct SListNode
{SLDataType data;//数据域struct SListNode* next;//指向下一个结点的指针域,所以指针类型应该为struct SListNode*
}SLTNode;//起别名,将struct SListNode简写成SLTNode
2.申请新结点函数:
因为在插入操作中需要频繁申请结点,因此可以将申请结点的操作封装成一个函数。
//申请新结点
SLTNode* BuySListNode(SLDataType x)
{SLTNode* NewNode = (SLTNode*)malloc(sizeof(SLTNode));NewNode->data = x;NewNode->next = NULL;return NewNode;
}
3.尾插函数:
需要特别注意的是,凡是涉及修改链表,必须传二级指针,因为链表本身是用每个结点的指针链结而成的,作为参数传递时是一级指针,再将每个结点的地址作为实参传递,这是二级指针。
//尾插函数
//需要传二级指针,否则形参的改变不影响实参
void SListPushBack(SLTNode** pphead, SLDataType x)
{assert(pphead);//不能传空地址,否则解引用找链表头结点会报错//创建新结点SLTNode* NewNode = (SLTNode*)malloc(sizeof(SLTNode));NewNode->data = x;NewNode->next = NULL;//链表为空,直接插入if (*pphead == NULL){*pphead = NewNode;}else{//需要找到最后一个结点才能尾插,因此先用一个cur结点标记当前所在位置SLTNode* cur = *pphead;while (cur->next != NULL)//循环结束走到最后一个结点{cur = cur->next;//让cur遍历到最后一个结点}if (NewNode == NULL){perror("malloc fail!");exit(1);}cur->next = NewNode;}
}
4.头插函数:
//头插函数
void SListPushFront(SLTNode** pphead, SLDataType x)
{assert(pphead);//创建新结点SLTNode* NewNode = BuySListNode(x);NewNode->next = *pphead;*pphead = NewNode;
}
5.尾删函数:
//尾删函数
void SListPopBack(SLTNode** pphead)
{assert(pphead && *pphead);//如果只有一个结点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLTNode* cur = *pphead;while (cur->next->next != NULL)//需要找到倒数第二个结点才能删除最后一个结点{cur = cur->next;}SLTNode* tmp = cur->next;free(tmp);tmp = NULL;cur->next = NULL;}
}
6.头删函数:
//头删函数
void SListPopFront(SLTNode** pphead)
{assert(pphead&&*pphead);//链表为空时不能删除SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;}
7.在指定结点之前插入:
//在指定结点之前插入函数
void SListInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
{assert(pphead && *pphead);assert(pos);//需要找到指定结点的前一个结点SLTNode* prev = *pphead;//可能第一个结点就是指定结点,此时相当于头插if (prev == pos){//直接调用头插函数SListPushFront(pphead, x);}else{while (prev->next != pos){prev = prev->next;}SLTNode* NewNode = BuySListNode(x);NewNode->next = prev->next;prev->next = NewNode;}
}
8.在指定结点之后插入:
//在指定结点之后插入函数
void SListInsertAfter(SLTNode** pphead, SLTNode* pos, SLDataType x)
{assert(pphead && *pphead);assert(pos);SLTNode* NewNode = BuySListNode(x);NewNode->next = pos->next;pos->next = NewNode;
}
8.删除指定结点:
//删除指定结点
void SListErase(SLTNode** pphead, SLTNode* pos)
{SLTNode* prev = *pphead;//如果第一个结点就是要删除的结点if (prev == pos){//直接调用头删SListPopFront(pphead);}else{while (prev->next != pos){prev = prev->next;}SLTNode* tmp = prev->next;//tmp即要删除的结点prev->next = tmp->next;free(tmp);tmp = NULL;}
}
9.查找函数:
//查找
SLTNode* SListFind(SLTNode* phead, SLDataType x)
{SLTNode* cur = phead;while (cur != NULL){if (cur->data == x)return cur;cur = cur->next;}//没找到或链表为空时,返回空指针return NULL;
}
10.销毁链表:
//销毁链表函数
void SListDestory(SLTNode** pphead)
{assert(pphead && *pphead);while (*pphead != NULL){SLTNode* tmp = *pphead;*pphead = (*pphead)->next;free(tmp);tmp = NULL;}
}
四.全部源代码实现
1.头文件(声明动态顺序表的结构,操作等,起到目录作用):
SList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int SLDataType;//结点的结构体
typedef struct SListNode
{SLDataType data;//数据域struct SListNode* next;//指向下一个结点的指针域,所以指针类型应该为struct SListNode*
}SLTNode;//起别名,将struct SListNode简写成SLTNode//打印函数(方便调试)
void SListPrint(SLTNode* phead);//申请新结点
SLTNode* BuySListNode(SLDataType x);//尾插函数
void SListPushBack(SLTNode** pphead, SLDataType x);//需要传二级指针,否则形参的改变不影响实参//头插函数
void SListPushFront(SLTNode** pphead, SLDataType x);//尾删函数
void SListPopBack(SLTNode** pphead);//头删函数
void SListPopFront(SLTNode** pphead);//在指定位置之前插入函数
void SListInsert(SLTNode** pphead, SLTNode* pos, SLDataType x);//在指定位置之后插入函数
void SListInsertAfter(SLTNode** pphead, SLTNode* pos, SLDataType x);//删除指定结点
void SListErase(SLTNode** pphead, SLTNode* pos);//查找
SLTNode* SListFind(SLTNode* phead, SLDataType x);//销毁链表函数
void SListDestory(SLTNode** pphead);
2.源文件(具体实现各种操作):
SList.c
#include"SList.h"//打印函数(方便调试)
void SListPrint(SLTNode* phead)
{assert(phead);SLTNode* cur = phead;while (cur != NULL)//循环结束走到空结点{printf(" %d ->", cur->data);cur = cur->next;}printf("NULL\n");
}//申请新结点
SLTNode* BuySListNode(SLDataType x)
{SLTNode* NewNode = (SLTNode*)malloc(sizeof(SLTNode));NewNode->data = x;NewNode->next = NULL;return NewNode;
}//尾插函数
//需要传二级指针,否则形参的改变不影响实参
void SListPushBack(SLTNode** pphead, SLDataType x)
{assert(pphead);//不能传空地址,否则解引用找链表头结点会报错//创建新结点SLTNode* NewNode = BuySListNode(x);//链表为空,直接插入if (*pphead == NULL){*pphead = NewNode;}else{//需要找到最后一个结点才能尾插,因此先用一个cur结点标记当前所在位置SLTNode* cur = *pphead;while (cur->next != NULL)//循环结束走到最后一个结点{cur = cur->next;//让cur遍历到最后一个结点}if (NewNode == NULL){perror("malloc fail!");exit(1);}cur->next = NewNode;}
}//头插函数
void SListPushFront(SLTNode** pphead, SLDataType x)
{assert(pphead);//创建新结点SLTNode* NewNode = BuySListNode(x);NewNode->next = *pphead;*pphead = NewNode;
}//尾删函数
void SListPopBack(SLTNode** pphead)
{assert(pphead && *pphead);//如果只有一个结点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLTNode* cur = *pphead;while (cur->next->next != NULL)//需要找到倒数第二个结点才能删除最后一个结点{cur = cur->next;}SLTNode* tmp = cur->next;free(tmp);tmp = NULL;cur->next = NULL;}
}//头删函数
void SListPopFront(SLTNode** pphead)
{assert(pphead&&*pphead);//链表为空时不能删除SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}//在指定结点之前插入函数
void SListInsert(SLTNode** pphead, SLTNode* pos, SLDataType x)
{assert(pphead && *pphead);assert(pos);//需要找到指定结点的前一个结点SLTNode* prev = *pphead;//可能第一个结点就是指定结点,此时相当于头插if (prev == pos){//直接调用头插函数SListPushFront(pphead, x);}else{while (prev->next != pos){prev = prev->next;}SLTNode* NewNode = BuySListNode(x);NewNode->next = prev->next;prev->next = NewNode;}
}//在指定结点之后插入函数
void SListInsertAfter(SLTNode** pphead, SLTNode* pos, SLDataType x)
{assert(pphead && *pphead);assert(pos);SLTNode* NewNode = BuySListNode(x);NewNode->next = pos->next;pos->next = NewNode;
}//删除指定结点
void SListErase(SLTNode** pphead, SLTNode* pos)
{SLTNode* prev = *pphead;//如果第一个结点就是要删除的结点if (prev == pos){//直接调用头删SListPopFront(pphead);}else{while (prev->next != pos){prev = prev->next;}SLTNode* tmp = prev->next;//tmp即要删除的结点prev->next = tmp->next;free(tmp);tmp = NULL;}
}//查找
SLTNode* SListFind(SLTNode* phead, SLDataType x)
{SLTNode* cur = phead;while (cur != NULL){if (cur->data == x)return cur;cur = cur->next;}//没找到或链表为空时,返回空指针return NULL;
}//销毁链表函数
void SListDestory(SLTNode** pphead)
{assert(pphead && *pphead);while (*pphead != NULL){SLTNode* tmp = *pphead;*pphead = (*pphead)->next;free(tmp);tmp = NULL;}
}
3.测试文件(测试各个函数的功能)
test.c
#include"SList.h"//测试尾插函数
void test01()
{SLTNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPrint(phead);
}//测试头插函数
void test02()
{SLTNode* phead = NULL;SListPushFront(&phead, 1);SListPushFront(&phead, 2);SListPushFront(&phead, 3);SListPushFront(&phead, 4);SListPrint(phead);
}//测试尾删函数
void test03()
{SLTNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPrint(phead);SListPopBack(&phead);SListPrint(phead);SListPopBack(&phead);SListPrint(phead);SListPopBack(&phead);SListPrint(phead);
}//测试头删函数
void test04()
{SLTNode* phead = NULL;SListPushFront(&phead, 1);SListPushFront(&phead, 2);SListPushFront(&phead, 3);SListPushFront(&phead, 4);SListPrint(phead);SListPopFront(&phead);SListPrint(phead);SListPopFront(&phead);SListPrint(phead);SListPopFront(&phead);SListPrint(phead);SListPopFront(&phead);SListPrint(phead);SListPopFront(&phead);SListPrint(phead);
}//测试查找函数
void test05()
{SLTNode* phead = NULL;SListPushFront(&phead, 1);SListPushFront(&phead, 2);SListPushFront(&phead, 3);SListPushFront(&phead, 4);SListPrint(phead);SLTNode* ret1 = SListFind(phead, 2);if (ret1 != NULL)printf("找到了\n");elseprintf("未找到\n");SLTNode* ret2 = SListFind(phead, 57);if (ret2 != NULL)printf("找到了\n");elseprintf("未找到\n");
}//测试在指定结点之前插入
void test06()
{SLTNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPrint(phead);//在第三个结点前插入57//先查找到第三个结点SLTNode* pos1 = SListFind(phead, 3);SListInsert(&phead, pos1, 57);SListPrint(phead);//在第一个结点前插入79//先查找到第一个结点SLTNode* pos2 = SListFind(phead, 1);SListInsert(&phead, pos2, 79);SListPrint(phead);//在最后一个结点前插入36//先查找到最后一个结点SLTNode* pos3 = SListFind(phead, 4);SListInsert(&phead, pos3, 36);SListPrint(phead);
}//测试在指定结点之后插入
void test07()
{SLTNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPrint(phead);//在第三个结点后插入57//先查找到第三个结点SLTNode* pos1 = SListFind(phead, 3);SListInsertAfter(&phead, pos1, 57);SListPrint(phead);//在第一个结点后插入79//先查找到第一个结点SLTNode* pos2 = SListFind(phead, 1);SListInsertAfter(&phead, pos2, 79);SListPrint(phead);//在最后一个结点后插入36//先查找到最后一个结点SLTNode* pos3 = SListFind(phead, 4);SListInsertAfter(&phead, pos3, 36);SListPrint(phead);
}//测试删除结点函数
void test08()
{SLTNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPrint(phead);//删除第一个结点SLTNode* pos1 = SListFind(phead, 1);SListErase(&phead, pos1);SListPrint(phead);//删除第三个结点SLTNode* pos2 = SListFind(phead, 3);SListErase(&phead, pos2);SListPrint(phead);//删除最后一个结点SLTNode* pos3 = SListFind(phead, 4);SListErase(&phead, pos3);SListPrint(phead);
}//测试销毁函数
void test09()
{SLTNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPrint(phead);SListDestory(&phead);SListPrint(phead);
}
int main()
{//test01();//test02();//test03();//test04();//test05();//test06();//test07();//test08();test09();return 0;
}
五.单链表和顺序表的对比
1.存储分配方式
顺序表采用一段连续的存储单元存储数据元素。
单链表采用一组任意的存储单元存储元素。
2.时间性能
查找:
顺序表按值查找O(n),按索引查找O(1)。
单链表O(n)。
插入和删除:
顺序表O(n)。
单链表O(1)。
3.空间性能
顺序表需要预分配空间,小了需再次分配,大了造成空间浪费。
单链表需要时申请结点空间。
4.总结
若线性表需要频繁查找,宜采用顺序存储结构。若频繁插入和删除,宜采用链式存储结构。比如说游戏开发中,对于用户注册的个人信息,除了注册时插入数据外,绝大多数情况都是读取,所以应该考虑用顺序存储结构 。而游戏中的玩 家的武器或者装备列表,随着玩家的游戏过程中,可能会随时增加或删除,此时再用顺序存储就不大合适了,链表结构就可以大展拳脚。当然,这只是简单的类比,现实中的软件开发,要考虑的问题会复杂得多。
总之,线性表的顺序存储和链式存储各有优缺点,不能简单说哪个好,哪个不好,需根据实际情况做出选择。
相关文章:
【数据结构】线性表--链表
【数据结构】线性表--链表 一.前情回顾二.链表的概念三.链表的实现1.链表结点的结构:2.申请新结点函数:3.尾插函数:4.头插函数:5.尾删函数:6.头删函数:7.在指定结点之前插入:8.在指定结点之后插…...
2022年第十三届蓝桥杯省赛B组Java题解
2022年第十三届蓝桥杯省赛B组Java题解 个人心得: 2022年蓝桥杯省赛Java B组共包含10道题目,其中填空题2道(A、B),编程题8道(C-J)。题目覆盖数论、字符串处理、动态规划、数据结构等核心知识点…...
【操作系统】死锁
1. 定义 死锁是指两个或多个进程(或线程)在执行过程中,因争夺资源而造成的一种僵局,每个进程都无限期地等待其他进程释放它们所持有的资源。在这种情况下,没有任何进程能够继续执行,除非有外部干预。 2. …...
Ubuntu22.04及以上版本buildroot SIGSTKSZ 报错问题
本文提供一种解决 Buildroot SIGSTKSZ 报错途径 解决途径来源参考:Buildroot error when building with Ubuntu 21.10 其出现原因在于 GNU C Library 2.34 release announcement: Add _SC_MINSIGSTKSZ and _SC_SIGSTKSZ. When _DYNAMIC_STACK_SIZE_SOU…...
postgresql数据库基本操作
1. 连接 PostgreSQL 数据库 首先,使用 psql 命令行工具连接到数据库。如果是本地连接,命令格式如下: psql -U postgres -d <数据库名称> -h <主机地址>其中: -U postgres:表示以 postgres 用户身份登录…...
【运维】构建基于Python的自动化运维平台:用Flask和Celery打造高效管理工具
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着企业IT基础设施的复杂性不断增加,手动运维已无法满足高效管理的需求。本文详细介绍如何基于Python构建一个自动化运维平台,利用Flask…...
ES6入门---第三单元 模块三:async、await
async function fn(){ //表示异步:这个函数里面有异步任务 let result await xxx //表示后面结果需要等待 } 读取文件里数据实例: const fs require(fs);//简单封装 fs封装成一个promise const readFile function (fileName){return…...
洛谷 P2866 [USACO06NOV] Bad Hair Day S
题目描述 农夫约翰有 N 头奶牛正在过乱头发节。 每一头牛都站在同一排面朝右,它们被从左到右依次编号为 1,2,⋯,N。编号为 i 的牛身高为 hi。第 N 头牛在最前面,而第 1 头牛在最后面。 对于第 i 头牛前面的第 j 头牛,如果 hi>hi1…...
TS 变量类型生成
TS简单类型注解 let count:number 15 let myName:string MIO let isLoading:boolean false let a:null null let b:undefined undefined let s:symbol Symbol()console.log(hello ts)TS数组类型 数组类型两种写法: 问题:数组中只能存在单一类型数…...
工业大模型:从设备诊断到工艺重构
引言 工业大模型正在引发制造业认知革命。据埃森哲研究,到2026年全球工业大模型市场规模将突破280亿美元,其中工艺优化应用占比达42%。本文将系统解析工业大模型的"预训练-领域适配-应用落地"技术路径,并通过设备健康诊断与工艺参数生成的实践案例,展示如何构建…...
【项目篇之统一内存操作】仿照RabbitMQ模拟实现消息队列
我们的操作分为两种,一种是在内存上进行统一的操作,一种是在硬盘上面操作,今天我写的文章是编写了一个MemoryDataCenter类来实现了 在内存上面的统一操作: 实现统一内存操作 如何使用内存来组织数据 创建一个类来统一管理内存上的…...
强化学习机器人模拟器——GridWorld:一个用于强化学习的 Python 环境
GridWorld 是一个为强化学习(Reinforcement Learning, RL)实验设计的多功能 Python 环境。它提供了一个可定制的二维网格,智能体(agent)需要从起始位置导航到目标位置,避开障碍物、穿越泥泞单元格并收集奖励。本篇博客将详细介绍 grid_world.py 代码中实现的 GridWorld 环…...
DeepSeek Copilot idea插件推荐
🌌 DeepSeek Copilot for IntelliJ IDEA 让 AI 成为你的编程副驾驶,极速生成单元测试 & 代码注释驱动开发! 🚀 简介 DeepSeek Copilot 是一款为 IntelliJ IDEA 打造的 AI 编程助手插件,它能够智能分析你的代码逻辑…...
vue-cropper实现图片裁剪
一、什么是vue-cropper? Vue-Cropper 是一个基于 Vue.js 的图片裁剪组件库,专为 Web 应用设计。当你在网上搜索的时候发现还有一个叫cropper的库,下面是他们的区别: 特性cropper.jsvue-cropper框架依赖纯 JavaScript&am…...
MPI,Pthreads和OpenMP等并行实验环境配置
(假设你已按照文档前面的步骤正确安装了 VMware 和 Ubuntu 20.04) 第一部分:安装 C/OpenMP/Pthreads 环境(修正后) 打开终端: 在 Ubuntu 中启动终端应用程序。 更新软件包列表: sudo ap…...
Spring AI Advisors API:AI交互的灵活增强利器
Spring AI Advisors API:AI交互的灵活增强利器 前言 在当今的软件开发领域,随着人工智能技术的飞速发展,将AI融入应用程序变得越来越普遍。Spring AI作为一个强大的框架,为开发者提供了便捷的方式来实现这一目标。其中的Advisor…...
排序功法入门指南【江湖算法笔记】
话说江湖风云变幻,各路英雄好汉行走江湖,总得有个名号排行。若问“东邪西毒南帝北丐”谁强谁弱,总得排个座次不是?这排序之道,恰似武功秘籍,练好了能号令群雄,练岔了怕是要被笑掉大牙࿰…...
Free Draft Model!Lookahead Decoding加速大语言模型解码新路径
Free Draft Model!Lookahead Decoding加速大语言模型解码新路径 大语言模型(LLMs)在当今AI领域大放异彩,但其自回归解码方式锁死了生成效率。本文将为你解读一种全新的解码算法——Lookahead Decoding,它无需Draft Mo…...
Spring AI 实战:第八章、Spring AI Tool Calling之与时俱进
引言:AI的"知识截止日期"尴尬 如果你想问大模型"明天是星期几?",猜猜TA会怎么答复你~ @GetMapping("/tools/simple/test") public String simpleTest() {return chatClient.prompt...
PyTorch数据集与数据集加载
PyTorch中的Dataset与DataLoader详解 1. Dataset基础 Dataset是PyTorch中表示数据集的抽象类,我们需要继承它并实现两个关键方法: from torch.utils.data import Datasetclass CustomDataset(Dataset):def __init__(self, data, labels):""…...
探秘 Git 底层原理:理解版本控制的基石
Git 是一款开源的分布式版本控制系统,在软件开发领域广泛应用,能有效管理项目的版本变更,Git 已经成为了版本控制的代名词。日常使用中,我们通过git commit提交代码,用git push推送变更,这些便捷操作背后&a…...
chili3d调试10 网页元素css node deepwiki 生成圆柱体 生成零件图片
.input是input的外框,.input input是input的内框 沙雕 全部input都换成textarea了 自己的方法用接口定义,把自己的方法pub出去,定义在内部拉出去只是取个值 这其实是mainwindow端pub回来的 窗口pub端把数据pub回 mainwindow端让mainwindow端…...
【计网】互联网的组成
回顾: 互联网(Internet):它是一个专有名词,是一个特定的互连网,它是指当下全球最大的、最开放的、由众多网络相互连接而形成的特定的的互连网,采用TCP/IP协议族作为通信规则。 一、互联网的组成部分 从互联网的工作方…...
Go语言接口实现面对对象的三大特征
一.知识回顾 在 Go 语言中,接口是一种强大的抽象机制,它允许我们定义一组方法签名,任何类型只要实现了这些方法,就被视为实现了该接口。接口的实现是隐式的,这意味着类型不需要显式声明它实现了某个接口,只…...
TS 字面量类型
str是string类型l str2是常量,类型是字面量类型 用途:配合联合类型确定更严谨精确的可选值利恩...
langchain中 callbacks constructor实现
目录 代码代码解释代码结构代码功能 类似例子 代码 from typing import Any, Dict, Listfrom langchain_openai import ChatOpenAI from langchain_core.callbacks import BaseCallbackHandler from langchain_core.messages import BaseMessage from langchain_core.outputs …...
小土堆pytorch--tensorboard的使用
小土堆pytorch--tensorboard的使用 小土堆pytorch--tensorboard的使用0.介绍1.使用tensorboard绘制 y x 等简单函数1.1 相应的代码1.2 对上述代码的解释1.3 可能遇到的问题1.3.1 问题1.3.2 解决方法 2.使用tensorboard加载数据集中的图片2.1 相应代码2.2 对上述代码的解释2.2.…...
从 0 到 1:使用 Jetpack Compose 和智能自动化实现高效 Android UI 开发
现代 Android UI 开发正逐步从命令式 XML 向声明式 Compose 转变。Compose 凭借其简洁、高效、易测试的特点,能够让开发者更专注于界面和业务逻辑,而不必陷入大量模板化的代码。手把手带你构建一个完整的 Todo List 应用,并演示如何借助自动化…...
学习黑客 week1周测 复盘
Day 7 – 周测 & 复盘 今天任务: 完成 10 道快测题,涵盖 Week 1 的核心知识点:《CIA 三要素》、OWASP Top 10、MITRE ATT&CK、NIST RMF、Linux 权限、TCP/IP、网络安全法、“黑客五阶段” 与风险管理。撰写 300 字周总结…...
【五一培训】Day 3
Topic 1:元学习 一、概念:learn to learn 区分少样本学习与元学习 少样本学习(Few-shot learning)是元学习的一个重要应用,它指的是机器能够在仅有少量样本的情况下,成功地学习和泛化到新任务上。在许多现…...
C++继承详讲
1.继承的概念 继承是实现代码复用的手段,它允许程序员在保持基类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。 2.继承和组合 1.继承体系下,子类对象包含父类的成员。组合体系下,子类对象包含…...
第四节:OpenCV 基础入门-第一个 OpenCV 程序:图像读取与显示
一、引言:为什么选择 OpenCV? 在计算机视觉领域,OpenCV(Open Source Computer Vision Library)是一个开源的、跨平台的计算机视觉库,广泛应用于图像处理、模式识别、机器学习等领域。它支持多种编程语言&a…...
基于PHP实现的easy管理系统
easy管理系统 2.0.1 easy管理系统 是一个多功能的 Web 管理平台,旨在简化项目管理、文件共享和协作流程。它集成了大创项目管理、在线文档生成、代码托管等多种功能,并提供了用户管理、系统设置、日志查看等后台管理能力。 ✨ 功能特性 统一管理平台:…...
ios systeam introduction
Here is an in-depth look at Apple’s iOS, from its inception to its latest major release, covering architecture, core components, security, app lifecycle, development tools, and the headline features of iOS 18. iOS began life as “iPhone OS,” unveiled alo…...
【论文阅读】LLMOPT:一种提升优化泛化能力的统一学习框架
文章目录 第一遍一、摘要二、关键词三、预知识1. 什么是优化泛化问题2. 什么是消融研究3. model alignment(模型对齐) 第二遍:了解论文论点一、研究背景与目的二、相关工作三、LLMOPT框架四、METHODOLOGY(方法论)1. 数据处理2. 学习过程3. 自…...
Prompt多版本测试指南:如何科学评估不同提示词的效果
对于现代AI开发来说,同一个需求,不同的提示表达方式往往会产生截然不同的结果。因此,如何设计、测试和优化提示词成为了一项关键技能。 本文将深入探讨Prompt多版本测试的技术方法,帮助你系统性地评估不同提示词的效果࿰…...
每日c/c++题 备战蓝桥杯(洛谷P1015 [NOIP 1999 普及组] 回文数)
洛谷P1015 [NOIP 1999 普及组] 回文数 题解 题目描述 P1015 回文数 是NOIP 1999普及组的经典模拟题。题目要求如下: 给定一个数N(十进制)和进制K(2≤K≤16),将N转换为K进制表示后,通过以下操…...
最小单调子序列的长度+联通最小乘积
因为题目ICPC是英文版,基于大家都不怎么看的懂的情况下直接给大家进行题目讲解 题目1: 题目分析: 构造一个长度为n的排列 p(里面的数是1-n),不能重复得 max(lis(p),lds(p)) 最小。 其中,lis(p)是 p 的最长递增子序…...
OpenHarmony平台驱动开发(一),ADC
OpenHarmony平台驱动开发(一) ADC 概述 功能简介 ADC(Analog to Digital Converter),即模拟-数字转换器,可将模拟信号转换成对应的数字信号,便于存储与计算等操作。除电源线和地线之外&#…...
数据结构与算法:回溯
回溯 先给出一些leetcode算法题,以后遇见了相关题目再往上增加 主要参考代码随想录 2.1、组合问题 关于去重:两种写法的性能分析 需要注意的是:使用set去重的版本相对于used数组的版本效率都要低很多,大家在leetcode上提交&#x…...
KaiwuDB X 遨博智能 | 构建智能产线监测管理新系统
01 项目背景 遨博智能作为国内协作机器人行业领军企业,深度布局制造、农业、医疗、教育、民生等场景,出货量连续四年蝉联国内第一、世界第二。随着工业自动化的蓬勃发展,遨博智能生产规模不断扩大,先后在常州、淄博等地建设完成…...
高等数学第三章---微分中值定理与导数的应用(§3.6 函数图像的描绘§3.7 曲率)
3.6 函数图像的描绘 一、曲线的渐近线 对于某些函数,其图形向无穷远处延伸时,会越来越趋近于某一条直线,这条直线被称为曲线的渐近线 (Asymptote)。 1. 定义 若曲线 y f ( x ) yf(x) yf(x) 上一点 P ( x , y ) P(x, y) P(x,y) 沿曲线趋…...
【PostgreSQL数据分析实战:从数据清洗到可视化全流程】4.2 数据类型转换(CAST函数/自定义函数)
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 PostgreSQL数据分析实战:数据清洗之数据类型转换(CAST函数/自定义函数)4.2 数据类型转换:让数据「格式正确,类型对…...
docker:制作镜像+上传镜像+拉取镜像
1.dockerfile制作镜像 示例内容: 1.创建一个index.js的文件 console.log("hello world")2.在相同目录下创建名为dockerfile的文件 FROM node:alpine COPY index.js /index.js CMD node /index.js3.构建镜像 docker build -t minterra/hello-docker . …...
信息系统监理师第二版教材模拟题第三组(含解析)
信息系统监理师模拟题第三组(30题) 监理基础理论 信息系统工程监理的性质是( ) A. 服务性、独立性、公正性、科学性 B. 强制性、营利性、行政性、技术性 C. 临时性、从属性、随意性、主观性 D. 单一性、封闭性、被动性、保守性答案:A 解析:监理具有服务性、独立性、公正…...
潮乎盲盒商城系统全开源多级分销推广海报奖品兑换试玩概率OSS云存储多端源码
一、源码描述 这是一套潮乎盲盒商城源码,仿小叮当盲盒商城,后端Laravel框架前端uniappvue,前后端数据库分离,支持四端同步数据(H5小程序等),测试环境: php7.4,mysql5.6,…...
文章记单词 | 第64篇(六级)
一,单词释义 residence [ˈrezɪdəns] n. 住宅;居住;住所;居住期fling [flɪŋ] v. (用力地)扔,掷,抛;猛动(身体或身体部位);急冲&a…...
数据同步实战篇
文章目录 数据同步实战篇1. mysql数据同步1.1 mysql集群部署1.2 数据同步1.2.1 同步复制1.2.2 异步复制1.2.3 半同步复制 2. redis数据同步2.1 redis集群部署2.2 数据同步 3. mq数据同步3.1 mq集群部署3.2 数据同步 4. es数据同步4.1 es集群部署4.2 数据同步 数据同步实战篇 数…...
具身系列——Double DQN算法实现CartPole游戏(强化学习)
完整代码参考: rl/ddqn_cartpole.py 陈先生/ailib - Gitee.com 部分训练得分: Model saved to ./output/best_model.pth New best model saved with average reward: 9.6 Episode: 0 | Train Reward: 25.0 | Epsilon: 0.995 | Best Eval Avg: 9.6…...
以下是在 Ubuntu 上的几款PDF 阅读器,涵盖轻量级、功能丰富和特色工具:
默认工具:Evince(GNOME 文档查看器) 特点:Ubuntu 预装,轻量快速,支持基本标注和书签。 安装:已预装,或手动安装: sudo apt install evince功能全面:Okular&…...