单链表-通讯录

news2024/11/25 10:59:02

目录

单链表实现

通讯录代码实现

初始化

初始化函数

添加

删除

展示

查找

修改

销毁

代码展示

main.c

text.c

text.h

list.c

list.h


和前面的通讯录实现差不多这次就是实现一个以单链表为底层的通讯录

单链表实现

数据结构:单链表-CSDN博客

通讯录代码实现

初始化

//初始化
void InitContact(contact** con) {
	//初始化函数
	initialize(con);
}

初始化函数

// 函数:initialize,用于初始化联系人指针数组con,并从文件中读取并导入联系人信息
void initialize(contact** con) {
    // 打开名为"Contact.txt"的文件以只读二进制模式 ("rb")
    FILE* fp = fopen("Contact.txt", "rb");
    // 检查文件是否成功打开,如果文件不存在或无法打开,则输出错误信息并返回
    if (fp == NULL) {
        perror("fopen");  // 输出错误信息
        return;
    }

    // 定义一个PeoInfo类型的变量info,用于存储从文件中读取的单个联系人信息
    PeoInfo info;

    // 使用while循环逐条读取文件中的联系人信息
    while (fread(&info, sizeof(info), 1, fp)) {  // fread函数从文件中读取指定大小的数据到info变量
        // 调用Tail_insertion函数将读取到的联系人信息按照尾部插入的方式添加到通讯录(链表)中
        Tail_insertion(con, info);
    }

    // 当所有联系人信息成功插入后,输出提示信息
    printf("历史记录插入成功!\n");

    
    fclose(fp);  // 在这里关闭文件
}

尾部插入函数请看我的链表博客

添加

// 函数:AddContact,用于添加新的联系人至通讯录
void AddContact(contact** con) {
    // 创建一个PeoInfo类型的结构体变量info,用于存储用户输入的新联系人信息
    PeoInfo info;

    // 提示用户输入新联系人的姓名,并使用scanf读取字符串
    printf("请输入添加联系人姓名:\n");
    scanf("%s", info.name);

    // 提示用户输入新联系人性别,并使用scanf读取字符串
    printf("请输入添加联系人性别:\n");
    scanf("%s", info.sex);

    // 提示用户输入新联系人年龄,并使用scanf读取整数
    printf("请输入添加联系人年龄:\n");
    scanf("%d", &info.age);

    // 提示用户输入新联系人电话号码,并使用scanf读取字符串
    printf("请输入添加联系人电话:\n");
    scanf("%s", info.tel);

    // 提示用户输入新联系人地址,并使用scanf读取字符串
    printf("请输入添加联系人地址:\n");
    scanf("%s", info.addr);

    // 将新获取的联系人信息通过调用Tail_insertion函数将其按尾部插入的方式添加到通讯录(链表)中
    Tail_insertion(con, info);

    // 提示用户添加联系人成功
    printf("添加成功\n");
}

删除

// 函数:DelContact,用于根据姓名删除联系人
void DelContact(contact** con) {
    // 定义一个字符数组name,用于存储用户想要删除的联系人姓名
    char name[NAME_MAX];

    // 提示用户输入要删除的联系人姓名,并使用scanf读取
    printf("请输入要删除人的姓名>\n");
    scanf("%s", name);

    // 调用查找函数fun_b,传入通讯录头结点的指针以及待查找姓名,寻找对应联系人
    contact* pos = fun_b(*con, name); // 解引用con,获取通讯录头结点

    // 如果查找函数返回NULL,说明没有找到该姓名对应的联系人
    if (pos == NULL) {
        printf("没找到这个name\n");
        return;
    }

    // 调用SLTErase函数,传入通讯录头结点指针和待删除节点的指针,执行删除操作
    SLTErase(con, pos);

    // 删除操作成功后,输出提示信息
    printf("已经删除此联系人\n");
}

展示

