基于顺序表实现通讯管理系统!(有完整源码!)

​​​​​​​

                                                                                个人主页:秋风起,再归来~

                                                                                文章专栏:C语言实战项目                              

                                                                        个人格言:悟已往之不谏,知来者犹可追

                                                                                        克心守己,律己则安!​​​​​​​

目录

1、实现思路

​编辑

2、各种接口的实现

2.1 初始化通讯录

2.2 添加通讯录数据

2.3 删除通讯录数据

2.4 展示通讯录数据

2.5 查找通讯录数据

2.6 修改通讯录数据

2.7 销毁通讯录数据

2.8 制作一个简易的菜单 

3、完整源码

SeqList.h

Contact.h

SeqList.c

Contact.c

test.c

4、 完结散花


1、实现思路

前言:在我之前的文章当中已经写过一篇关于如何实现顺序表的文章(点击这里),而这篇文章主要是讲解如何基于顺序表实现通讯管理系统,所以要看明白这篇文章的宝子们一定要先看完写的顺序表的文章哦~

1.1 首先我们知道顺序表的底层就是数组,而通讯录就是顺序表通过封装过后的产物~

所以我们可以说通讯录的底层其实就是顺序表啦~

1.2我们知道之前实现顺序表的时候,每个数组中存放的是内置类型int,而我们如果想要将各种联系人的数据存放并管理起来,那么我们就必须先自定义一个结构体类型来存放每个联系人的数据。然后将每个联系人的数据存放到数组中统计管理起来~

我们用宏定义来表示数组的大小方便以后的调整~(这些代码都是写在contact.h头文件当中)

#define NAME_MAX 20
#define GENDER_MAX 20
#define TELE_MAX 20
#define ADDR_MAX 200
//定义一个自定义类型来存放我们所要的联系人信息
typedef struct PersonInformation
{char name[NAME_MAX];//名字char gender[GENDER_MAX];//性别int age;//年龄char tele[TELE_MAX];//电话char addr[ADDR_MAX];//住址
}PeoInfo;

 ​​

1.3 我们知道顺序表是这样定义的~

//定义一个动态顺序表的结构体变量
typedef struct SeqList
{SLDataType* arr;size_t num;//记录有效数据的个数size_t capacity;//该顺序表的容量大小
}SL;//将该结构体类型重命名为SL

我们在顺序表的头文件当中引入Contact.h头文件(因为我们要将顺序表中的每个元素改成我们自定义是类型)

​​

1.4 接下来我们就让顺序表摇身一变成为通讯录!

//前置申明
typedef struct SeqList contact;

 这里我只是给顺序表重新取了一个名字(contact)!

因为头文件之间不可以互相包含,所以我们不可以将SeqList.h中的SL进行重命名,只能通过前置声明。

到这里我们就可以对通讯录进行各种接口的实现了!

Contact.h

#define _CRT_SECURE_NO_WARNINGS#pragma once
#define NAME_MAX 20
#define GENDER_MAX 20
#define TELE_MAX 20
#define ADDR_MAX 200//定义一个自定义类型来存放我们所要的联系人信息
typedef struct PersonInformation
{char name[NAME_MAX];//名字char gender[GENDER_MAX];//性别int age;//年龄char tele[TELE_MAX];//电话char addr[ADDR_MAX];//住址
}PeoInfo;//前置申明
typedef struct SeqList contact;//初始化通讯录
void InitContact(contact* con);//添加通讯录数据
void AddContact(contact* con);//删除通讯录数据
void DelContact(contact* con);//展示通讯录数据
void ShowContact(contact* con);//查找通讯录数据
void FindContact(contact* con);//修改通讯录数据
void ModifyContact(contact* con);//销毁通讯录数据
void DestroyContact(contact* con);

SeqList.h

