当前位置: 首页 > news >正文

单链表实现通讯录

之前我们完成了基于顺序表(动态)实现通讯录,现在我们链表学完了,可以尝试着使用链表来实现我们的通讯录。

首先我们要明白我们写的通讯录是由一个个节点组成的,每个节点里存储的就是我们的联系人信息。也就是说 我们需要先写一个单链表,完成单链表的插入,删除等功能。然后在单链表的基础上将单链表中的每个节点存储的数据改为一个联系人 由于这一部分我们之前写过,所以我在这里就不重复写了,大家可以看下我前面的博客。

一、通讯录的具体形式
在这里插入图片描述
二、实现通讯录

(1)、确定链表的类型

在我的双向链表这篇博客里我们了解了链表的分类,我们既写过不带头单向不循环链表,又写过带头双向循环链表。那么我们该如何选择呢?-在这里其实两种链表都可以,难度也是差不多的,因为双链表相较于单链表完善许多,那我们就用单链表来写。

(2)、完成通讯录的思路

首先,通讯录需要完成我们的 增、删联系人,修改联系人,查找联系人,打印通讯录。 这一部分就是我们需要完成的功能。

准备阶段:上面我们知道我们是由一个结构体来储存我们的联系人信息,我们就需要定义一个person联系人的结构体,然后我们之前写的链表里每个节点存储的数据的类型是int型,我们需要将其改为我们现在的person型。联系人的增删查改就是调用我们之前写的单链表的增删等函数,查改这两部分略有差异需要重新来写。

(3)、准备阶段:
contact.h

#define NAME_MAX 20
#define GENDER_MAX 10
#define ADDR_MAX 100
#define NUM_MAX 15
typedef struct person
{char name[NAME_MAX];//姓名char gender[GENDER_MAX];//性别int age;//年龄char addr[ADDR_MAX];//住址char num[NUM_MAX];//电话号码
}person;void ConAdd(contact** ptr);//联系人添加
void ConPrint(contact** ptr);//联系人打印
void ConPop(contact** ptr);//删除联系人
void ConFind(contact** ptr);//查找联系人
void ConGai(contact** ptr);//修改联系人
void ConDesTroy(contact** ptr);//销毁通讯录

ListNode.h

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"单链表contact.h"
typedef person datatype;
typedef struct ListNode
{datatype data;struct ListNode* next;
}ListNode;
void SLprint(ListNode** ptr);//打印
void SLBackPush(ListNode** ptr,datatype x);//单链表的尾插
void SLProntPush(ListNode** ptr, datatype x);//单链表的头插
void SLBackPop(ListNode** ptr);//单链表的尾删
void SLProntPop(ListNode** ptr);//单链表的头删
ListNode* SLFind(ListNode** ptr,datatype x);//链表的查找
void SLPosPush(ListNode** ptr, ListNode* pos, datatype x);//在指定位置插入数据
void SLPosPop(ListNode** ptr,ListNode* pos);//删除指定节点
void SLDesTory(ListNode** ptr);//销毁链表

这里我们需要注意的是因为我们需要将每个结构体里的数据类型换为person那么我们就需要包含contact.h的头文件,但是我们知道我们使用通讯录时其实是调用的外层的单链表结构,所以我们需要将ListNode.h包含在contact.h里,现在就出现了一个尴尬的情况–互相包含。解决的办法就是前置申明,在contact.h中typedef struct ListNode contact;这一段代码不光前置声明了还将外层的链表给改个名。

(4)、增删查改的实现

1、增加联系人,上面我们说过增加联系人就是调用我们的单链表的插入函数,我们写单链表的时候写了单链表的头插与尾插,在这里都可以,但是为了更符合日常我在这里采用尾插。

void ConAdd(contact** ptr)
{assert(ptr);printf("请输入添加的联系人的姓名  性别  年龄  住址  电话\n");person pes;scanf("%s", pes.name);scanf("%s", pes.gender);scanf("%d", &pes.age);//age是整型所以需要&符号scanf("%s", pes.addr);scanf("%s", pes.num);SLBackPush(ptr, pes);
}

这里需要注意的是我们是将整个person结构体定义的变量插入到链表,所以我们需要定义一个联系人的变量,先将联系人赋值,然后再将这整个变量作为我们的数据插入。

2、删除联系人