// 函数:ShowContact,用于展示通讯录中的所有联系人信息
void ShowContact(contact* con) {
    // 设置输出格式,依次为姓名(10个字符宽度)、性别(4个字符宽度)、年龄(4个字符宽度)、电话(15个字符宽度)和地址(20个字符宽度)
    printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");

    // 初始化指向当前联系人的指针pcur为通讯录头结点
    contact* pcur = con;

    // 当pcur不为空时,即遍历整个通讯录链表
    while (pcur) {
        // 按照预先设置的格式输出当前联系人的详细信息
        printf("%-10s %-4s %-4d %15s %-20s\n",
            pcur->data.name,
            pcur->data.sex,
            pcur->data.age,
            pcur->data.tel,
            pcur->data.addr);

        // 遍历完当前节点后,将pcur指向下一个联系人节点
        pcur = pcur->next;
    }
}

查找

// 函数:fun_b,用于查找通讯录中指定姓名的联系人节点
contact* fun_b(contact* con, char* p) {
    // 初始化指针pcur指向通讯录头结点
    contact* pcur = con;

    // 循环遍历整个通讯录链表
    while (pcur) {
        // 使用strcmp函数比较当前节点联系人的姓名与输入的姓名字符串是否相同
        if (strcmp(pcur->data.name, p) == 0) {
            // 若姓名相同,直接返回当前节点的地址
            return pcur; // 找到了直接返回这个节点的位置
        }
        // 若姓名不同,则将pcur指向下一个联系人节点继续比较
        pcur = pcur->next;
    }

    // 若遍历完整个链表都没有找到匹配的姓名,则返回NULL
    return NULL;
}

修改

// 函数:ModifyContact,用于修改通讯录中指定姓名的联系人信息
void ModifyContact(contact** con) {
    // 定义一个字符数组name,用于存储用户想要修改的联系人姓名
    char name[NAME_MAX];

    // 提示用户输入要修改的联系人姓名,并使用scanf读取
    printf("请输入要修改的人的姓名>\n");
    scanf("%s", name);

    // 调用查找函数fun_b,传入通讯录头结点的指针以及待查找姓名,寻找对应联系人
    contact* pos = fun_b(*con, name); // 解引用con,获取通讯录头结点

    // 如果查找函数返回NULL,说明没有找到该姓名对应的联系人
    if (pos == NULL) {
        printf("没找到这个name\n");
        return;
    }

    // 找到联系人后,提示用户并逐一输入新的联系人信息
    printf("找到了\n");
    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);

    // 此处并未显示,但在实际应用中,通常会在输入验证和更新信息后,输出修改成功的提示信息
}

// 这段代码的作用是先查找通讯录中指定姓名的联系人,找到后让用户重新输入该联系人的各项信息,从而实现对联系人信息的修改。

销毁

// 函数:SaveContact,用于将通讯录数据保存到文件
void SaveContact(contact* con) {
    // 打开名为"Contact.txt"的文件以二进制写入模式 ("wb")
    FILE* pf = fopen("Contact.txt", "wb");
    
    // 检查文件是否成功打开,如果文件打开失败,则输出错误信息并返回
    if (pf == NULL) {
        perror("fopen");
        return;
    }

    // 遍历通讯录链表,将每个联系人的数据写入文件
    contact* pcur = con;
    while (pcur) {
        // 使用fwrite函数将当前联系人数据写入文件
        fwrite(&(pcur->data), sizeof(pcur->data), 1, pf);
        
        // 移动到下一个联系人节点
        pcur = pcur->next;
    }

    // 数据保存成功后输出提示信息
    printf("保存成功\n");

    
   fclose(pf);
}

// 函数:DestroyContact,用于销毁通讯录数据结构并保存数据到文件后再清理内存
void DestroyContact(contact** con) {
    // 先调用SaveContact函数将当前通讯录数据保存到文件
    SaveContact(*con);

    // 调用链表销毁函数SListDesTroy,释放通讯录所占用的内存资源
    SListDesTroy(con);
}

代码展示

main.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"text.h"

#if 0
void text1() {
	//创建4个节点
	SLTNode* a1 = (SLTNode*)malloc(sizeof(SLTNode));
	a1->data = 1;
	SLTNode* a2 = (SLTNode*)malloc(sizeof(SLTNode));
	a2->data = 2;
	SLTNode* a3 = (SLTNode*)malloc(sizeof(SLTNode));
	a3->data = 3;
	SLTNode* a4 = (SLTNode*)malloc(sizeof(SLTNode));
	a4->data = 4;

	//链接节点
	a1->next = a2;
	a2->next = a3;
	a3->next = a4;    
	a4->next = NULL;

	SLTNode* ptr = a1;
	SLTPrint(ptr);
}



