基于顺序表实现的可存储性通讯录!!!

基于顺序表实现的通讯录

    • 通讯录的基本功能
  • 顺序表
    • 顺序表的部分变量修改
      • 修改处一
      • 修改处二
      • 修改处三
  • 头文件 Contact.h
    • 通讯录自定义结构体
  • 功能实现 源文件 Contact.c
      • 读取文件中联系人的信息 void ContactReadFile(contact* pcon)
      • 保存到文件 void ContactSave(contact* pcon)
    • 测试文件的保存与读取
      • 初始化 void ContactInit(contact* pcon)
      • 销毁当前联系人信息 void ContactDestroy(contact* pcon)
      • 添加联系人 void ContactAdd(contact* pcon)
      • 删除联系人 void ContactDel(contact* pcon)
      • 展示单个人物信息 void ContactSpecifyShow(contact* pcon, unsigned int pos)
      • 展示所有联系人信息 void ContactShow(contact* pcon)
    • 测试添加与删除联系人
      • 查找联系人 void ContactFind(contact* pcon)
      • 更改通讯录信息 void ContactChange(contact* pcon)
    • 测试查找与更改联系人信息
  • 逻辑实现 源文件 test.c
      • 界面菜单 void menu(void)
      • 主体逻辑 void test_contact(void)
  • 结语
  • 源代码
    • Contact.c
    • test.c
    • SeqList.h
    • SeqList.h

通讯录的基本功能

通讯录是用来存储联系人的基本信息,同时也具备对联系人基本信息的添加,删除,修改,查询,显示信息的功能,可以辅助使用者在日常生活中的信息记忆等等。
而存储的信息我们也可以根据自己的需求来设计,这里我们就拿联系人的基本信息:姓名,电话号码,爱好,因她而存在的故事 来举例。

顺序表

这里我们要使用上一期所讲到的顺列表来辅助实现,(不懂的友友们可以先看看上一期顺序表的实现)链接:顺序表的实现。
注意:一定要了解上期顺序表的实现,因为本期通讯录是基于上期顺序表所实现的。

顺序表的部分变量修改

因为通讯录是使用结构体类型,而我们上一期所用到的是 整型变量 所测试的,所以我们在这里要进行部分变量的修改,修改如下:

修改处一

//SeqList.h
#define SLDataType CInfo
bool SLFind(SL* ps, char* x);
int SLFindPos(SL* ps, char* x);

这里将之前的int改为CInfoCInfo是后续我们要实现的结构体,并将SLFind函数与SLFindPos函数 的第二个参数的变量改为char*类型的变量,因为我们通讯录使用结构体为数组元素单位,后续也要用char*类型来存储名字,所以需要改变。

修改处二

//SeqList.c

需要修改的两个函数如下:
在这里插入图片描述
在查找名字的时候,我们传的是字符串指针,需要断言,并且利用strcmp(str1,str2)库函数来比较,两个字符串是否相同,相同则返回0,不同则返回非0

修改处三

//SeqList.c

如下图:
在这里插入图片描述
之前用到的打印顺序表元素的函数现阶段也不适用于结构体,所以要注释掉,之后我们会重新编写通讯录的打印函数。

这也是为了后续查找联系人做准备

头文件 Contact.h

#pragma once#define NAME_MAX 20
#define PHONE_NUMBER_MAX 30
#define HOBBY_MAX 500
#define STORY_MAX 3000typedef struct ContactInfo
{char name[NAME_MAX];char Phone_number[PHONE_NUMBER_MAX];char hobby[HOBBY_MAX];char Story[STORY_MAX];
}CInfo;typedef struct SeqList contact;void ContactReadFile(contact* pcon);//读取文件中联系人的信息void ContactInit(contact* pcon);//初始化void ContactDestroy(contact* pcon);//销毁void ContactShow(contact* pcon);//展示所有联系人信息void ContactAdd(contact* pcon);//添加联系人void ContactDel(contact* pcon);//删除联系人void ContactFind(contact* pcon);//查找联系人void ContactSpecifyShow(contact* pcon, unsigned int pos);//展示单个人物信息void ContactSave(contact* pcon);//保存到文件void ContactChange(contact* pcon);//更改通讯录信息

因为这里要实现的是通讯录,所以我们需要的顺列表的结构体重命名:typedef struct SeqList contact; ,这是因为修改后写成Contact更符合整体风格也更方便阅读

