C语言数据结构-基于单链表实现通讯录

文章目录

  • 1 基础要求
  • 2 通讯录功能
    • 2.1 引入单链表的文件
    • 2.2 定义联系人数据结构
    • 2.3 打开通讯录
    • 2.4 保存数据后销毁通讯录
    • 2.5 添加联系人
    • 2.6 删除联系人
    • 2.7 修改联系人
    • 2.8 查找联系人
    • 2.9 查看通讯录
  • 3 通讯录代码展示
    • 3.1 SeqList_copy.h
    • 3.2 SeqList_copy.c
    • 3.3 Contact.h
    • 3.4 Contact.c
    • 3.5 test.c
    • 3.6 调试控制台截图


1 基础要求

单链表,文件操作,结构体,二级指针
思路:利用上一篇博客-单链表,对单链表简易修改,应用到通讯录.

2 通讯录功能

通讯录只能能存100个人
用户信息:名字,性别,年龄,电话,地址
通讯录的展示,增,删,改,查,找.
联系人信息存储

2.1 引入单链表的文件

为了显现区别,笔者备份单链表的文件并且更名为SeqList_copy.hSeqList_copy.c
创建Contact.hContact.c以及测试代码功能的test.c
test.cContact.c引用的头文件都是Contact.hSeqList_copy.h
在这里插入图片描述

2.2 定义联系人数据结构

Contact.h头文件中
定义名字最大长度,性别最大长度,电话最大长度,地址最大长度

#define NAME_MAX 120
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 50
//前置声明
typedef struct SListNode contact;
//定义结构体
typedef struct ContactInfo
{ char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}ConInfo;

2.3 打开通讯录

void ContactInit(contact** pcon)
{FILE* pf = fopen("Contact_Info.txt", "rb");	//二进制方式打开文件if (pf == NULL){perror("fopen error.\n");  //主动报错,打开失败return;}ConInfo info;//回顾一下fread //size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );//从流中读取一个由count元素组成的数组,每个元素的大小为size字节,并将它们存储在ptr指定的内存块中。//流的位置指示器按读取的总字节数前进。//如果成功读取的总字节数为(size * count)while (fread(&info, sizeof(info), 1, pf)){SLPushBack(pcon, info);}printf("历史数据已导入通讯录\n");
}

2.4 保存数据后销毁通讯录

销毁通讯录之前一定要保存数据,不然2.3打开有存储联系人的通讯录的作用就没有了

void ContactSave(contact* con)
{FILE* pf = fopen("Contact_Info.txt", "wb");if (pf == NULL){perror("fopen error\n");return;}contact* cur = con;while (cur){fwrite(&(cur->data), sizeof(cur->data), 1, pf);cur = cur->next;}printf("成功保存通讯录数据\n");
}void ContactDestory(contact** pcon)
{ContactSave(*pcon);SLDestory(pcon);
}

2.5 添加联系人

使用单链表一节中尾插法添加数据

void ContactAdd(contact** pcon)
{ConInfo info;printf("请输入添加联系人姓名:\n");scanf("%s", &info.name);printf("请输入添加联系人性别:\n");scanf("%s", &info.sex);printf("请输入添加联系人年龄:\n");scanf("%d", &info.age);printf("请输入添加联系人电话:\n");scanf("%s", &info.tel);printf("请输入添加联系人地址:\n");scanf("%s", &info.addr);SLPushBack(pcon, info);printf("已添加联系人数据\n");
}

2.6 删除联系人

借助FindByName()函数,找到索引.然而缺陷明显,找到的索引是第一次出现的输入的姓名,同样,只能通过姓名查找

//我们这里通过姓名删除联系人
contact* FindByName(contact* con, char name[])
{contact* cur = con;while (cur){if (strcmp(cur->data.name,name) == 0){return cur;}cur = cur->next;}return NULL;
}void ContactDel(contact** pcon)
{char name[NAME_MAX];printf("请输入你要删除的联系人姓名:\n");scanf("%s", name);contact* pos = FindByName(*pcon, name);if (pos == NULL){printf("该联系人不存在\n");return;}SLErase(pcon, pos);printf("已删除该联系人\n");
}