void text2() {

	SLTNode* a1 = NULL;
	Tail_insertion(&a1,1);
	Tail_insertion(&a1,2);
	Tail_insertion(&a1,3);
	Tail_insertion(&a1,4);
	SLTPrint(&a1);
	SListDesTroy(&a1);
	SLTPrint(&a1);
	/*Head_insertion(&a1,0);
	SLTPrint(&a1);*/

	/*Tail_delete(&a1);
	SLTPrint(&a1);*/

	/*Head_delete(&a1);
	SLTPrint(&a1);*/
	

	//SLTNode *p = Find(a1, 1);
	//SLTInsert(&a1, p, 5);
	//SLTPrint(&a1);
	/*SLTInsert(&a1, 1, 5);
	SLTPrint(&a1);*/
	/*
	SLTInsertAfter(p,6);
	SLTPrint(&a1);*/
	//if (p == NULL)
	//{
	//	printf("NO");
	//}
	//else
	//{
	//	printf("YES");
	//}
	/*SLTErase(&a1,p);
	SLTPrint(&a1);*/
	/*SLTEraseAfter(p);
	SLTPrint(&a1);*/
}
int main() {
	//text1();
	text2();
	return 0;
}
#endif // 0
void eumn() {
	printf("****************************\n");
	printf("****1.add  2.DEL  3.FIND****\n");
	printf("****4.MOD  5.SHOW 6.SORT****\n");
	printf("****7.SAVE        0.EXIT****\n");
	printf("****************************\n");
}
int main() {
	contact* con = NULL;//创建一个为NULL的链表

	int input = -1;
	InitContact(&con);//初始化

	do
	{
		eumn();
		printf("请选择您的操作:\n");
		scanf("%d", &input);

		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case FIND:
			FindContact(con);
			break;
		case MOD:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(con);
			break;
		case SORT:
			Contacts_sort(con);
			break;
		case SAVE:
			DestroyContact(&con);
			break;
		case EXIT:
		
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);

	return 0;
}

text.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"text.h"
#include"list.h"
//开辟内存函数
static SLTNode* SList_ina(SLTDataType x) {

	//申请空间
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	//判断是否为空
	if (newnode == NULL)
	{
		perror("malloc");
		exit(EXIT_FAILURE);//中止程序
	}
	newnode->data = x;//将新节点的内容x赋值
	newnode->next = NULL;//将指向下一个地址设NULL
	return newnode;//返回节点
}
#if 0
//打印
void SLTPrint(SLTNode** Phead) {
	assert(Phead);
	SLTNode* pcur = *Phead;

	while (pcur)
	{
		printf("%d->", pcur->data);//打印节点内容
		pcur = pcur->next;//下一个节点地址赋值(循环)
	}
	printf("NULL\n");
}
#endif // 0

//尾插
void Tail_insertion(SLTNode** Phead, SLTDataType x){
	//判断链表是否为空
	//开辟新的节点
	SLTNode* newnode = SList_ina(x);
	if (*Phead == NULL)
	{
		*Phead = newnode;
	}
	else
	{
		//用一个指针指向第一个元素
		SLTNode* pcur = *Phead;
		while (pcur->next)
		{
			pcur = pcur->next;
		}
		pcur->next = newnode;
	}
}
	
//头插
void  Head_insertion(SLTNode** Phead, SLTDataType x) {
	//创建新的节点
	SLTNode* newcode = SList_ina(x);
	//将新开辟的节点的执政指向第一个节点
	newcode->next = *Phead;
	//由于Phead指向的是头部,然后我们在头部插入了一个节点,这个时候Phead指向的就不再是头部,我们直接将新节点的地址赋值给这个指向头部的指针
	*Phead = newcode;
}