通讯录自定义结构体

#define NAME_MAX 20
#define PHONE_NUMBER_MAX 30
#define HOBBY_MAX 500
#define STORY_MAX 3000typedef struct ContactInfo
{char name[NAME_MAX];char Phone_number[PHONE_NUMBER_MAX];char hobby[HOBBY_MAX];char Story[STORY_MAX];
}CInfo;

为了满足多样化的输入,我这里使用都是字符类型的数组,其依次表示:姓名,电话号码,爱好,因她而存在的故事 ,这里数组的空间大小我们也用#define 宏定义修改方便后续修改。

功能实现 源文件 Contact.c

读取文件中联系人的信息 void ContactReadFile(contact* pcon)

void ContactReadFile(contact* pcon)
{CInfo s = { 0 };FILE* pf = fopen("Contact.txt", "r");if (pf == NULL){FILE* pw = fopen("Contact.txt", "w+");assert(pw);fprintf(pw, "%d\n", 0);fclose(pw);pw = NULL;pf = fopen("Contact.txt", "r");}int i = 0;fscanf(pf, "%d", &i);while (i--){fscanf(pf, "%s %s %s %s", &(s.name), &(s.Phone_number), &(s.hobby), &(s.Story));SLPushBack(pcon, s);}fclose(pf);pf = NULL;
}
	FILE* pf = fopen("Contact.txt", "r");

以只读模式创建一个文件指针来读取"Contact.txt",当然在第一次使用的时候,我们的程序文件夹在电脑磁盘中是没有这个文件的,所以fopen会返回一个空指针NULL,所以我们要对pf进行一个判断,若pf为空,我们就要创建一个文件指针pw用"w+"读写模式创建一个文本文件,然后再用pf重新读取。

目前,我们已经成功打开了**“Contact.txt”,我们现在要开始读取文件,如何读取文件呢?这里我们使用了fscanf()函数来进行读取,每次同时读取联系人的名字、电话号、爱好,故事**,再利用while循环来限制读取次数。

那么这个限制次数是多少呢?我们在第一次创建文件时,细节的输入了一个0,这就说明了这个文件中并没有一个联系人的数据,但是如果说我们不是第一次使用,那限制次数又该如何计算呢?

	int i = 0;fscanf(pf, "%d", &i);

每当我们进入while循环中,限制次数就是我们在文件第一行读取到的数字,而保存这个数的任务,这就要看我们的下一个函数了。

保存到文件 void ContactSave(contact* pcon)

void ContactSave(contact* pcon)
{FILE* pw = fopen("Contact.txt", "w");assert(pw);fprintf(pw, "%d\n", pcon->size);for (int i = 0; i < pcon->size; i++){fprintf(pw, "%s\n%s\n%s\n%s\n",pcon->arr[i].name, pcon->arr[i].Phone_number,pcon->arr[i].hobby, pcon->arr[i].Story);}fclose(pw);pw = NULL;
}
	fprintf(pw, "%d\n", pcon->size);

在保存文件时,我们第一行保存通讯录的有效联系人个数,这也是方便ContactSave函数保存。

	fprintf(pw, "%s\n%s\n%s\n%s\n",pcon->arr[i].name, pcon->arr[i].Phone_number,pcon->arr[i].hobby, pcon->arr[i].Story);

利用for循环将数位联系人的信息保存在文件中,然后再关闭文件即可。

测试文件的保存与读取

目前,我们存放程序的文件夹是没有"Contact.txt"文本文件的,下面让我们运行来看一下吧。
在这里插入图片描述
我们可以看到在文件夹中多出了一个"Contact.txt"文本文件,并且通过文件预览我们也可看到程序成功将信息保存在了文本中,程序的返回值也为0,所以可以说明代码没问题
在这里插入图片描述

初始化 void ContactInit(contact* pcon)

void ContactInit(contact* pcon)
{SLInit(pcon);ContactReadFile(pcon);
}

基于以上代码,这里通讯录初始化的实现,只要先调用SLInit(pcon)函数让顺序表初始化,再调用ContactReadFile(pcon)函数读取磁盘中所存储文件即可。

销毁当前联系人信息 void ContactDestroy(contact* pcon)

void ContactDestroy(contact* pcon)
{SLDestroy(pcon);
}

同理,销毁当前联系人信息就相当于销毁顺序表。

添加联系人 void ContactAdd(contact* pcon)