void ConPop(contact** ptr)
{assert(ptr && *ptr);char NAME[NAME_MAX];//定义一个数组printf("请输入你要删除的联系人的姓名:\n");scanf("%s", NAME);//输入我们要删除的联系人的姓名contact* pcur = *ptr;while (pcur){if (strcmp(pcur->data.name,NAME)==0)//比较输入的字符串和链表中的联系人姓名,名字相同时删除该联系人{if (pcur==*ptr)//当删除的联系人为第一个节点{pcur = pcur->next;free(*ptr);*ptr = pcur;break;}else//删除的联系人不在第一个节点{contact* prev = *ptr;while (prev->next != pcur)//找需要删除的联系人的前一个节点{prev = prev->next;}prev->next = pcur->next;free(pcur);pcur = NULL;break;}}pcur = pcur->next;}
}

删除联系人稍微比较麻烦,首先我们要确定以什么为标准来删除联系人,如果以电话号码来删除,就需要比较两个电话号码的字符串,名字同理,为了符合常理我这里使用名字,确定了以什么为标准以后我们还要考虑需要删除的联系人是否为第一个节点。

如果不为第一个节点,就需要遍历整个链表,找到需要删除的联系人的前一个节点,然后将前一个节点与后一个节点连接,最后释放掉需要删除的节点即可。

如果需要删除的联系人就是第一个节点的话,我们就不需要找前一个节点,直接让指向头结点的指针向后移,然后释放掉原来的头结点。

在这里插入图片描述
以上就是删除时的三种情况,第三种只有一个联系人的情况是可以通过第二种方式的代码解决。

3、查找联系人

同样查找联系人也需要我们以一个标准来选,我这里依然用名字来比较。

void ConFind(contact** ptr)
{assert(ptr && *ptr);char NAME[NAME_MAX];printf("请输入你要查找的联系人的姓名:\n");scanf("%s", NAME);contact* pcur = *ptr;while (pcur){if (strcmp(pcur->data.name, NAME) == 0){printf("姓名  性别  年龄  住址  电话\n");printf("%s  %s  %d  %s  %s\n", pcur->data.name,pcur->data.gender,pcur->data.age,pcur->data.addr,pcur->data.num);}pcur = pcur->next;}
}

这一部分简单许多,直接遍历链表,找到名字相同的节点,然后将该节点存储的联系人信息打印出来即可。

4、修改联系人

同样我这里用名字作为找联系人的标准。

void ConGai(contact** ptr)
{assert(ptr && *ptr);char NAME[NAME_MAX];printf("请输入你要修改的联系人的姓名:\n");scanf("%s", NAME);contact* pcur = *ptr;while (pcur){if (strcmp(pcur->data.name, NAME) == 0){printf("请输入修改后的联系人的姓名  性别  年龄  住址  电话\n");scanf("%s %s %d %s %s",pcur->data.name,pcur->data.gender,&pcur->data.age,pcur->data.addr,pcur->data.num);}pcur = pcur->next;}
}

这里跟上面的找联系人相似,找到后直接输入修改后的联系人的信息,覆盖掉原联系人的信息即可。

(5)、通讯录的销毁

当我们使用完通讯录,我们就需要将这个通讯录的空间给释放掉,那之前我们说有销毁就有初始化,为什么通讯录没有初始化呢?那是因为我们使用这个链表时,使用的是指向这个链表的指针,当我们不进行增删查改等操作时,该指针就为空,不需要进行初始化。

void ConDesTroy(contact** ptr)
{assert(ptr && *ptr);contact* pcur = *ptr;while (pcur){contact* del = pcur->next;free(pcur);pcur = del;}pcur = NULL;
}

销毁链表也比较简单,直接遍历整个链表,遍历一个释放一个。

上面我们完成了通讯录的功能,那么我们就可以将功能组装起来成为我们的通讯录。

#include"ListNode.h"
#include"单链表contact.h"
void menu()
{printf("***************************************\n");printf("*************单链表通讯录**************\n");printf("*******1、添加联系人  2、删除联系人****\n");printf("*******3、查找联系人  4、修改联系人****\n");printf("*******5、打印联系人  0、退出通讯录****\n");printf("***************************************\n");
}int main()
{contact* phead=NULL;int input = 0;do{menu();printf("请输入你的选项:\n");scanf("%d", &input);switch (input){case 1:ConAdd(&phead);break;case 2:ConPop(&phead);break;case 3:ConFind(&phead);break;case 4:ConGai(&phead);break;case 5:ConPrint(&phead);break;case 0:ConDesTroy(&phead);printf("退出成功");break;default:printf("选项错误,请重新输入:");break;}} while (input);return 0;
}

像这样我们就可以通过输入的数字来进行我们的通讯录操作。