2.7 修改联系人

注意age年龄是int整型,其他四个数据结构都是数组,用scanf时,这里的数组相当于首元素地址,不用&.

void ContactModify(contact* con)
{char name[NAME_MAX];printf("请输入你要修改的联系人姓名:\n");scanf("%s", name);contact* pos = FindByName(con, name);if (pos == NULL){printf("该联系人不存在\n");return;}printf("该联系人姓名修改为:\n");scanf("%s", pos->data.name);	printf("该联系人性别修改为:\n");scanf("%s", pos->data.sex);	printf("该联系人年龄修改为:\n");scanf("%d", &pos->data.age);	printf("该联系人电话修改为:\n");scanf("%s", pos->data.tel);printf("该联系人地址修改为:\n");scanf("%s", pos->data.addr);printf("修改成功\n");
}

2.8 查找联系人

同样根据姓名查看详细联系人的通讯录信息

void ContactFind(contact* con)
{char name[NAME_MAX];printf("请输入你要查找的联系人姓名:\n");scanf("%s", name);contact* pos = FindByName(con, name);if (pos == NULL){printf("该联系人不存在\n");return;}printf("找到了\n");printf("%s %s %d %s %s\n",pos->data.name,pos->data.sex,pos->data.age,pos->data.tel,pos->data.addr);
}

2.9 查看通讯录

第一次自己写的时候,cur=cur->next放在while循环外面了.QAQ

void ContactShow(contact* con)
{printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");contact* cur = con;while (cur){printf("%s %s %d %s %s\n", cur->data.name, cur->data.sex, cur->data.age, cur->data.tel, cur->data.addr);cur = cur->next;}
}

3 通讯录代码展示

3.1 SeqList_copy.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include"Contact.h"//定义链表的结构
//typedef int SLDataType
typedef struct ContactInfo SLDataType;   //更改SLDataType的类型typedef struct SListNode
{SLDataType data;	//保存的数据struct SListNode* next;		//指针变量存放下一个节点的地址
}SLNode;//1 打印链表
void SLPrint(SLNode* phead);//2 尾插
void SLPushBack(SLNode** pphead, SLDataType x);
//3 头插
void SLPushFront(SLNode** pphead, SLDataType x);//4 尾删
void SLPopBack(SLNode** pphead);//5 头删
void SLPopFront(SLNode** pphead);//SLFind()找到要查找数据的下标
//找节点的函数这里传一级实际上就可以了,因为不改变头结点
//但是这里要写二级指针,因为要保持接口一致性
//缺点:这个函数有一定的局限性,他找到数据x的下标是第一次出现的x的下标后,不会找后续的x的下标
SLNode* SLFind(SLNode** pphead, SLDataType x);//6 定点前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x);//7 定点后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x);//8 删除pos节点
void  SLErase(SLNode** pphead, SLNode* pos);//9 删除pos后的节点
void SLEraseAfter(SLNode* pos);//10 销毁链表
void SLDestory(SLNode** pphead);

3.2 SeqList_copy.c