void ContactAdd(contact* pcon)
{CInfo info;printf("请输入姓名:");scanf("%s", info.name);printf("请输入电话号码:");scanf("%s", &info.Phone_number);printf("请输入爱好:");scanf("%s", info.hobby);printf("请输入与他一起的趣事:");scanf("%s", info.Story);SLPushBack(pcon, info);
}

先创建一个临时变量info,通过scanf函数来输入数据,再将info尾插到顺序表即可实现。

删除联系人 void ContactDel(contact* pcon)

void ContactDel(contact* pcon)
{assert(pcon);printf("输入你要删除的联系人:");char x[NAME_MAX] = { 0 };scanf("%s", x);int ret = SLFindPos(pcon, x);if (ret >= 0){SLErase(pcon, ret);printf("删除成功!\n");}else{printf("不存在该联系人\n");}
}

先利用scanf函数输入联系人姓名的信息x,再利用顺序表中的SLFindPos(pcon, x)函数来查找姓名的位置,若返回大于0的值说明x存在,此时就用SLErase(pcon, ret)函数再顺序表中进行删除;若为-1,这说明该联系人x根本不存在。

展示单个人物信息 void ContactSpecifyShow(contact* pcon, unsigned int pos)

void ContactSpecifyShow(contact* pcon, unsigned int pos)
{printf("\n姓名:%s\n电话号码:%s\n爱好:%s\nThe story that exists because of her:\n%s\n",pcon->arr[pos].name,pcon->arr[pos].Phone_number,pcon->arr[pos].hobby,pcon->arr[pos].Story);
}

通过传入顺序表的地址与数组下标来确定联系人的位置,再依次打印数据即可。
PS:在展示联系人与使用者所产生的故事的时候,考虑到字数可能较多影响美观,所以这里在he story that exists because of her:后面进行了换行。

展示所有联系人信息 void ContactShow(contact* pcon)

void ContactShow(contact* pcon)
{for (int i = 0; i < pcon->size; i++){ContactSpecifyShow(pcon, i);}
}

利用for循环遍历顺序表利用ContactSpecifyShow(pcon, i)函数进行逐个打印。

测试添加与删除联系人

#include"SeqList.h"
//测试添加与删除联系人
int main() 
{contact con;ContactInit(&con);printf("输入_1:\n");ContactAdd(&con);printf("\n输入_2:\n");ContactAdd(&con);ContactShow(&con);printf("\n删除_1\n");ContactDel(&con);ContactShow(&con);ContactDestroy(&con);return 0;
}

(PS:为了更清晰的表达本次实验,这里删除了上一次测试所保留的"Contact.txt"文件)
先进行两次输入,然后展示通讯录,再删除原神,再展示通讯录。运行结果如下:
请添加图片描述

查找联系人 void ContactFind(contact* pcon)

void ContactFind(contact* pcon)
{assert(pcon);printf("输入你要查找的联系人:");char x[NAME_MAX] = { 0 };scanf("%s", x);int ret = SLFindPos(pcon, x);if (ret >= 0){ContactSpecifyShow(pcon, ret);}else{printf("不存在该联系人\n");}
}

这里也是基于顺序表,先判断输入的名字x是否存在,存在则单独打印该联系人信息,反之告知不存在。

更改通讯录信息 void ContactChange(contact* pcon)

void ContactChange(contact* pcon)
{char str[NAME_MAX] = { 0 };printf("输入你要更改的该联系人:");scanf("%s", str);int ret = SLFindPos(pcon , str);if (ret < 0){printf("不存在该联系人");return 0;}CInfo info;printf("请输入更正后的姓名:");scanf("%s", info.name);printf("请输入更正后的电话号码:");scanf("%s", &info.Phone_number);printf("请输入更正后的爱好:");scanf("%s", info.hobby);printf("请输入更正后的故事:");scanf("%s", info.Story);SLErase(pcon, ret);SLInsert(pcon, ret, info);}

基于顺序表SLFindPos(pcon , str)函数,先判断要更改人的姓名,是否存在于通讯录,若存在,则让用户输入修改信息,然后先调用SLErase(pcon, ret)函数将该位置的原数据删除,再调用SLInsert(pcon, ret, info)函数对该位置进行添加;反之告知不存在联系人并退出函数。

测试查找与更改联系人信息