//尾删
void Tail_delete(SLTNode** Phead) {
	assert(Phead && *Phead);
	//判断是否是一个节点
	//如果是就直接释放掉
	//如果不是就找的尾节点,和为节点的上一个节点

	if ((*Phead)->next == NULL)//->优先级高于*
	{
		free(*Phead);
		*Phead = NULL;
	}
	else
	{
		//定义两个指针都指向头节点
		SLTNode* Tail_1 = *Phead;
		SLTNode* Tail_2 = *Phead;

		//当Tail_1 == NULL的时候我们的while循环就跳出去了,这样我们的Tail_2就存的尾节点的上一个位置
		while (Tail_1 ->next)
		{
			Tail_2 = Tail_1;//存储尾节点的上一个位置
			Tail_1 = Tail_1->next;//找尾节点
		}
		free(Tail_1);
		Tail_1 = NULL;
		Tail_2->next = NULL;//要将指向的下一个元素设为NULL

	}
}

//头删
void Head_delete(SLTNode** Phead) {
	assert(*Phead && Phead);//Phead -- 不能解引用空指针  *Phead -- 指向第一个节点的指针,第一个节点不能为空
	//存储第二个节点的地址
	SLTNode* next = (*Phead)->next;
	//直接释放掉第一个节点
	free(*Phead);
	//将我们存储的第二个的地址赋给*Phead(头指针),让他指向第二个节点,让第二个节点变成第二个节点
	*Phead = next;
}


#if 0


//查找
SLTNode *Find(SLTNode* Phead, SLTDataType x) {
	assert(Phead);
	SLTNode* pcur = Phead;//不改变我们的头,找个小弟帮他走	
	while (pcur)
	{
		if (pcur->data == x) {
			return pcur;
		}
		//往后找
		pcur = pcur->next;
	}
	return NULL;
}

#endif // 0

#if 0



//在指定位置之前插⼊数据 
void SLTInsert(SLTNode** Phead, SLTNode* pos, SLTDataType x) {
	assert(Phead && *Phead);
	SLTNode* pcur = *Phead;//把第一个节点地址传给pcur
	SLTNode* newnode = SList_ina(x);
	SLTNode* poss =  Find(*Phead,pos);
	if (*Phead == poss)
	{
		Head_insertion(Phead,x);
	}
	else
	{
		//寻找pos前的一个点
		while (pcur->next != poss)
		{
			assert(pcur->next);//判断下一个节点不能为空
			pcur = pcur->next;
		}
		//改变节点指针
		newnode->next = poss;
		pcur->next = newnode;
	}
}
#endif // 0


//在指定位置之后插⼊数据 
void SLTInsertAfter(SLTNode* pos, SLTDataType x) {
	assert(pos && pos->next);
	SLTNode* newnode = SList_ina(x);
	SLTNode* pcur = pos->next;//将下一个节点地址给pcur
	 newnode->next = pcur;
	 pos->next = newnode;
}


//删除pos节点 
void SLTErase(SLTNode** Phead, SLTNode* pos) {
	assert(Phead && *Phead);
	if (*Phead == pos)//要删除第一个节点
	{
		//直接调用头删除
		Head_delete(Phead);
	}
	else
	{
		//将第一个节点地址传入pcur
		SLTNode* pcur = *Phead;
		while (pcur->next != pos)
		{
			pcur = pcur->next;
		}
		pcur->next = pos->next;//将pos中next指针指向的地址让pcur中next指针指向
		//释放pos
		free(pos);
		pos = NULL;
	}
}

//删除pos之后的节点 
void SLTEraseAfter(SLTNode* pos){

	assert(pos && pos->next);
	SLTNode* pcur = pos->next;//将第二个节点的地址存在pcur
	pos->next = pcur->next;//这边pcur->next指向的是第三个节点的地址
	free(pcur);
	pcur = NULL;
}


//销毁链表
void SListDesTroy(SLTNode** Phead) {
	//这里的销毁我们需要将每一个节点都销毁掉
	assert(Phead && *Phead);
	SLTNode* pcur = *Phead;
	while (pcur)
	{
		SLTNode* next = pcur->next;//将下一个位置存储一下
		free(pcur);
		pcur = next;
	}
	*Phead = NULL;
}

text.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
//#include<vld.h>
#include"list.h"


typedef struct PersonInfo SLTDataType;
//定义链表节点结构
typedef struct SListNode
{
	SLTDataType data;//内容
	struct SListNode* next;//指向下一个节点的指针
}SLTNode;


//打印
void SLTPrint(SLTNode** Phead);