#include"SList_copy.h"//1 创建新的节点的函数
SLNode* SLBuyNode(SLDataType x)
{SLNode* node = (SLNode*)malloc(sizeof(SLNode));node->data = x;node->next = NULL;return node;
}//2 尾插
void SLPushBack(SLNode** pphead, SLDataType x)	//保存第一个节点的指针的地址
{assert(pphead);//创建一个节点SLNode* node = SLBuyNode(x);if (*pphead == NULL){*pphead = node;return;}//链表不为空,找尾SLNode* pcur = *pphead;while (pcur->next)//相当于pcur->next!=NULL{pcur = pcur->next;}pcur->next = node;
}//3 头插
void SLPushFront(SLNode** pphead, SLDataType x)
{assert(pphead);SLNode* node = SLBuyNode(x);//新结点跟头结点连接起来node->next = *pphead;//让新节点成为头结点*pphead = node;
}//4 尾删
void SLPopBack(SLNode** pphead)
{assert(pphead);assert(*pphead);	//第一个节点不能为空//判断只有一个结点的情况if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}//找到尾节点和尾节点的前一个节点SLNode* pre = NULL;SLNode* ptail = *pphead;while (ptail->next){pre = ptail;ptail = ptail->next;}//pre的next指针不指向ptail,而是指向ptail的下一个节点//pre->next = NULL;pre->next = ptail->next;//因为在SLPrint(SLNode* phead)函数中有判断节点是否为空while (pcur),所以置空free(ptail);ptail = NULL;}//5 头插
void SLPopFront(SLNode** pphead)
{assert(pphead);assert(*pphead);	//第一个节点不能为空SLNode* del = *pphead;*pphead = (*pphead)->next;free(del);del = NULL;
}//6 定点前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
{assert(pphead);assert(pos);	//pos不能为空assert(*pphead);  //NULL前插入数据是荒谬的,所以assert第一个节点SLNode* node = SLBuyNode(x);//当只有一个结点(pos就是第一个节点)//if (((*pphead)->next) == NULL||pos==*pphead),可以简化成以下代码if (pos == *pphead) {node->next = *pphead;*pphead = node;return;}//找到pos的前一个节点SLNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}//处理pre node pos的位置node->next = pos;pre->next = node;
}//7 定点后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x)
{assert(pos);SLNode* node = SLBuyNode(x);node->next = pos->next;pos->next = node;
}//8 删除pos节点
void SLErase(SLNode** pphead, SLNode* pos)
{assert(*pphead);assert(pphead);assert(pos);//pos是头结点if (pos == *pphead){*pphead = (*pphead)->next;free(pos);return;}//pos不是头结点,找pos的前一个节点SLNode* pre = *pphead;while (pre->next != pos){pre = pre->next;}pre->next = pos->next;free(pos);pos = NULL;   //代码规范
}//9 删除pos后的节点
void SLEraseAfter(SLNode* pos)
{//删除pos之后的节点也不能空assert(pos && pos->next);SLNode* del = pos->next;pos->next = del->next;free(del);
}void SLDestory(SLNode** pphead)
{assert(pphead);SLNode* pcur = *pphead;while (pcur){SLNode* next = pcur->next;free(pcur);pcur = next;}//头结点记得置空*pphead = NULL;
}

3.3 Contact.h

#pragma once
//创建保存联系人数据的结构
#define NAME_MAX 120
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 50typedef struct ContactInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}ConInfo;
//前置声明
typedef struct SListNode contact;//1.打开通讯录
void ContactInit(contact** pcon);//2.保存数据后销毁通讯录
void ContactDestory(contact** pcon);//3.添加联系人
void ContactAdd(contact** pcon);//4.删除联系人
void ContactDel(contact** pcon);//5.修改联系人
void ContactModify(contact* con);//6.查找联系人
void ContactFind(contact* pcon);//7.查看通讯录
void ContactShow(contact* pcon);