上面我已经给出了contact.h ListNode.h test.c的代码,下面是其他部分的代码:
ListNode.c

#include"ListNode.h"ListNode* buynode(datatype x)
{ListNode* node = (ListNode*)malloc(sizeof(ListNode));if (node == NULL){perror("malloc");exit(1);}node->data = x;node->next = NULL;return node;
}void SLBackPush(ListNode** ptr,datatype x)
{assert(ptr);ListNode* node = buynode(x);if (*ptr == NULL){*ptr = node;}else{ListNode* ptail = *ptr;while (ptail->next != NULL){ptail = ptail->next;}ptail->next = node;}
}//void SLprint(ListNode** ptr)
//{
//	assert(ptr);
//	ListNode* pcur = *ptr;
//	while (pcur)
//	{
//		printf("%d ", pcur->data);
//		pcur = pcur->next;
//	}
//	printf("\n");
//}void SLProntPush(ListNode** ptr, datatype x)
{assert(ptr);ListNode* node = buynode(x);if (*ptr == NULL){*ptr = node;}else{node->next = *ptr;*ptr = node;}
}void SLBackPop(ListNode** ptr)
{assert(ptr);if ((*ptr)->next==NULL){free(*ptr);*ptr = NULL;}else{ListNode* pcur = *ptr;while (pcur->next->next){pcur = pcur->next;}ListNode* del = pcur->next;free(del);pcur->next = NULL;del = NULL;}
}void SLProntPop(ListNode** ptr)
{assert(ptr && *ptr);ListNode* del = *ptr;*ptr = (*ptr)->next;free(del);del = NULL;
}//ListNode* SLFind(ListNode** ptr, datatype x)
//{
//	assert(ptr && *ptr);
//	ListNode* pcur = *ptr;
//	while (pcur)
//	{
//		if (pcur->data == x)
//		{
//			return pcur;
//		}
//		pcur = pcur->next;
//	}
//	return NULL;
//}void SLPosPush(ListNode** ptr, ListNode* pos, datatype x)
{assert(ptr && *ptr && pos);if (pos == *ptr){SLProntPush(ptr, x);}else{ListNode* node = buynode(x);ListNode* pcur = *ptr;while (pcur->next != pos){pcur = pcur->next;}node->next = pos;pcur->next = node;}
}void SLPosPop(ListNode** ptr, ListNode* pos)
{assert(ptr&&*ptr&&pos);if (pos == *ptr){SLProntPop(ptr);}else{ListNode* pcur = *ptr;while (pcur->next != pos){pcur = pcur->next;}pcur->next = pos->next;free(pos);pos = NULL;}
}void SLDesTory(ListNode** ptr)
{assert(ptr);ListNode* pcur = *ptr;while (pcur){ListNode* del = pcur->next;pcur = pcur->next;free(pcur);pcur = del;}pcur = NULL;*ptr = NULL;
}

contact.c

#include"单链表contact.h"
#include"ListNode.h"void ConAdd(contact** ptr)
{assert(ptr);printf("请输入添加的联系人的姓名  性别  年龄  住址  电话\n");person pes;scanf("%s", pes.name);scanf("%s", pes.gender);scanf("%d", &pes.age);scanf("%s", pes.addr);scanf("%s", pes.num);SLBackPush(ptr, pes);
}void ConPrint(contact** ptr)
{assert(ptr);printf("姓名  性别  年龄  住址  电话\n");contact* pcur = *ptr;while (pcur){printf("%s    %s     %d    %s    %s\n", pcur->data.name,pcur->data.gender,pcur->data.age,pcur->data.addr,pcur->data.num);pcur = pcur->next;}
}void ConPop(contact** ptr)
{assert(ptr && *ptr);char NAME[NAME_MAX];printf("请输入你要删除的联系人的姓名:\n");scanf("%s", NAME);contact* pcur = *ptr;while (pcur){if (strcmp(pcur->data.name,NAME)==0){if (pcur==*ptr){pcur = pcur->next;free(*ptr);*ptr = pcur;break;}else{contact* prev = *ptr;while (prev->next != pcur){prev = prev->next;}prev->next = pcur->next;free(pcur);pcur = NULL;break;}}pcur = pcur->next;}
}void ConFind(contact** ptr)
{assert(ptr && *ptr);char NAME[NAME_MAX];printf("请输入你要查找的联系人的姓名:\n");scanf("%s", NAME);contact* pcur = *ptr;while (pcur){if (strcmp(pcur->data.name, NAME) == 0){printf("姓名  性别  年龄  住址  电话\n");printf("%s  %s  %d  %s  %s\n", pcur->data.name,pcur->data.gender,pcur->data.age,pcur->data.addr,pcur->data.num);}pcur = pcur->next;}
}void ConGai(contact** ptr)
{assert(ptr && *ptr);char NAME[NAME_MAX];printf("请输入你要修改的联系人的姓名:\n");scanf("%s", NAME);contact* pcur = *ptr;while (pcur){if (strcmp(pcur->data.name, NAME) == 0){printf("请输入修改后的联系人的姓名  性别  年龄  住址  电话\n");scanf("%s %s %d %s %s",pcur->data.name,pcur->data.gender,&pcur->data.age,pcur->data.addr,pcur->data.num);}pcur = pcur->next;}
}void ConDesTroy(contact** ptr)
{assert(ptr && *ptr);contact* pcur = *ptr;while (pcur){contact* del = pcur->next;free(pcur);pcur = del;}pcur = NULL;
}