//尾部插入/头部插入
void Tail_insertion(SLTNode** Phead, SLTDataType x);
void  Head_insertion(SLTNode** Phead, SLTDataType x);

//尾部删除/头部删除
void Tail_delete(SLTNode** Phead);
void Head_delete(SLTNode** Phead);

//查找
SLTNode* Find(SLTNode* Phead, SLTDataType x);


//在指定位置之前插⼊数据 
void SLTInsert(SLTNode** Phead, SLTNode* pos, SLTDataType x);
//在指定位置之后插⼊数据 
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

//删除pos节点 
void SLTErase(SLTNode** Phead, SLTNode* pos);
//删除pos之后的节点 
void SLTEraseAfter(SLTNode* pos);
//销毁链表 
void SListDesTroy(SLTNode** Phead);

list.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"text.h"
#include"list.h"
void initialize(contact** con) {
	//读文件内容
	FILE* fp = fopen("Contact.txt", "rb");
	if (fp == NULL) {
		perror("fopen");
		return;
	}

	//创建一个通讯录结构
	PeoInfo info;
	//利用while循环进行导入
	while (fread(&info,sizeof(info),1,fp))
	{
		Tail_insertion(con,info);//尾插
	}
	fclose(fp);
	printf("历史记录插入成功!\n");

}

//初始化
void InitContact(contact** con) {
	//初始化函数
	initialize(con);
}

//增加
void AddContact(contact** con){
	//创建一个通讯录结构
	PeoInfo 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);
	//进行尾插
	Tail_insertion(con, info);
	printf("添加成功\n");
}

//展示
void ShowContact(contact* con) {
	printf("%-10s %-4s %-4s %15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	contact* pcur = con;
	while (pcur)
	{
		printf("%-10s %-4s %-4d %15s %-20s\n",
			pcur->data.name,
			pcur->data.sex,
			pcur->data.age,
			pcur->data.tel,
			pcur->data.addr);
		pcur = pcur->next;//每打印一个节点走向下一个节点
	}
}

//查找函数
contact* fun_b(contact* con,char *p) {
	contact* pcur = con;
	while (pcur)
	{
		if (strcmp(pcur->data.name, p) == 0) {
			return pcur;//找到了直接返回这个节点的位置
		}
		pcur = pcur->next;
	}
	return NULL;
}

//删除
void DelContact(contact** con) {
	char name[NAME_MAX];
	printf("请输入要删除人的姓名>\n");
	scanf("%s", name);
	//查找函数
	contact* pos = fun_b(*con, name);//解引用con
		if (pos == NULL)	
		{
			printf("没找到这个name\n");
			return;
		}
SLTErase(con, pos);
printf("已经删除此联系人\n");
	
}

//查找
void FindContact(contact* con) {
	char name[NAME_MAX];
	printf("请输入要查找人的姓名>\n");
	scanf("%s", name);
	//查找函数
	contact* pos = fun_b(con, name);
	if (pos == NULL)
	{
		printf("没找到这个name");
		return;
	}
	printf("找到了\n");
	printf("%-10s %-4s %-4d %15s %-20s\n",
		pos->data.name,
		pos->data.sex,
		pos->data.age,
		pos->data.tel,
		pos->data.addr);
}


//修改通讯录数据
void ModifyContact(contact** con) {
	char name[NAME_MAX];
	printf("请输入要修改的人的姓名>\n");
	scanf("%s", name);
	//查找函数
	contact* pos = fun_b(*con, name);//解引用con
	if (pos == NULL)
	{
		printf("没找到这个name");
		return;
	}
	printf("找到了\n");
	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);
}

int compareMyType_name(const void* a1, const void* a2) {

	return strcmp(((PeoInfo*)a1)->name, ((PeoInfo*)a2)->name);
}

void compareMyType_age(void* a1, void* a2) {

	return ((PeoInfo*)a1)->age - ((PeoInfo*)a2)->age;
}
//排序


//销毁之前的存储
void SaveContact(contact* con) {
	FILE* pf = fopen("Contact.txt","wb");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}
	//将通讯录数据写⼊⽂件 
	contact* pcur = con;
	while (pcur)
	{
		fwrite(&(pcur->data),sizeof(pcur->data),1,pf);
		pcur = pcur->next;//一直往后走
	}
	printf("保存成功\n");
}
//销毁
void DestroyContact(contact** con) {
	SaveContact(*con);//存储
	SListDesTroy(con);//直接调用链表中的销毁
}

