单链表-通讯录

目录

单链表实现

通讯录代码实现

初始化

初始化函数

添加

删除

展示

查找

修改

销毁

代码展示

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.mfbz.cn/a/555599.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony多媒体-video_trimmer

简介 videotrimmer是在OpenHarmony环境下&#xff0c;提供视频剪辑能力的三方库。 效果展示&#xff1a; 安装教程 ohpm install ohos/videotrimmerOpenHarmony ohpm环境配置等更多内容&#xff0c;请参考 如何安装OpenHarmony ohpm包 。 使用说明 目前支持MP4格式。 视频…

docker部署的nginx配置ssl证书https

申请ssl证书&#xff0c;已腾讯的免费证书为例 2.上传证书到linux服务器 2.1 映射ssql目录 首先确保容器命令已映射宿主机目录&#xff0c;不一定是ssl&#xff0c;也可以是其他路径。 2.2 上传文件到指定路径 以我映射的ssl路径为例&#xff0c;我上传到宿主机的 /usr/local…

【GEE实践应用】使用MODIS NDVI数据集绘制研究区域每日NDVI序列曲线

// 设置研究区域 var geometry table;// 选择MODIS NDVI 数据集 var modisNDVI ee.ImageCollection(MODIS/006/MOD13A2).filterBounds(geometry).filterDate(2000-01-01, 2023-12-31);// 计算每天的平均 NDVI var dailyMeanNDVI modisNDVI.map(function(image) {var date e…

(最详细)关于List和Set的区别与应用

关于List与Set的区别 List和Set都继承自Collection接口&#xff1b; List接口的实现类有三个&#xff1a;LinkedList、ArrayList、Vector。Set接口的实现类有两个&#xff1a;HashSet(底层由HashMap实现)、LinkedHashSet。 在List中&#xff0c;List.add()是基于数组的形式来添…

OpenHarmony网络组件-Mars

项目简介 Mars 是一个跨平台的网络组件&#xff0c;包括主要用于网络请求中的长连接&#xff0c;短连接&#xff0c;是基于 socket 层的解决方案&#xff0c;在网络调优方面有更好的可控性&#xff0c;暂不支持HTTP协议。 Mars 极大的方便了开发者的开发效率。 效果演示 编译…

简述Kafka的高可靠性

什么叫可靠性&#xff1f; 大家都知道&#xff0c;系统架构有三高&#xff1a;「高性能、高并发和高可用」&#xff0c;三者的重要性不言而喻。 对于任意系统&#xff0c;想要同时满足三高都是一件非常困难的事情&#xff0c;大型业务系统或者传统中间件都会搭建复杂的架构来…

万字长文带你APK反编译重签名aabapks转换

Android反编译 反编译&#xff08;Decompilation&#xff09;是将已编译的程序&#xff08;比如二进制代码&#xff09;转换回更高级别的编程语言代码的过程。这通常用于理解程序的工作原理&#xff0c;进行软件审计&#xff0c;恢复丢失的源代码&#xff0c;或者进行教学研究…

提升数据质量的三大要素:清洗prompt、数据溯源、数据增强(含Reviewer2和PeerRead)​

前言 我带队的整个大模型项目团队超过40人了&#xff0c;分六个项目组 每个项目组都是全职带兼职&#xff0c;且都会每周确定任务/目标/计划然后各项目组各自做任务拆解&#xff0c;有时同组内任务多时 则2-4人一组 方便并行和讨论&#xff0c;每周文档记录当周工作内容&…

Leetcode 4.18

Leetcode 1.无重复字符的最长子串2.最长回文子串3.整数反转4.字符串转换整数 (atoi)5.正则表达式匹配 1.无重复字符的最长子串 无重复字符的最长子串 滑动窗口&#xff0c;先让右指针右移&#xff0c;如果发现这个子串有元素和右指针当前元素重复。 则&#xff1a; 左指针右移…

HackmyVM-----Boxing靶机