先添加三个联系人a,b,c ,再查找已存在的a与·不存在的d,再更改联系人ad,再查找ad,根据逻辑程序运行结果符合预期。
请添加图片描述

逻辑实现 源文件 test.c

界面菜单 void menu(void)

void menu()
{printf("+-------------------------------------------------------+\n");printf("|         欢迎来到月下的依靠-----志昂的通讯录           |\n");printf("|                  请选择你的操作:                      |\n");printf("|          1.ContactInit    初始化备忘录                |\n");printf("|          2.ContactAdd     添加联系人信息              |\n");printf("|          3.ContactDel     删除联系人信息              |\n");printf("|          4.ContactShow    展示联系人信息              |\n");printf("|          5.ContactFind    查找联系人信息              |\n");printf("|          6.ContactSave    保存至文件中                |\n");printf("|          7.ContactChange  更改联系人信息              |\n");printf("|          8.ContactDestroy 销毁当前联系人信息          |\n");printf("|          9.ClearScreen    清除屏幕                    |\n");printf("|          0.CloseProgram   退出程序                    |\n");printf("+-------------------------------------------------------+\n");
}

这里的菜单只要表达的内容可以让使用者知道如何操作即可。

主体逻辑 void test_contact(void)

void test_contact()
{contact con;ContactInit(&con);void (*p[9])(contact * pcon) = { 0,ContactInit, ContactAdd ,ContactDel, ContactShow ,ContactFind, ContactSave, ContactChange ,ContactDestroy};menu();int choose = 0;printf("请输入指令:");while (scanf("%d", &choose), choose != 0){switch (choose){case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:(*p[choose])(&con);break;case 9:system("cls");menu();break;default:printf("请正确输入!!!!\n");break;}printf("请输入指令:");}ContactDestroy(&con);
}
	void (*p[9])(contact * pcon) = { 0,ContactInit, ContactAdd ,ContactDel, ContactShow ,ContactFind, ContactSave, 	ContactChange ,ContactDestroy};

利用函数指针数组存放函数指针,使得输入的数字可以轻松调用函数地址来使用。
当输入值为1~8时,进入到函数指针数组进行调用;
当输入9就利用system()调用控制台指令"cls"来清空屏幕,并重新打印菜单;
当输入为0时,break跳出循环并销毁顺序表所存储的通讯录;
否则就要求使用者重新输入。

结语

到此基于顺序表和文件操作所实现的通讯录就实现了,本期的内容到这里就全部结束了,谢谢大家的观看。
那么,喜欢请多多关注吧。

请添加图片描述

画师:.com
投稿时间:2023年02月03日23:01
作品lD: 105059867
画师ID: 3889453 

源代码

所有源代码如下:

Contact.c