list.h

#pragma once

#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100

enum MyEnum
{
	EXIT,
	ADD,//增加
	DEL,//删除
	FIND,//查找
	MOD,//修改
	SHOW,//展示
	SORT,//排序
	SAVE,//保存
};

//前置声明
typedef struct SListNode contact;

//用户数据
typedef struct PersonInfo
{
    char name[NAME_MAX];
    char sex[SEX_MAX];
    int age;
    char tel[TEL_MAX];
    char addr[ADDR_MAX];
}PeoInfo;

//初始化通讯录
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);
//排序
//void Contacts_sort(contact* con);

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

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

相关文章

【资源分享】SPSS 26免费下载安装

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…

(51单片机)第十一章-串行口应用提高

11.1 方式0应用 在第6章中&#xff0c;已经对51单片机的串行口结构做过详细介绍&#xff0c;并且通过实例讲解了串行口的4种工作方式中方式1的具体用法&#xff0c;本节详细讲述串行口方式0的用法。 串行口方式0被称为同步移位寄存器的输入/输出方式&#xff0c;主要用于扩展并…

量化系统QTYX使用攻略|“选股框架”篇——组合对比分析,孰优孰劣一目了然(更新2.8.2)...

2024龙年大吉&#xff01;整装待发&#xff01;知识星球《玩转股票量化交易》精华内容概览 搭建自己的量化系统 股票量化交易系统QTYX是一个即可以用于学习&#xff0c;也可以用于实战炒股分析的系统。 分享QTYX系统目的是提供给大家一个搭建量化系统的模版&#xff0c;最终帮助…

OCP Java17 SE Developers 复习题13

答案 D, F. There is no such class within the Java API called ParallelStream, so options A and E are incorrect. The method defined in the Stream class to create a parallel stream from an existing stream is parallel(); therefore, option F is correct, and o…

【粉丝福利 | 第5期】教你快速入门三大层次学习企业架构框架TOGAF

⛳️ 写在前面参与规则&#xff01;&#xff01;&#xff01; ✅参与方式&#xff1a;关注博主、点赞、收藏、评论&#xff0c;任意评论&#xff08;每人最多评论三次&#xff09; ⛳️本次送书1~4本【取决于阅读量&#xff0c;阅读量越多&#xff0c;送的越多】 三大层次学习…

想冲银行去了!

这次给大家分享银行的Java后端面经&#xff0c;面试难度相比互联网大厂小了很多&#xff0c;面试时间大概是 10-30 分钟&#xff0c;技术面试的时间直接缩减一半&#xff01;而且&#xff0c;问的问题也相对比较简单一些。 今天主要分享杭州银行、招商银行网络科技的技术面试问…

相机摄影入门技巧,数码摄影技巧大全

一、资料前言 本套数码相机摄影资料&#xff0c;大小1.08G&#xff0c;共有42个文件。 二、资料目录 《aking人像摄影技巧分享》.pdf 《Nikon.D90数码单反摄影技巧大全》FUN视觉.全彩版.pdf 《不可不学的摄影技巧》.pdf 《常用场景摄影》.pdf 《单反数码摄影专家技法》.…

java学习笔记6

11. 类的封装 ​ 在Java中,**封装(Encapsulation)**是面向对象编程中的重要概念,它指的是将类的数据(属性)和行为(方法)绑定在一起,并对外部隐藏数据的具体实现细节,只通过公共方法来访问和操作数据。这有助于提高代码的安全性、可维护性和灵活性。 11.1 为什要封装 …

electron打包编译国产统信uos系统 arm架构 x86架构 linux mac等环境

electron v21版本以上统信UOS会提示gbm_bo_map错误&#xff0c;可使用v8~v21版本的electron 打包linux包需要再linux系统下运行编译&#xff0c;arch可以指定架构 如果要在统信uos上运行&#xff0c;需要打包成deb格式&#xff0c;在target中修改成deb 或者用第三方软件把app…

3. 无重复字符的最长子串/438. 找到字符串中所有字母异位词/560. 和为 K 的子数组

3. 无重复字符的最长子串 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。 思路&#xff1a;想象一下我们…