3.4 Contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
#include"SList_copy.h"//1.打开通讯录
void ContactInit(contact** pcon)
{FILE* pf = fopen("Contact_Info.txt", "rb");if (pf == NULL){perror("fopen error.\n");  //主动报错,打开失败return;}ConInfo info;//回顾一下fread //size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );//从流中读取一个由count元素组成的数组,每个元素的大小为size字节,并将它们存储在ptr指定的内存块中。//流的位置指示器按读取的总字节数前进。//如果成功读取的总字节数为(size * count)while (fread(&info, sizeof(info), 1, pf)){SLPushBack(pcon, info);}printf("历史数据已导入通讯录\n");
}void ContactSave(contact* con)
{FILE* pf = fopen("Contact_Info.txt", "wb");if (pf == NULL){perror("fopen error\n");return;}contact* cur = con;while (cur){fwrite(&(cur->data), sizeof(cur->data), 1, pf);cur = cur->next;}printf("成功保存通讯录数据\n");
}void ContactDestory(contact** pcon)
{ContactSave(*pcon);SLDestory(pcon);
}void ContactAdd(contact** pcon)
{ConInfo info;printf("请输入添加联系人姓名:\n");scanf("%s", &info.name);printf("请输入添加联系人性别:\n");scanf("%s", &info.sex);printf("请输入添加联系人年龄:\n");scanf("%d", &info.age);printf("请输入添加联系人电话:\n");scanf("%s", &info.tel);printf("请输入添加联系人地址:\n");scanf("%s", &info.addr);SLPushBack(pcon, info);printf("已添加联系人数据\n");
}//我们这里通过姓名删除联系人
contact* FindByName(contact* con, char name[])
{contact* cur = con;while (cur){if (strcmp(cur->data.name,name) == 0){return cur;}cur = cur->next;}return NULL;
}void ContactDel(contact** pcon)
{char name[NAME_MAX];printf("请输入你要删除的联系人姓名:\n");scanf("%s", name);contact* pos = FindByName(*pcon, name);if (pos == NULL){printf("该联系人不存在\n");return;}SLErase(pcon, pos);printf("已删除该联系人\n");
}void ContactModify(contact* con)
{char name[NAME_MAX];printf("请输入你要修改的联系人姓名:\n");scanf("%s", name);contact* pos = FindByName(con, name);if (pos == NULL){printf("该联系人不存在\n");return 1;}printf("该联系人姓名修改为:\n");scanf("%s", pos->data.name);	printf("该联系人性别修改为:\n");scanf("%s", pos->data.sex);	printf("该联系人年龄修改为:\n");scanf("%d", &pos->data.age);	printf("该联系人电话修改为:\n");scanf("%s", pos->data.tel);printf("该联系人地址修改为:\n");scanf("%s", pos->data.addr);printf("修改成功\n");
}void ContactFind(contact* con)
{char name[NAME_MAX];printf("请输入你要查找的联系人姓名:\n");scanf("%s", name);contact* pos = FindByName(con, name);if (pos == NULL){printf("该联系人不存在\n");return;}printf("找到了\n");printf("%s %s %d %s %s\n",pos->data.name,pos->data.sex,pos->data.age,pos->data.tel,pos->data.addr);
}void ContactShow(contact* con)
{printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");contact* cur = con;while (cur){printf("%s %s %d %s %s\n", cur->data.name, cur->data.sex, cur->data.age, cur->data.tel, cur->data.addr);cur = cur->next;}
}

3.5 test.c

test()我封装了五个函数,都是用来测试通讯录功能的,调试结束后,就将函数封装在一起,写一个菜单完成通讯录功能.

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
#include"SList_copy.h"void test1()
{contact *pcontact=NULL;ContactInit(&pcontact);
}void test2()
{contact* pcontact = NULL;ContactInit(&pcontact);ContactAdd(&pcontact);ContactDel(&pcontact);ContactShow(pcontact);}void test3()
{contact* pcontact = NULL;ContactInit(&pcontact);ContactShow(pcontact);ContactAdd(&pcontact);ContactShow(pcontact);ContactDel(&pcontact);ContactShow(pcontact);
}
void test4()
{contact* pcontact = NULL;ContactInit(&pcontact);ContactAdd(&pcontact);ContactAdd(&pcontact);ContactShow(pcontact);ContactFind(pcontact);ContactShow(pcontact);}void test5()
{contact* pcontact = NULL;ContactInit(&pcontact);ContactAdd(&pcontact);ContactShow(pcontact);ContactModify(pcontact);ContactShow(pcontact);ContactDestory(&pcontact);
}void menu()
{printf("\n");printf("****************************\n");printf("****************************\n");printf("************通讯录***********\n");printf("*********1.添加联系人********\n");printf("*********2.删除联系人********\n");printf("*********3.修改联系人********\n");printf("*********4.查找联系人********\n");printf("*********5.查看通讯录********\n");printf("*********0.退  出************\n");printf("****************************\n");printf("****************************\n");
}int main()
{//test1();//test2();//test3();//test4();//test5();int op = 0;contact* con=NULL;ContactInit(&con);do {menu();printf("请选择:\n");scanf("%d", &op);switch (op){case 1:ContactAdd(&con);break;case 2:ContactDel(&con);break;case 3:ContactModify(con);break;case 4:ContactFind(con);break;case 5:ContactShow(con);break;case 0:printf("退出了哈\n");break;default:printf("输入错误\n");break;}} while (op!=0);ContactDestory(&con);return 0;
}

3.6 调试控制台截图

在这里插入图片描述

这里忘记啥问题了,一转眼就忘了
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在多次语法错误,死循环,输出乱码,代码崩溃后,终于简单完成通讯录的功能!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/210357.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

模块化机房在大数据时代的角色:高效、可扩展的数据存储和处理平台

随着大数据时代的到来&#xff0c;数据已经成为企业竞争的核心资源。然而&#xff0c;传统的数据中心已经无法满足现代业务的需求&#xff0c;尤其是在数据存储和处理方面。模块化机房作为一种新型的数据中心建设模式&#xff0c;具有高效、可扩展等优势&#xff0c;逐渐成为大…

PyCharm编辑器结合Black插件,轻松实现Python代码格式化

大家好&#xff0c;使用Black对Python代码进行格式化&#xff0c;可使代码看起来更美观。但是&#xff0c;随着项目规模不断变大&#xff0c;对每个文件运行Black变得很繁琐。本文就来介绍在PyCharm中实现这一目标的方法。 1.安装Black 首先&#xff0c;在虚拟环境中安装Blac…

二叉树的锯齿形层序遍历[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类推&#xff0c;层与层之间交替进行&#xff09;。 示例 1&#xff1a; 输…

认识线程和创建线程

目录 1.认识多线程 1.1线程的概念 1.2进程和线程 1.2.1进程和线程用图描述关系 1.2.2进程和线程的区别 1.3Java 的线程和操作系统线程的关系 2.创建线程 2.1继承 Thread 类 2.2实现 Runnable 接口 2.3匿名内部类创建 Thread 子类对象 2.4匿名内部类创建 Runnable 子类对…

使用贝叶斯网络检测因果关系,提升模型效果更科学(附Python代码)

虽然机器学习技术可以实现良好的性能&#xff0c;但提取与目标变量的因果关系并不直观。换句话说&#xff0c;就是&#xff1a;哪些变量对目标变量有直接的因果影响&#xff1f; 机器学习的一个分支是贝叶斯概率图模型(Bayesian probabilistic graphical models)&#xff0c;也…

【Com通信】Com模块详细介绍

目录 前言 1. Com模块功能介绍 2.关键概念理解 3.功能详细设计 3.1 Introduction 3.2 General Functionality 3.2.1 AUTOSAR COM basis 3.2.2 Signal Values 3.2.3 Endianness Conversion and Sign Extension 3.2.4 Filtering 3.2.5 Signal Gateway 3.3 Normal Ope…

2.2 网络多线程(私聊、群发、发送文件、推送新闻、离线留言)

文章目录 一、私聊1.1 分析1.2 客户端1.2.1 MessageClientService 私聊类1.2.2 ClientConnectServerThread 线程类 1.3 服务端1.3.1 ServerConnectClientThread 线程类 1.4功能演示 二、群发消息2.1 分析2.2 客户端2.2.1 MessageClientService类2.2.2 ClientConnectServerThrea…

通过仿真理解完整的阵列信号噪声模型

概要 噪声对无线电设备的信号接收会造成影响,是通信、雷达、导航、遥感等工程应用领域中的关键考虑因素。通常认为阵列合成能够提升信噪比,但忽略了这一论断的前提,即不同通道引入的噪声互不相关。但实际应用中,接收的噪声不仅仅包含信道引入的不相关噪声,还包含从外界环…

1-6、编程语言排行榜

语雀原文链接 https://www.tiobe.com/tiobe-index/

IntelliJ IDEA创建一个Maven项目

在IDEA中创建Maven项目&#xff0c;前提是已经安装配置好Maven环境 。 本文主要使用的是IntelliJ IDEA 2022.2.1 (Community Edition) 1.创建一个新project:File>Project 2.修改Maven配置&#xff1a;File>Settings>搜索maven 创建好的工程如下&#xff1a; src/main…

Chart 8 内核优化

文章目录 前言8.1 内核融合和拆分8.2 编译选项8.3 Conformant&#xff08;规范&#xff09; vs. fast vs. native math functions8.4 Loop unrolling8.5 避免分支发散8.6 Handle image boundaries8.7 Avoid the use of size_t8.8 通用 vs. 具名内存地址空间8.9 Subgroup8.10 Us…

SpringSecurity6 | 自定义认证规则

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…

移相干涉技术1-多种干涉条纹仿真模拟生成(原理转载+代码实现 包括模拟生成干涉条纹图)

过去的干涉测量技术是通过人的肉眼或者相机拍摄&#xff0c;来直观判断干涉图中条纹特征进而完成测量&#xff0c;该方法的不稳定因素&#xff08;比如人的主观意志&#xff09;很多&#xff0c;其精度误差在/10左右38]&#xff1b;现代干涉测量技术通过将电子技术、计算机技术…

智能优化算法应用:基于厨师算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于厨师算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于厨师算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.厨师算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

一加 12 Pop-up快闪活动来袭,十城联动火爆开启

12 月 9 日&#xff0c;一加 12 Pop-up 快闪活动在北京、深圳、上海、广州等十城联动开启&#xff0c;各地加油欢聚快闪现场&#xff0c;抢先体验与购买一加 12。作为一加十年超越之作&#xff0c;一加 12 全球首发拥有医疗级护眼方案和行业第一 4500nit 峰值亮度的 2K 东方屏、…

C++新经典模板与泛型编程:策略类模板

策略类模板 在前面的博文中&#xff0c;策略类SumPolicy和MinPolicy都是普通的类&#xff0c;其中包含的是一个静态成员函数模板algorithm()&#xff0c;该函数模板包含两个类型模板参数。其实&#xff0c;也可以把SumPolicy和MinPolicy类写成类模板—直接把algorithm()中的两…

【Linux】无法使用 ifconfig 查看系统网络接口信息,报错 command not found: ifconfig

问题描述 ifconfig是一个用于配置和显示系统网络接口信息的命令行工具。它通常用于Unix、Linux和其他类Unix系统中。 通过ifconfig命令&#xff0c;你可以查看和修改系统中网络接口的配置信息&#xff0c;包括IP地址、子网掩码、MAC地址、MTU&#xff08;最大传输单元&#x…

javacv踩坑记录

前一阵学习opencv&#xff0c;发现在做人脸识别的时候遇到一些类库不存在的情况&#xff0c;查找后发现是由于拓展包没有安装完全&#xff08;仅安装了基础版&#xff09;。由于网络的问题&#xff08;初步猜测&#xff09;&#xff0c;始终无法安装好拓展包。 于是另辟蹊径&am…

[文档级关系抽取|ACL论文]文档级关系抽取中语言理解的基础模型

Did the Models Understand Documents? Benchmarking Models for Language Understanding in Document-Level Relation Extraction School of Computer Science, Fudan University | ACL 2023.06 | 原文链接 Background 过去的工作大多数都是从单个句子中收获更多的关系&am…

MongoDB中的$type操作符和limit与skip方法

本文主要介绍MongoDB中的$type操作符和limit与skip方法。 目录 MongoDB的$type操作符MongoDB的limit方法MongoDB的skip方法 MongoDB的$type操作符 MongoDB中的$type操作符用于检查一个字段的类型是否与指定的类型相匹配。它可以用于查询和投影操作。 $type操作符可以与以下数…