#include"SeqList.h"void ContactReadFile(contact* pcon)
{CInfo s = { 0 };FILE* pf = fopen("Contact.txt", "r");if (pf == NULL){FILE* pw = fopen("Contact.txt", "w+");assert(pw);fprintf(pw, "%d\n", 0);fclose(pw);pw = NULL;pf = fopen("Contact.txt", "r");}//读文件int i = 0;fscanf(pf, "%d", &i);while (i--){fscanf(pf, "%s %s %s %s", &(s.name), &(s.Phone_number), &(s.hobby), &(s.Story));SLPushBack(pcon, s);}fclose(pf);pf = NULL;}void ContactSpecifyShow(contact* pcon, unsigned int pos)
{printf("\n姓名:%s\n电话号码:%s\n爱好:%s\nThe story that exists because of her:\n%s\n",pcon->arr[pos].name,pcon->arr[pos].Phone_number,pcon->arr[pos].hobby,pcon->arr[pos].Story);
}void ContactInit(contact* pcon)
{SLInit(pcon);ContactReadFile(pcon);
}void ContactDestroy(contact* pcon)
{SLDestroy(pcon);
}void ContactAdd(contact* pcon)
{CInfo info;printf("请输入姓名:");scanf("%s", info.name);printf("请输入电话号码:");scanf("%s", &info.Phone_number);printf("请输入爱好:");scanf("%s", info.hobby);printf("请输入与他一起的趣事:");scanf("%s", info.Story);SLPushBack(pcon, info);
}void ContactShow(contact* pcon)
{for (int i = 0; i < pcon->size; i++){ContactSpecifyShow(pcon, i);}
}void ContactFind(contact* pcon)
{assert(pcon);printf("输入你要查找的联系人:");char x[NAME_MAX] = { 0 };scanf("%s", x);int ret = SLFindPos(pcon, x);if (ret >= 0){ContactSpecifyShow(pcon, ret);}else{printf("不存在该联系人\n");}
}void ContactDel(contact* pcon)
{assert(pcon);printf("输入你要删除的联系人:");char x[NAME_MAX] = { 0 };scanf("%s", x);int ret = SLFindPos(pcon, x);if (ret >= 0){SLErase(pcon, ret);printf("删除成功!\n");}else{printf("不存在该联系人\n");}
}void ContactSave(contact* pcon)
{FILE* pw = fopen("Contact.txt", "w");assert(pw);fprintf(pw, "%d\n", pcon->size);for (int i = 0; i < pcon->size; i++){fprintf(pw, "%s\n%s\n%s\n%s\n",pcon->arr[i].name, pcon->arr[i].Phone_number,pcon->arr[i].hobby, pcon->arr[i].Story);}fclose(pw);pw = NULL;}void ContactChange(contact* pcon)
{char str[NAME_MAX] = { 0 };printf("输入你要更改的该联系人:");scanf("%s", str);int ret = SLFindPos(pcon , str);if (ret < 0){printf("不存在该联系人");return 0;}CInfo info;printf("请输入更正后的姓名:");scanf("%s", info.name);printf("请输入更正后的电话号码:");scanf("%s", &info.Phone_number);printf("请输入更正后的爱好:");scanf("%s", info.hobby);printf("请输入更正后的故事:");scanf("%s", info.Story);SLErase(pcon, ret);SLInsert(pcon, ret, info);
}

test.c

#include"SeqList.h"void menu()
{printf("+-------------------------------------------------------+\n");printf("|         欢迎来到月下的依靠-----志昂的通讯录           |\n");printf("|                  请选择你的操作:                      |\n");printf("|          1.ContactInit    初始化备忘录                |\n");printf("|          2.ContactAdd     添加联系人信息              |\n");printf("|          3.ContactDel     删除联系人信息              |\n");printf("|          4.ContactShow    展示联系人信息              |\n");printf("|          5.ContactFind    查找联系人信息              |\n");printf("|          6.ContactSave    保存至文件中                |\n");printf("|          7.ContactChange  更改联系人信息              |\n");printf("|          8.ContactDestroy 销毁当前联系人信息          |\n");printf("|          9.ClearScreen    清除屏幕                    |\n");printf("|          0.CloseProgram   退出程序                    |\n");printf("+-------------------------------------------------------+\n");
}void test_contact()
{contact con;ContactInit(&con);void (*p[9])(contact * pcon) = { 0,ContactInit, ContactAdd ,ContactDel, ContactShow ,ContactFind, ContactSave, ContactChange ,ContactDestroy};menu();int choose = 0;printf("请输入指令:");while (scanf("%d", &choose), choose != 0){switch (choose){case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:(*p[choose])(&con);break;case 9:system("cls");menu();break;default:printf("请正确输入!!!!\n");break;}printf("请输入指令:");}ContactDestroy(&con);
}int main()
{test_contact();//ContactReadFile();//test_1();return 0;
}

SeqList.h

#include"SeqList.h"void SLInit(SL* ps)
{ps->arr = NULL;ps->capacity = ps->size = 0;
}void SLDestroy(SL* ps)
{if (ps->arr)free(ps->arr);ps->arr = NULL;ps->capacity = ps->size = 0;
}void SLCheckCapacity(SL* ps)
{if (ps->capacity == ps->size){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));assert(tmp);ps->arr = tmp;tmp = NULL;ps->capacity = newcapacity;}
}void SLPushBack(SL* ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);ps->arr[ps->size++] = x;}void SLPushFront(SL* ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);int i = 0;for (i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];}ps->size++;ps->arr[0] = x;
}//void SLPrint(SL* ps)
//{
//	int i = 0;
//	for (i = 0; i < ps->size; i++)
//	{
//		printf("%d ", ps->arr[i]);
//	}
//	printf("\n");
//}void SLPopBack(SL* ps)
{assert(ps);assert(!SLIsEmpty(ps));ps->size--;
}void SLPopFront(SL* ps)
{assert(ps);assert(!SLIsEmpty(ps));int i = 0;for (i = 0; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}bool SLIsEmpty(SL* ps)
{assert(ps);return (ps->size == 0);
}void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);SLCheckCapacity(ps);if (pos < 0 || pos > ps->size){printf("输入错误!!!");return;}for (int i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}void SLErase(SL* ps, int pos)
{assert(ps);assert(!SLIsEmpty(ps));for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;}bool SLFind(SL* ps, char* x)
{assert(ps&&x);for (int i = 0; i < ps->size; i++){if(0 == strcmp(ps->arr[i].name,x))return true;}return false;
}int SLFindPos(SL* ps, char* x)
{assert(ps&&x);for (int i = 0; i < ps->size; i++){if(0 == strcmp(ps->arr[i].name, x))return i;}return -1;
}void SLRevise(SL* ps, int pos, SLDataType x)
{assert(ps);if (pos >= ps->size && ps < 0){printf("输入错误,无法修改\n");return;}ps->arr[pos] = x;
}