C语言 选择控制结构(1) 了解选择结构 关系运算符讲解 基本逻辑判断演示

接下来 我们来说 选择控制结构 在生活中 我们也有很多需要分支结构的例子 比如: 计算两个整数的最大值 计算n个数的最大值&#xff0c;最小值 判断三角形三边能否构成三角形? 判断某年是否是闰年? 判断输入的英文字母是大写还是小写? 我们在程序开发中 需要根据某种条件 进…

重磅!Meta 发布 Llama 3,前所未有的强大功能和多模态能力|TodayAI

Meta今日宣布推出其最新一代尖端开源大型语言模型Llama 3。该模型预计很快将在多个领先的云服务平台上线&#xff0c;包括AWS、Databricks、Google Cloud、Hugging Face、Kaggle、IBM WatsonX、Microsoft Azure、NVIDIA NIM和Snowflake。 Llama 3模型得到了AMD、AWS、Dell、In…

解决VirtualBox虚拟机启动失败的问题

一.出现的问题&#xff08;未能启动虚拟电脑&#xff0c;由于物理网卡未找到&#xff09; 一、错误信息分析 “未能启动虚拟电脑&#xff0c;由于物理网卡未找到”&#xff1a;这个错误通常是由于VirtualBox无法识别或连接到物理网卡造成的。可能是由于驱动程序问题、网络设置错…

Hadoop——Yarn 调度器和调度算法

Yarn 调度器和调度算法 YARN调度器&#xff08;Scheduler&#xff09;是负责将集群资源分配给不同应用程序的组件。它根据应用程序的资源需求和优先级&#xff0c;以及集群的资源供给情况&#xff0c;决定如何分配资源。YARN提供了多种调度器实现&#xff0c;每种调度器都有不…

力扣:219. 存在重复元素 II

力扣&#xff1a;219. 存在重复元素 II 给你一个整数数组 nums 和一个整数 k &#xff0c;判断数组中是否存在两个 不同的索引 i 和 j &#xff0c;满足 nums[i] nums[j] 且 abs(i - j) < k 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 …

服务调用-微服务小白入门(4)

背景 各个服务应用&#xff0c;有很多restful api&#xff0c;不论是用哪种方式发布&#xff0c;部署&#xff0c;注册&#xff0c;发现&#xff0c;有很多场景需要各个微服务之间进行服务的调用&#xff0c;大多时候返回的json格式响应数据多&#xff0c;如果是前端直接调用倒…

ST-GCN模型详解(+openpose)

ST-GCN模型详解&#xff08;openpose&#xff09; 一、什么是ST-GCN呢 基于骨架的动作识别&#xff08;Skeleton-Based Action Recognition&#xff09;主要任务是从一系列时间连续的骨骼关键点&#xff08;2D/3D&#xff09;中识别出正在执行的动作。因为牵涉到骨骼框架这种…

工控CTF之协议分析类型

协议分析 主要以工控流量和恶意流量为主&#xff0c;难度较低的题目主要考察Wireshark使用和找规律&#xff0c;难度较高的题目主要考察协议定义和特征 简单只能简单得干篇一律&#xff0c;难可以难得五花八门 常见的工控协议有&#xff1a;Modbus、MMS、IEC60870、MQTT、CoA…

完整版软件建模复习题和答案

一、单选题 D &#xff09;1&#xff0e;下面哪个不是信息系统利益相关者&#xff1f; A&#xff0e;客户 B&#xff0e;用户 C&#xff0e;开发人员 D&#xff0e;监理人员 B &#xff09;2&#xff0e;下面哪项不是用户主要关注的软件质量属性&#xff1f; A&#xff0e;…

解线性方程组——上三角、下三角,回代算法 | 北太天元

解上三角(回代) a i i ≠ 0 a_{ii\neq0} aii0​ , i 1 , 2 , … , n i1,2,\ldots,n i1,2,…,n a 11 x 1 a 12 x 2 ⋯ a 1 n x n b 1 a 22 x 2 ⋯ a 2 n x n b 2 ⋯ a n n x n b n \begin{aligned} a_{11}x_1a_{12}x_2\cdotsa_{1n}x_n&b_1 \\ a_{22}x_2\cdotsa_…