最终实现的形式如下
在这里插入图片描述

相关文章:

单链表实现通讯录

之前我们完成了基于顺序表&#xff08;动态&#xff09;实现通讯录&#xff0c;现在我们链表学完了&#xff0c;可以尝试着使用链表来实现我们的通讯录。 首先我们要明白我们写的通讯录是由一个个节点组成的&#xff0c;每个节点里存储的就是我们的联系人信息。也就是说 我们需…...

Linux 命令操作技巧

Linux命令行界面提供了丰富的快捷键来提高操作效率&#xff0c;以下是一些常用的Linux终端快捷键&#xff0c;主要基于Bash shell&#xff1a; Tab - 自动补全&#xff1a;输入命令、文件名、目录名或命令选项的开头部分&#xff0c;然后按Tab键&#xff0c;系统会自动补全剩余…...

深度学习21天 —— 卷积神经网络(CNN):识别验证码( 第12天)

目录 一、前期准备 1.1 标签数字化 1.2 加载数据 1.3 配置数据 二、其他 2.1 损失函数 categorical_crossentropy 2.2 plt.legend(loc ) 2.3 history.history 活动地址&#xff1a;CSDN21天学习挑战赛 学习&#xff1a;深度学习100例-卷积神经网络&#xff08;CNN&…...

利用 Docker 简化Redis部署:快速搭建Redis服务

利用 Docker 简化Redis部署&#xff1a;快速搭建Redis服务 目录 利用 Docker 简化Redis部署&#xff1a;快速搭建Redis服务为什么选择 Docker准备工作拉取Redis镜像快速运行Redis容器验证Redis服务总结 在现代软件开发中&#xff0c;Redis作为一种高性能的键值数据库&#xff0…...

Web前端框架:深入探索与实践

Web前端框架&#xff1a;深入探索与实践 在当下数字化飞速发展的时代&#xff0c;Web前端框架的选择与应用成为了开发者们关注的焦点。Node.js&#xff0c;作为一种强大的后端技术&#xff0c;在前端框架的构建中也发挥着不可或缺的作用。本文将围绕Node.js Web前端框架&#…...

【算法】贪心算法——柠檬水找零

题解&#xff1a;柠檬水找零(贪心算法) 目录 1.题目2.题解3.参考代码4.证明5.总结 1.题目 题目链接&#xff1a;LINK 2.题解 分情况讨论 贪心算法 当顾客为5元时&#xff0c;收下当顾客为10元时&#xff0c;收下10元并找回5元当顾客为20元时&#xff0c;收下20元并找回10…...

Jmeter安装教程

1 Jmeter下载 Jmeter下载地址&#xff1a;https://jmeter.apache.org/download_jmeter.cgi&#xff0c;选择需要的版本点击下载 解压jmeter安装包 解压后的安装包如下&#xff1a; 2 配置Jmeter环境变量 进入环境变量配置页面&#xff1a;计算机->属性->高级系统设置-&…...

关于磁盘管理

磁盘管理是操作系统提供的一项功能&#xff0c;用于高效地组织、维护和控制计算机的硬盘驱动器及其卷&#xff08;分区&#xff09;。通过磁盘管理工具&#xff0c;用户和管理员可以执行多种与存储相关的高级任务&#xff0c;主要包括&#xff1a; 初始化新磁盘&#xff1a; …...

人大金仓数据库大小写不敏感确认