文章目录 正常打靶流程1.获取靶机IP地址2.获取靶机端口服务3.访问网页4.添加域名WindowsLinux 5.访问域名6.nc反弹shell 7.结束 正常打靶流程 1.获取靶机IP地址 ┌──(root㉿kali)-[/home/kali] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:10:3c:9b, …

Stable Diffusion XL优化终极指南

如何在自己的显卡上获得SDXL的最佳质量和性能&#xff0c;以及如何选择适当的优化方法和工具&#xff0c;这一让GenAI用户倍感困惑的问题&#xff0c;业内一直没有一份清晰而详尽的评测报告可供参考。直到全栈开发者Flix San出手。 在本文中&#xff0c;Flix介绍了相关SDXL优化…

H264标准协议基础3

参考博文 上一篇H264标准协议基础2 1.解码视频帧的poc计算 2.残差4x4 矩阵中的trailingones & numcoeff 2.1查表 trailingones 表达出尾部one(1,-1)系数的个数,按照zigzag扫描出(1,-1)个数,trailingones的最大为3; numcoeff 表达非零值系数的个数,最多为16个…

uniapp开发 如何获取IP地址?

一定要看到最后&#xff01;&#xff01;&#xff01; 一、需求 使用uniapp开发小程序时&#xff0c;需要调取【记录日活动统计】的接口&#xff0c;而这个接口需要传递一个ip给后台&#xff0c; 那么前端如何获取ip呢&#xff1f;下面代码里可以实现 二、代码实现 1.在项…

游戏开发主程进阶之路|主程或高级开发师面试必备之Android和iOS原生APP内嵌CocosCreator引擎

教程地址&#xff1a; 游戏开发主程进阶之路|主程或高级开发师面试必备之Android和iOS原生APP内嵌CocosCreator引擎 Hello大家好&#xff01;&#xff01;相信大家都玩过用过很多类型的APP应用或者游戏APP&#xff1b;现如今很多社交类型的APP或者教育机构的APP会选择通过在应…

demo(四)nacosgateway(2)gatewayspringsercurity

一、思路 1、整体思路 用户通过客户端访问项目时&#xff0c;前端项目会部署在nginx上&#xff0c;加载静态文件时直接从nginx上返回即可。当用户在客户端操作时&#xff0c;需要调用后端的一些服务接口。这些接口会通过Gateway网关&#xff0c;网关进行一定的处理&#xff0…

多线程学习记录

进程是一个个应用程序&#xff0c;线程则可以理解为一个应用进程中的多个功能。有了多线程&#xff0c;便可以让程序同时去做多件事情。 并发:在同一时刻&#xff0c;有多个指令在单个CPU上交替执行 并行:在同一时刻&#xff0c;有多个指令在多个CPU上同时执行 多线程实现 在J…

K8s: 关于Kubernetes中的Pod的创建,实现原理,Job调度pod以及pod网络

Pod 概述 Pod 是最小部署的单元&#xff0c;Pod里面是由一个或多个容器组成&#xff0c;也就是一组容器的集合一个pod中的容器是共享网络命名空间&#xff0c;每个Pod包含一个或多个紧密相关的用户业务容器Pod 是 k8s 系统中可以创建和管理的最小单元是资源对象模型中由用户创…

winform入门篇 第14章 列表控件

列表控件 列表控件 ListView相当于 ListBox的增强版&#xff0c;支持多列显示 最典型的例子:Windows的文件管理器的列表显示 列表控件的几种视图: Detail:详情模式 List: 列表模式 LargeIcon:大图标模式 Smallcon:小图标模式 列表控件的几个特点: 显示模式可以切换 可以…

java高校办公室行政事务管理系统设计与实现(springboot+mysql源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的闲一品交易平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于mvc的高校办公室行政…

excel导出并合并

普通导出数据 需求 需要将相同列数据合并 效果图&#xff1a; 代码&#xff1a; package cn.silence.test;import lombok.AllArgsConstructor; import lombok.Data;/*** 班级信息*/ Data AllArgsConstructor public class ClassInfo {/*** 学院*/private String academy;/**…