#define _CRT_SECURE_NO_WARNINGS#pragma once//避免头文件的多次包含
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"Contact.h"//需要自定义的类型,所以引入contact头文件
typedef PeoInfo SLDataType;//便于类型的改动//定义一个动态顺序表的结构体变量
typedef struct SeqList
{SLDataType* arr;size_t num;//记录有效数据的个数size_t capacity;//该顺序表的容量大小
}SL;//将该结构体类型重命名为SL//加入增删查改接口//1. 顺序表初始化
void SeqListInit(SL* p);//2. 检查顺序表容量是否已满
void CheckSeqList(SL* p);//3. 顺序表的尾插
void SeqListPushBack(SL* p, SLDataType x);//4. 顺序表的尾删
void SeqListPopBack(SL* p);//5. 顺序表的头插
void SeqListPushFront(SL* p, SLDataType x);//6. 顺序表的头删
void SeqListPopFront(SL* p);//7. 顺序表在pos位置插入
void SeqListInsert(SL* p, size_t pos, SLDataType x);//8. 顺序表在pos位置删除
void SeqListErase(SL* p, size_t pos);//9. 顺序表的查找
int SeqListFind(SL* p, SLDataType x);//如果该数字存在则返回该数字的下标,否则返回-1//10 顺序表的销毁
void SeqListDestory(SL* p);//11. 顺序表的打印
void SeqListPrint(SL* p);

2、各种接口的实现

2.1 初始化通讯录

因为我们希望在初始化通讯录时可以将我们之前保存的数据加载到通讯中,所以我们可以通过文件操作将数据加载到通讯录当中~

//导入原文件中的数据
void DoadContact(contact* con)
{FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("open fail\n");return;}PeoInfo info = { 0 };while (fread(&info, sizeof(PeoInfo), 1, pf)){SeqListPushBack(con, info);}printf("历史数据导入成功!\n");fclose(pf);pf = NULL;
}

在初始化时,我们就可以调用顺序表中的初始化接口来实现通讯录的初始化 ,然后再导入原数据~

//初始化通讯录
void InitContact(contact* con)
{SeqListInit(con);DoadContact(con);
}

2.2 添加通讯录数据

添加数据,我们就是在尾插的基础上对顺序表进行封装(头插也可以)!

//添加通讯录数据
void AddContact(contact* con)
{PeoInfo p;printf("请输入您要添加的联系人的姓名!\n");scanf("%s", p.name);printf("请输入您要添加的联系人的性别!\n");scanf("%s", p.gender); printf("请输入您要添加的联系人的年龄!\n");scanf("%d", &(p.age));printf("请输入您要添加的联系人的电话!\n");scanf("%s", p.tele);printf("请输入您要添加的联系人的住址!\n");scanf("%s", p.addr);SeqListPushBack(con, p);printf("插入成功\n");
}

2.3 删除通讯录数据

这里我们通过名字来删除通讯录的数据!(当然我们也可以通过其他方式来删除数据)