SeqList.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1#include"Contact.h"#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>#define SLDataType CInfotypedef struct SeqList
{SLDataType* arr;int size;int capacity;
}SL;void SLInit(SL* ps);
void SLDestroy(SL* ps);void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
void SLPopBack(SL* ps);void SLErase(SL* ps, int pos);
void SLInsert(SL* ps, int pos, SLDataType x);
bool SLFind(SL* ps, char* x);
int SLFindPos(SL* ps, char* x);
void SLRevise(SL* ps, int pos, SLDataType x);//void SLPrint(SL* ps);
bool SLIsEmpty(SL* ps);

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

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

相关文章

高德地图撒点组件

一、引入amap地图库 - public/index.html <script type"text/javascript">window._AMapSecurityConfig {securityJsCode: 地图密钥 }</script><scripttype"text/javascript"src"https://webapi.amap.com/maps?v1.4.8&key111111…

基于单片机的智能鱼缸控制系统的设计与实现

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、开发技术和原理的相关知识2.1开发设计目标2.2 开发设计使用技术和原理2.2.1嵌入式技术2.2.2传感器技术 二、基于单片机的智能鱼缸控制系统的总体设计3.1智能鱼缸控制系统的基本组成3.1.1系统的构成部分3.2需求…

【生物信息学】单细胞RNA测序数据分析:计算亲和力矩阵(基于距离、皮尔逊相关系数)及绘制热图(Heatmap)

文章目录 一、实验介绍二、实验环境1. 配置虚拟环境2. 库版本介绍 三、实验内容0. 导入必要的库1. 读取数据集2. 质量控制&#xff08;可选&#xff09;3. 基于距离的亲和力矩阵4. 绘制基因表达的Heatmap5. 基于皮尔逊相关系数的亲和力矩阵6. 代码整合 一、实验介绍 计算亲和力…

【ElasticSearch系列-04】ElasticSearch的聚合查询操作

ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【三】ElasticSearch的高级查询Quer…

动态路由协议OSPF项目部署(二)

1. 静态和动态路由的区别&#xff1b; 2. OSPF协议通信过程与部署&#xff1b; 3. OSPF协议在项目上的应用场景 - OSPF - 开放式最短路径优先 - 一个动态路由协议 - 路由器转发数据 - 路由器需要一张地图 - 路由表 - 路由表如何构建的&#xff1f; - 依靠手动 或…

python脚本监听域名证书过期时间,并将通知消息到钉钉

版本一&#xff1a; 执行脚本带上 --dingtalk-webhook和–domains后指定钉钉token和域名 python3 ssl_spirtime.py --dingtalk-webhook https://oapi.dingtalk.com/robot/send?access_tokenavd345324 --domains www.abc1.com www.abc2.com www.abc3.com脚本如下 #!/usr/bin…

面试算法53:二叉搜索树的下一个节点

题目 给定一棵二叉搜索树和它的一个节点p&#xff0c;请找出按中序遍历的顺序该节点p的下一个节点。假设二叉搜索树中节点的值都是唯一的。例如&#xff0c;在图8.9的二叉搜索树中&#xff0c;节点8的下一个节点是节点9&#xff0c;节点11的下一个节点是null。 分析&#xf…

Qt封装的Halcon显示控件,支持ROI绘制

前言 目前机器视觉ROI交互控件在C#上做的比较多&#xff0c;而Qt上做的比较少&#xff0c;根据作者 VSQtHalcon——显示图片&#xff0c;实现鼠标缩放、移动图片的文章&#xff0c;我在显示和移动控件的基础上&#xff0c;增加了ROI设置功能&#xff0c;并封装成了一个独立的Q…