1、图形化确认(管理—其他选项—预设选项) 2、命令行确认 # ksql -p 54321 -U system test # show enable_ci; 查看是否大小写敏感&#xff0c;on表示大小敏感&#xff0c;off表示大小写不敏感&#xff0c;使用某些项目的时候&#xff0c;需要设置数据库大小写不敏感&#…...

【Java】还有人不懂继承?25 个 Case 包教包会

还有人不懂继承&#xff1f;25 个 Case 包教包会 1.Implement single inheritance2.Implement multilevel inheritance3.Implement hierarchical inheritance4.Override a base class method into a derived class5.Demonstrate the protected access specifier6.Create an Stu…...

Qt实现窗口失去焦点抖动功能

一、失去焦点检测 当窗口失去焦点时会发出FocusOut事件&#xff0c;具体实现如下&#xff1a; 首先给窗口安装事件过滤器&#xff1a; this->installEventFilter(this);然后在事件过滤器函数中判断有没有失去焦点 bool MessageDialog::eventFilter(QObject *object, QEve…...

Flink 数据源

原理 在 Flink 中&#xff0c;数据源&#xff08;Source&#xff09;是其中一个核心组件&#xff0c;负责从各种来源读取数据供 Flink 程序处理。 Flink 的数据源类型丰富&#xff0c;涵盖了从简单测试到生产环境使用的各种场景。Kafka、Socket、文件和集合是 Flink 中最常见…...

在本地电脑中如何用命令操作远程服务器上的数据库

日常做服务器维护&#xff0c;经常操作的2个事情&#xff0c;一个是备份远程服务器上的数据库到本地电脑&#xff0c;一个是将备份下来的数据库是恢复到本机做测试用。下面以阿里云的mysql为例&#xff0c;看看怎么弄。电脑是win10系统&#xff0c;先打开cmd命令行模式&#xf…...

uniApp子组件监听数据的变化的方法之一

props:{//用来接收外界传递过来的数据swiperList:{type:Array,default:[]}}, swiperList&#xff1a;是父组件传递过来的值 通过 watch 监听&#xff08;在父组件中也同样可以使用&#xff0c;跟VUE的监听数据变化同理&#xff09; watch:{//监听组件中的数据变化swiperList(ol…...

Python容器化技术的15个Docker实践

今天&#xff0c;我们将一起探索如何利用Docker这一强大的容器化工具&#xff0c;来提升你的Python项目开发、部署效率。通过一系列由浅入深的实践案例&#xff0c;你将学会如何将Python应用装入“小盒子”&#xff0c;让它在任何地方都能轻松运行。 1. Docker入门&#xff1a…...

QT天气预报项目(写在简历上)

一、ui设计 实现功能:可以搜索不同的城市进行天气的查询,并且显示未来7天内的天气,并绘制出当天的最高气温和最低气温曲线图。 学到的知识: stylesheet界面美化 Json数据解析 HTTP通信get请求 使用事件过滤器绘制温度曲线 多控件处理(利用数组) 代码整合调试能力 二…...

从零到一建设数据中台 - 数据可视化

从零到一建设数据中台(八)- 数据可视化 一、数据可视化大屏 数据可视化是借助于图形化手段,清晰有效地传达与沟通信息。 将一些业务的关键指标通过数据可视化的方式展示到一块或多块LED大屏上,以大屏为主要展示载体的数据可视化设计。 在数据可视化大屏构建过程中,为了…...

一步步实现知乎热榜采集:Scala与Sttp库的应用

背景 在大数据时代&#xff0c;网络爬虫技术发挥着不可或缺的作用。它不仅能够帮助我们快速地获取互联网上的信息&#xff0c;还能处理和分析这些数据&#xff0c;为我们提供深刻的洞察。知乎&#xff0c;作为中国领先的问答社区&#xff0c;汇聚了各行各业的专家和广大用户的…...

Windows和Linux系统部署Docker(2)

目录 一、Linux系统部署docker 前置环境&#xff1a; 1.安装需要的软件包&#xff0c; yum-util 提供yum-config-manager功能 2.添加阿里云 docker-ce 仓库 3.安装docker软件包 4.启动 docker并设置开机自启 5.查看版本&#xff1a; 二、windows系统部署docker 1.查看…...

PyCharm中快速搭建Python虚拟环境的指南

在 PyCharm 中创建一个新的 Python 虚拟环境可以帮助你为不同的项目管理不同的依赖包&#xff0c;避免版本冲突。以下是在 PyCharm 中创建虚拟环境的步骤&#xff1a; 打开或创建一个项目: 如果你还没有打开 PyCharm&#xff0c;首先打开它&#xff0c;然后选择“Open”打开一个…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...