//通过名字来查找通讯录中是否存在该联系人数据
int  FindByName(contact* con,char* name)
{for (int i = 0; i < con->num; i++){if (strcmp(con->arr[i].name, name) == 0){return i;//如果找到就返回他的下标}}return -1;//如果没找到返回一个无效的下标
}
//删除通讯录数据
void DelContact(contact* con)
{char name[NAME_MAX];printf("请输入您要删除的联系人的名字!\n");scanf("%s", name);int pos=FindByName(con, name);if (pos < 0){printf("您要删除的联系人不存在!\n");return;}//调用顺序表中的在指定位置删除数据的函数SeqListErase(con, pos);printf("删除成功!\n");
}

2.4 展示通讯录数据

//展示通讯录数据
void ShowContact(contact* con)
{printf("名字\t\t性别\t\t年龄\t\t电话\t\t\t住址\n");for (int i = 0; i < con->num; i++){printf("%s\t\t%s\t\t%d\t\t%s\t\t%s\n",con->arr[i].name,con->arr[i].gender,con->arr[i].age,con->arr[i].tele,con->arr[i].addr);}
}

2.5 查找通讯录数据

//查找通讯录数据
void FindContact(contact* con)
{char name[NAME_MAX];printf("请输入您要查找的联系人的名字!\n");scanf("%s", name);int pos = FindByName(con, name);if (pos < 0){printf("您要查找的联系人不存在!\n");return;}printf("名字\t性别\t年龄\t电话\t住址\n");printf("%s\t%s\t%d\t%s\t%s\t\n",con->arr[pos].name,con->arr[pos].gender,con->arr[pos].age,con->arr[pos].tele,con->arr[pos].addr);
}

2.6 修改通讯录数据

//修改通讯录数据
void ModifyContact(contact* con)
{char name[NAME_MAX];printf("请输入您要修改的联系人的名字!\n");scanf("%s", name);int pos = FindByName(con, name);if (pos < 0){printf("您要修改的联系人不存在!\n");return;}printf("请输入新的名字\n");scanf("%s", con->arr[pos].name);printf("请输入新的性别\n");scanf("%s", con->arr[pos].gender);printf("请输入新的年龄\n");scanf("%d", &con->arr[pos].age);printf("请输入新的电话\n");scanf("%s", con->arr[pos].tele);printf("请输入新的住址\n");scanf("%s", con->arr[pos].addr);printf("修改成功!\n");
}

2.7 销毁通讯录数据

在退出通讯录时我们希望将我们对通讯录进行的操作保存下来!

//将输入的数据保存到通讯录中
void SaveContact(contact* con)
{FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("open fail\n");return;}PeoInfo info = { 0 };for (int i = 0; i < con->num; i++){fwrite(con->arr + i, sizeof(PeoInfo), 1, pf);}printf("历史数据保存成功!\n");fclose(pf);pf = NULL;
}
//先保存数据到文件中再销毁通讯录数据
void DestroyContact(contact* con)
{SaveContact(con);//调用顺序表的销毁函数即可SeqListDestory(con);
}

2.8 制作一个简易的菜单 

#define _CRT_SECURE_NO_WARNINGS#include"SeqList.h"
#include"contact.h"void menu()
{printf("**********************************\n");printf("*****1、增加用户 2、删除用户  ****\n");printf("*****3、查找用户 4、修改用户  ****\n");printf("*****5、展示用户 0、退出通讯录****\n");printf("**********************************\n");
}int main()
{contact con = { 0 };InitContact(&con);int input = 0;do{menu();printf("请输入您的选择!\n");scanf("%d", &input);switch (input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:FindContact(&con);break;case 4:ModifyContact(&con);break;case 5:ShowContact(&con);break;case 0:printf("退出通讯录成功!\n");break;default:printf("输入错误,请重新选择!\n");break;}} while(input);DestroyContact(&con);return 0;
}

3、完整源码

SeqList.h

#define _CRT_SECURE_NO_WARNINGS#pragma once//避免头文件的多次包含
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"Contact.h"//需要自定义的类型,所以引入contact头文件
typedef PeoInfo SLDataType;//便于类型的改动//定义一个动态顺序表的结构体变量
typedef struct SeqList
{SLDataType* arr;size_t num;//记录有效数据的个数size_t capacity;//该顺序表的容量大小
}SL;//将该结构体类型重命名为SL//加入增删查改接口//1. 顺序表初始化
void SeqListInit(SL* p);//2. 检查顺序表容量是否已满
void CheckSeqList(SL* p);//3. 顺序表的尾插
void SeqListPushBack(SL* p, SLDataType x);//4. 顺序表的尾删
void SeqListPopBack(SL* p);//5. 顺序表的头插
void SeqListPushFront(SL* p, SLDataType x);//6. 顺序表的头删
void SeqListPopFront(SL* p);//7. 顺序表在pos位置插入
void SeqListInsert(SL* p, size_t pos, SLDataType x);//8. 顺序表在pos位置删除
void SeqListErase(SL* p, size_t pos);//9. 顺序表的查找
int SeqListFind(SL* p, SLDataType x);//如果该数字存在则返回该数字的下标,否则返回-1//10 顺序表的销毁
void SeqListDestory(SL* p);//11. 顺序表的打印
void SeqListPrint(SL* p);

Contact.h

#define _CRT_SECURE_NO_WARNINGS#pragma once
#define NAME_MAX 20
#define GENDER_MAX 20
#define TELE_MAX 20
#define ADDR_MAX 200//定义一个自定义类型来存放我们所要的联系人信息
typedef struct PersonInformation
{char name[NAME_MAX];//名字char gender[GENDER_MAX];//性别int age;//年龄char tele[TELE_MAX];//电话char addr[ADDR_MAX];//住址
}PeoInfo;//前置申明
typedef struct SeqList contact;//初始化通讯录
void InitContact(contact* con);//添加通讯录数据
void AddContact(contact* con);//删除通讯录数据
void DelContact(contact* con);//展示通讯录数据
void ShowContact(contact* con);//查找通讯录数据
void FindContact(contact* con);//修改通讯录数据
void ModifyContact(contact* con);//销毁通讯录数据
void DestroyContact(contact* con);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"
//1. 顺序表初始化
void SeqListInit(SL* p)
{assert(p);//判断指针的有效性p->arr = NULL;p->capacity = 0;p->num = 0;
}//2. 检查顺序表容量是否已满
void CheckSeqList(SL* p)
{assert(p);//判断指针的有效性if (p->num == p->capacity){size_t newcapacity = p->capacity == 0 ? p->capacity = 4 : p->capacity * 2;//如果原来没有空间,就给上4,有的话就扩大为原来的两倍SLDataType* ptr = (SLDataType*)realloc(p->arr, newcapacity * sizeof(SLDataType));//动态扩容if (ptr == NULL){perror("realloc fail;");return;}//也可以用assert断言一下p->arr = ptr;//开辟成功将地址传给arrp->capacity = newcapacity;//更新容量}
}//3. 顺序表的尾插
void SeqListPushBack(SL* p, SLDataType x)
{assert(p);//判断指针的有效性CheckSeqList(p);//尾插前先判断有没有容量或容量够不够p->arr[p->num] = x;//尾部插入数据p->num++;//有效数加一
}//4. 顺序表的尾删
void SeqListPopBack(SL* p)
{assert(p);//判断指针的有效性assert(p->num > 0);//断言存在有效数据p->num--;//尾删一个数据
}//5. 顺序表的头插
void SeqListPushFront(SL* p, SLDataType x)
{assert(p);//判断指针的有效性CheckSeqList(p);//先判断容量是否满了size_t end = p->num;while (end){p->arr[end] = p->arr[end - 1];//整体向后移动end--;}p->arr[0] = x;//头插p->num++;//有效数据加一
}//6. 顺序表的头删
void SeqListPopFront(SL* p)
{assert(p);//判断指针的有效性assert(p->num > 0);//有数据才删除size_t begin = 1;while (begin < p->num){p->arr[begin - 1] = p->arr[begin];//整体向前移动begin++;}p->num--;// 有效数据减一}//7. 顺序表在pos位置插入
void SeqListInsert(SL* p, size_t pos, SLDataType x)
{assert(p);//判断指针的有效性assert(pos >= 0 && pos < p->num);//pos必须小于num并且大于等于0CheckSeqList(p);//判断容量是否满了for (int i = p->num; i > pos - 1; i--){p->arr[i] = p->arr[i - 1];//将pos后面的元素往后挪}p->arr[pos - 1] = x;//在pos位置加入数据p->num++;//有效个数加一
}//8. 顺序表在pos位置删除
void SeqListErase(SL* p, size_t pos)
{assert(p);//判断指针的有效性assert(pos >= 0 && pos < p->num);//pos必须小于num并且大于等于0assert(p->num > 0);//有数据才能删除for (int i = pos; i < p->num-1; i++){p->arr[i] = p->arr[i+1];//将pos后面的元素往后挪}p->num--;//有效个数减一
}//9. 顺序表的查找
int SeqListFind(SL* p, SLDataType x)//如果该数字存在则返回该数字的下标,否则返回-1
{assert(p);//断言for (int i = 0; i < p->num; i++){if (p->arr[i] == x){return i;//查到返回下标}}return -1;//没有查到
}//10 顺序表的销毁
void SeqListDestory(SL* p)
{assert(p);//判断指针的有效性free(p->arr);//释放动态内存开辟的空间p->arr = NULL;p->capacity = 0;//容量置为0p->num = 0;//有效个数置为0
}//11. 顺序表的打印
void SeqListPrint(SL* p)
{assert(p);//判断指针的有效性if (p->num == 0){printf("顺序表为空!\n");return;}for (int i = 0; i < p->num; i++){printf("%d ", p->arr[i]);//打印数据}printf("\n");
}

Contact.c

#define _CRT_SECURE_NO_WARNINGS#include"SeqList.h"
#include"Contact.h"//导入原文件中的数据
void DoadContact(contact* con)
{FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("open fail\n");return;}PeoInfo info = { 0 };while (fread(&info, sizeof(PeoInfo), 1, pf)){SeqListPushBack(con, info);}printf("历史数据导入成功!\n");fclose(pf);pf = NULL;
}//初始化通讯录
void InitContact(contact* con)
{SeqListInit(con);DoadContact(con);
}//添加通讯录数据
void AddContact(contact* con)
{PeoInfo p;printf("请输入您要添加的联系人的姓名!\n");scanf("%s", p.name);printf("请输入您要添加的联系人的性别!\n");scanf("%s", p.gender); printf("请输入您要添加的联系人的年龄!\n");scanf("%d", &(p.age));printf("请输入您要添加的联系人的电话!\n");scanf("%s", p.tele);printf("请输入您要添加的联系人的住址!\n");scanf("%s", p.addr);SeqListPushBack(con, p);printf("插入成功\n");
}//通过名字来查找通讯录中是否存在该联系人数据
int  FindByName(contact* con,char* name)
{for (int i = 0; i < con->num; i++){if (strcmp(con->arr[i].name, name) == 0){return i;//如果找到就返回他的下标}}return -1;//如果没找到返回一个无效的下标
}//删除通讯录数据
void DelContact(contact* con)
{char name[NAME_MAX];printf("请输入您要删除的联系人的名字!\n");scanf("%s", name);int pos=FindByName(con, name);if (pos < 0){printf("您要删除的联系人不存在!\n");return;}//调用顺序表中的在指定位置删除数据的函数SeqListErase(con, pos);printf("删除成功!\n");
}//展示通讯录数据
void ShowContact(contact* con)
{printf("名字\t\t性别\t\t年龄\t\t电话\t\t\t住址\n");for (int i = 0; i < con->num; i++){printf("%s\t\t%s\t\t%d\t\t%s\t\t%s\n",con->arr[i].name,con->arr[i].gender,con->arr[i].age,con->arr[i].tele,con->arr[i].addr);}
}//查找通讯录数据
void FindContact(contact* con)
{char name[NAME_MAX];printf("请输入您要查找的联系人的名字!\n");scanf("%s", name);int pos = FindByName(con, name);if (pos < 0){printf("您要查找的联系人不存在!\n");return;}printf("名字\t性别\t年龄\t电话\t住址\n");printf("%s\t%s\t%d\t%s\t%s\t\n",con->arr[pos].name,con->arr[pos].gender,con->arr[pos].age,con->arr[pos].tele,con->arr[pos].addr);
}//修改通讯录数据
void ModifyContact(contact* con)
{char name[NAME_MAX];printf("请输入您要修改的联系人的名字!\n");scanf("%s", name);int pos = FindByName(con, name);if (pos < 0){printf("您要修改的联系人不存在!\n");return;}printf("请输入新的名字\n");scanf("%s", con->arr[pos].name);printf("请输入新的性别\n");scanf("%s", con->arr[pos].gender);printf("请输入新的年龄\n");scanf("%d", &con->arr[pos].age);printf("请输入新的电话\n");scanf("%s", con->arr[pos].tele);printf("请输入新的住址\n");scanf("%s", con->arr[pos].addr);printf("修改成功!\n");
}//将输入的数据保存到通讯录中
void SaveContact(contact* con)
{FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("open fail\n");return;}PeoInfo info = { 0 };for (int i = 0; i < con->num; i++){fwrite(con->arr + i, sizeof(PeoInfo), 1, pf);}printf("历史数据保存成功!\n");fclose(pf);pf = NULL;
}//先保存数据到文件中再销毁通讯录数据
void DestroyContact(contact* con)
{SaveContact(con);//调用顺序表的销毁函数即可SeqListDestory(con);
}

test.c

#define _CRT_SECURE_NO_WARNINGS#include"SeqList.h"
#include"contact.h"void menu()
{printf("**********************************\n");printf("*****1、增加用户 2、删除用户  ****\n");printf("*****3、查找用户 4、修改用户  ****\n");printf("*****5、展示用户 0、退出通讯录****\n");printf("**********************************\n");
}int main()
{contact con = { 0 };InitContact(&con);int input = 0;do{menu();printf("请输入您的选择!\n");scanf("%d", &input);switch (input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:FindContact(&con);break;case 4:ModifyContact(&con);break;case 5:ShowContact(&con);break;case 0:printf("退出通讯录成功!\n");break;default:printf("输入错误,请重新选择!\n");break;}} while(input);DestroyContact(&con);return 0;
}

4、 完结散花

好了,这期的分享到这里就结束了~

如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~

如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~

我们下期不见不散~~

​​​​

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

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

相关文章

OCm (Radeon Open Compute) 和 CUDA (Compute Unified Device Architecture)

OCm&#xff08;Radeon Open Compute&#xff09;和CUDA&#xff08;Compute Unified Device Architecture&#xff09;是两种旨在利用图形处理单元&#xff08;GPU&#xff09;进行通用计算的技术和框架。 OCm&#xff08;Radeon Open Compute&#xff09;&#xff1a; OCm&…

CentOS 7 下离线安装RabbitMQ教程

CentOS 7 下安装RabbitMQ教程一、做准备&#xff08;VMWare 虚拟机上的 CentOS 7 镜像 上安装的&#xff09; &#xff08;1&#xff09;准备RabbitMQ的安装包&#xff08;rabbitmq-server-3.8.5-1.el7.noarch&#xff09;下载地址mq https://github.com/rabbitmq/rabbitmq-se…

os.listdir()bug总结

今天测试出一个神奇的bug&#xff0c;算是教训吧&#xff0c;找了两天不知道问题在哪&#xff0c;最后才发现问题出现在这 原始文件夹显示 os.listdir()结果乱序 import os base_path "./file/"files os.listdir(base_path)print(files)问题原因 解决办法(排序)

NB-IOT 介绍 1

1 名称介绍 NB-----Narrow Band IOT -----Internet of things NB-IOT---窄带物联网 2 物联网技术发展 以太网&#xff1a;网线 RS232一种串行通信标准&#xff0c;通常采用正负电压来表示逻辑值&#xff0c;如正电压表示逻辑1&#xff0c;负电压表示逻辑0。 RS485一种串行通…

(学习日记)2024.04.06:UCOSIII第三十四节:互斥量函数接口讲解

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

【二分查找】Leetcode 二分查找

题目解析 二分查找在数组有序可以使用&#xff0c;也可以在数组无序的时候使用&#xff08;只要数组中的一些规律适用于二分即可&#xff09; 704. 二分查找 算法讲解 当left > right的时候&#xff0c;我们循环结束&#xff0c;但是当left和right缩成一个点的时候&#x…

大数据分析与内存计算——Spark安装以及Hadoop操作——注意事项

一、Spark安装 1.相关链接 Spark安装和编程实践&#xff08;Spark3.4.0&#xff09;_厦大数据库实验室博客 (xmu.edu.cn) 2.安装Spark&#xff08;Local模式&#xff09; 按照文章中的步骤安装即可 遇到问题&#xff1a;xshell以及xftp不能使用 解决办法&#xff1a; 在…

Node.js------Express

◆ 能够使用 express.static( ) 快速托管静态资源◆ 能够使用 express 路由精简项目结构◆ 能够使用常见的 express 中间件◆ 能够使用 express 创建API接口◆ 能够在 express 中启用cors跨域资源共享 一.初识Express 1.Express 简介 官方给出的概念&#xff1a;Express 是基…

AcWing 312. 乌龟棋(每日一题)

原题链接&#xff1a;312. 乌龟棋 - AcWing题库 小明过生日的时候&#xff0c;爸爸送给他一副乌龟棋当作礼物。 乌龟棋的棋盘只有一行&#xff0c;该行有 N 个格子&#xff0c;每个格子上一个分数&#xff08;非负整数&#xff09;。 棋盘第 1 格是唯一的起点&#xff0c;第…

LC 222.完全二叉树的节点个数

222. 完全二叉树的节点个数 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中…

解决沁恒ch592单片机在tmos中使用USB总线时,接入USB Hub无法枚举频繁Reset的问题

开发产品时采用了沁恒ch592&#xff0c;做USB开发时遇到了一个奇葩的无法枚举问题。 典型症状 使用USB线直连电脑时没有问题&#xff0c;可以正常使用。 如果接入某些特定方案的USB Hub&#xff08;例如GL3510、GL3520&#xff09;&#xff0c;可能会出现以下2种情况&#xf…

2024年第八届人工智能与虚拟现实国际会议(AIVR 2024)即将召开!

2024年第八届人工智能与虚拟现实国际会议&#xff08;AIVR 2024&#xff09;将2024年7月19-21日在日本福冈举行。人工智能与虚拟现实的发展对推动科技进步、促进经济发展、提升人类生活质量等具有重要意义。AIVR 2024将携手各专家学者&#xff0c;共同挖掘智能与虚拟的无限可能…

【C++初阶】 vector 在OJ中的使用

前言&#xff1a; &#x1f3af;个人博客&#xff1a;Dream_Chaser &#x1f388;博客专栏&#xff1a;C &#x1f4da;本篇内容&#xff1a;只出现一次的数字 和 杨辉三角 OJ 目录 一、只出现一次的数字 题目描述&#xff1a; 二、杨辉三角OJ 题目描述&#xff1a; 一、只…

AI设计优化电机、电路与芯片?

一、AI进行电机本体设计 使用AI进行电机本体设计是一种前沿且具有潜力的方法&#xff0c;通过深度学习、强化学习、遗传算法等AI技术&#xff0c;可以实现电机设计的自动化和优化。具体应用可以包括以下几个方面&#xff1a; 此图片来源于网络 1. **参数优化**&#xff1a; …

docker + miniconda + python 环境安装与迁移(详细版)

本文主要列出从安装dockerpython环境到迁移环境的整体步骤。windows与linux之间进行测试。 简化版可以参考&#xff1a;docker miniconda python 环境安装与迁移&#xff08;简化版&#xff09;-CSDN博客 目录 一、docker 安装和测试 二、docker中拉取miniconda&#xff…

vscode 连接远程服务器 服务器无法上网 离线配置 .vscode-server

离线配置 vscode 连接远程服务器 .vscode-server 1. .vscode-server下载 使用vscode连接远程服务器时会自动下载配置.vscode-server文件夹&#xff0c;如果远程服务器无法联网&#xff0c;则需要手动下载 1&#xff09;网址&#xff1a;https://update.code.visualstudio.com…

ICP备案工信部短信核验怎么看是否成功?

备案短信核验怎么看是否成功&#xff1f;在工信部官网输入6位短信验证码、手机号和身份证号后&#xff0c;点击提交&#xff0c;会返回尊敬的ICP用户&#xff1a; 您的短信核验已全部完成,该请求将提交管局审核。如下图&#xff1a; 尊敬的ICP用户&#xff1a; 您的短信核验已全…

ArcGis研究区边界提取

ArcGis研究区边界提取 *0* 引言*1* 有的步骤0 引言 GRACE数据处理前要先确定研究范围,而大多情况下所选的研究区都是有特殊意义的,比如常年干旱、经济特区、降水丰富等,这些区域往往有精确的边界,那就要从大的区块中将研究范围抠出来,获取相应坐标,以量化区域重力变化。那…

蓝桥集训之斐波那契数列

蓝桥集训之斐波那契数列 核心思想&#xff1a;矩阵乘法 将原本O(n)的递推算法优化为O(log2n) 构造1x2矩阵f和2x2矩阵a 发现f(n1) f(n) * a 则f(n1) f(1) * an可以用快速幂优化 #include <iostream>#include <cstring>#include <algorithm>using na…

白嫖 kimi.ai 的 API 接口,给这个开源项目点赞!

Kimi 是当前国内相当火爆的 AI 产品&#xff0c;输出结果和使用体验都非常不错。 Kimi 开放了 API 接口&#xff0c;新用户注册后会免费赠送 15 元额度。 Kimi API 的网址&#xff1a; platform.moonshot.cn/console 这是光明正大的白嫖方式&#xff0c;一定不要错过哦。 如…