领星ERP如何无需API开发轻松连接OA、电商、营销、CRM、用户运营、推广、客服等近千款系统

领星ERP&#xff08;LINGXING&#xff09;是一款专业的一站式亚马逊管理系统&#xff0c;帮助卖家构建完整的数据化运营闭环。&#xff0c;致力于为跨境电商卖家提供精细化运营和业财一体化的解决方案。 官网&#xff1a;https://erp.lingxing.com 集简云无代码集成平台&…

轻量封装WebGPU渲染系统示例<13>- 屏幕空间后处理效果(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/main/src/voxgpu/sample/ScreenPostEffect.ts 此示例渲染系统实现的特性: 1. 用户态与系统态隔离。 细节请见&#xff1a;引擎系统设计思路 - 用户态与系统态隔离-CSDN博客 2. 高频调用与低频调用隔离。…

轧钢厂安全生产方案:AI视频识别安全风险智能监管平台的设计

一、背景与需求 轧钢厂一般都使用打包机对线材进行打包作业&#xff0c;由于生产需要&#xff0c;人员需频繁进入打包机内作业&#xff0c;如&#xff1a;加护垫、整包、打包机检修、调试等作业。在轧钢厂生产过程中&#xff0c;每个班次生产线材超过300件&#xff0c;人员在一…

腾讯云优惠券是什么?腾讯云优惠券怎么领取?

腾讯云是腾讯集团倾力打造的云计算品牌&#xff0c;为了吸引用户上云&#xff0c;经常推出各种优惠活动&#xff0c;其中就包括腾讯云优惠券。 1、腾讯云优惠券解释说明 腾讯云优惠券是腾讯云的一种优惠凭证&#xff0c;包括代金券和折扣券&#xff0c;领券之后新购、续费、升…

证明char是定长的?

证明char是定长的&#xff1f; 大部分博客都在讲解char和varchar区别的时候都谈到char为定长&#xff0c;varchar为变长。 但是怎么证明char为定长呢&#xff1f; 下面是我证明的过程。 创建CHAR列&#xff1a;首先&#xff0c;创建一个CHAR列&#xff0c;指定其长度。例如&…

基于Tensorflow卷积神经网络玉米病害识别系统(UI界面)

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 Tensorflow是一个流行的机器学习框架&#xff0c;可用于训练和部署各种人工智能模型。玉米病害识别系统基于Tensorf…

毕业设计-课程设计-基于python+django+vue开发的外卖点餐网站

文章目录 源码下载地址项目介绍项目功能界面预览项目备注毕设定制&#xff0c;咨询 源码下载地址 点击下载源码 项目介绍 该系统是基于pythondjango开发的外卖点餐系统。适用场景&#xff1a;大学生、课程作业、毕业设计。学习过程中&#xff0c;如遇问题可以在github给作者…

【音视频 | opus】opus编解码库(opus-1.4)详细介绍以及使用——附带解码示例代码

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

答题测评考试小程序的效果如何

在线答题系统是一种在线练习、考试、测评的智能答题系统&#xff0c;适用于企业培训、测评考试、知识竞赛、模拟考试等场景&#xff0c;管理员可任意组题、随机出题&#xff0c;答题者成功提交后&#xff0c;系统自动判分。 多种题目类型&#xff0c;两种答题模式 练习模式&a…

搭建Qt5.7.1+kylinV10开发环境、运行环境

1.下载Qt源码 Index of / 2.编译Qt 解压缩qt-everywhere-opensource-src-5.7.1.tar.gz 进入到qt-everywhere-opensource-src-5.7.1/qtbase/mkspecs这个目录下&#xff0c; 2.1找到以下目录 复制他&#xff0c;然后改名linux-x86-arrch64&#xff0c;博主这里名字取的有些问…

go测试库之apitest

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

使用Python 脚自动化操作服务器配置

“ 有几十台特殊的服务器&#xff0c;没有合适的批量工具只能手动&#xff0c;要一个一个进行点击设置很耗费时间呀\~”,使用 Python 的简单脚本&#xff0c;即可模拟鼠标键盘进行批量作业 01 — 自动化示例 以某服务器中的添加用户权限为例&#xff0c;演示过程皆未触碰鼠标…