(超详细)基于动态顺序表实现简单的通讯录项目

前言:

  我们在上一章节用c语言实现了线性表中的的动态顺序表,那么顺序表就只是顺序表吗?当然不是,使用顺序表结构可以实现很多项目,许多项目的数据结构都会用到顺序表,本章节我们就要使用顺序表实现一个简易的通讯录项目。

准备

  由于我们的通讯录是基于动态顺序表实现的,所以我们实现这个项目会用到动态顺序表的底层代码。在动态顺序表中有三个文件,分别是头文件代码SeqList.h文件,包含项目实现代码SeqList文件,和测试文件test.c文件,我们要在此基础上增加两个文件实现通讯录,分别是包含头文件的Contact.h文件,和实现代码的Contact.c文件:

     在上一期的顺序表中,我们用一个结构体代表顺序表,而里面的arr数组负责存储数据,但是它内部存储的数据都是内置类型,如int,char类型的数据,所以比较简单。在这一期,我们要使用这个数组存储自定义类型,每个自定义类型都存储了一个联系人的信息,这样我们的顺序表就开始变得复杂了起来:

通讯录实现 

  我们说顺序表里存储的不再是内置类型,而是自定义类型,那么是怎样实现的呢?我们使用一个结构体,在它内部我们定义一个人的名字,性别,年龄,电话号码,家庭地址等信息使用数组存储,为了方便更改数组的长度,使用#define定义几个常量作为它们的数组长度,这个结构体我们将它命名为ConPeoInfo,为了方便使用,我们用typedef将它改名为Info:

#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100


 typedef struct ConPeoInfo
{
	char name[NAME_MAX];
	char gender[GENDER_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}Info;

定了好了自定义类型后我们只需要将需要实现的方法一一实现即可。

通讯录初始化和销毁

通讯录的初始化和销毁我们可以直接调用我们之前在顺序表的初始化方法,所以它们实现起来非常的简单。

通讯录初始化:
void ContactInit(Contact* con)
{
	assert(con);
	SeqInit(con);
}//初始化
通讯录销毁:
void ContactDestroy(Contact* con)
{
	SeqDestroy(con);
}//销毁

在这里我们提一下Contact类型就是SL类型,也就是顺序表类型。那么为什么要将它改名为Contact呢?contact的中文翻译为联系人,而SL也许放在通讯录代码中多数人都不认识,只会认为它是一个顺序表,所以为了让代码的辨识度更高,我们利用前置声明将SeqList类型改为了Contact类型:

typedef struct SeqList Contact;
//前置声明
添加联系人 :

   添加联系人是通讯录中最基本的功能。我们用一个Info类型的变量去接收我们要添加的联系人信息,再使用顺序表中的尾插方法将这个变量插入通讯录中:

void ContactAdd(Contact* con)
{
	Info cpi;
	printf("请输入要添加的姓名:\n");
	scanf("%s", cpi.name);
	printf("请输入要添加的性别:\n");
	scanf("%s", cpi.gender);
	printf("请输入要添加的年龄:\n");
	scanf("%d", &cpi.age);
	printf("请输入要添加的电话:\n");
	scanf("%s", cpi.tel);
	printf("请输入要添加的地址:\n");
	scanf("%s", cpi.addr);

	SeqPushBack(con, cpi);

	
}//添加联系人

当然我们也可以使用其他插入方法,如头插,指定位置插入。

删除联系人与通过姓名查找: 

  有添加就会有删除,删除联系人我们可以先通过查找联系人姓名来确定有没有这个人的信息,如果没有就输出没有这个联系人,如果有我们就将找到的联系人所在的下标返回,然后将这个下标的信息删除。

通过姓名查找联系人:
int FindByName(Contact* con, char name[])
{
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}
删除联系人: 
void ContactDel(Contact* con)
{
	char name[NAME_MAX];
	printf("请输入要删除的联系人姓名:\n");
	scanf("%s", name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("没有要删除的联系人数据!\n");
		return;
	}
	SLErase(con, find);
	printf("删除成功!\n");
}//删除

删除联系人我们使用了顺序表中的指定位置删除,因为我们返回的下标就是我们要删除的联系人所在的下标,所以这里我们只能使用指定位置删除这个方法。

修改联系人信息: 

 修改联系人我们同样采用查找联系人姓名的方法先确定有没有我们要修改的联系人信息,如果没有就无法修改,如果有我们才执行修改操作,而修改操作与添加操作相似:

void ContactMorify(Contact* con)
{
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("通讯录中没有要修改的联系人信息!\n");
		return;
	}

	printf("请输入新的姓名:\n");
	scanf("%s", con->arr[find].name);
	printf("请输入新的性别:\n");
	scanf("%s", con->arr[find].gender);
	printf("请输入新的年龄:\n");
	scanf("%d", &con->arr[find].age);
	printf("请输入新的电话:\n");
	scanf("%s",con->arr[find].tel);
	printf("请输入新的地址:\n");
	scanf("%s",con->arr[find].addr);
	printf("修改成功!\n");
	
}//修改
查找联系人 :

查找联系人则比较简单,我们同样使用查找联系人姓名的方法去确定有没有这个联系人,如果有我们就把这个联系人的信息全部打印出来:

void ContactFind(Contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人姓名:\n");
	scanf("%s", name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("要查找的联系人的数据不存在!\n");
		return;
	}
	printf("%5s  %5s  %5s  %5s %5s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("%s  %s  %d  %s  %s\n", con->arr[find].name,
		con->arr[find].gender,
		con->arr[find].age,
		con->arr[find].tel,
		con->arr[find].addr);
}
展示所有联系人信息:

当我们要查看所有联系人信息时,我们就可以使用这个方法,这个方法也比较简单,我们只需要将整个顺序表遍历一遍并将每个联系人的信息全部打印出来:

void ContactShow(Contact* con)
{
	int i = 0;
	printf("%5s  %5s  %5s  %5s %5s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (i = 0; i < con->size; i++)
	{
		printf("%s  %s  %d  %s  %s\n", con->arr[i].name,
			con->arr[i].gender,
			con->arr[i].age,
			con->arr[i].tel,
			con->arr[i].addr);

	}
}//所有联系人
 测试通讯录:

 当实现了这些方法之后,我们就可以实现通讯录的界面了,创建一个菜单函数,我们可以用指定数字来表示我们要执行的操作,比如我们要添加联系人,我们按数字1就可以开始添加联系人:

void menu()
{
	printf("*************通讯录************\n");
	printf("****1.添加联系人 2.删除联系人**\n");
	printf("****3.查找联系人 4.修改联系人**\n");
	printf("****5.全部联系人 0.退出********\n");
	printf("*******************************\n");

}

我们来看一下菜单:

菜单里的输入数字执行操作的功能我们使用switch语句实现:

int main()
{
	Contact con;
	int op = -1;
	ContactInit(&con);
	do
	{
		menu();
		printf("请选择您要进行的操作:\n");
		scanf("%d", &op);
		switch (op)
		{
		case 1:
			ContactAdd(&con);
			break;
		case 2:
			ContactDel(&con);
			break;
		case 3:
			ContactFind(&con);
			break;
		case 4:
			ContactMorify(&con);
			break;
		case 5:
			ContactShow(&con);
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}

	} while (op != 0);

	ContactDestroy(&con);

	//ContactTest01();
	return 0;
}

到这里我们通讯录所有的代码就已经实现完成了,我们来测试一下吧:

通过测试发现我们的方法都没有什么问题,我将代码放在下面 感兴趣的小伙伴可以试一下哦。

Contact.h :

#pragma once
typedef struct SeqList Contact;
//前置声明

#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100


 typedef struct ConPeoInfo
{
	char name[NAME_MAX];
	char gender[GENDER_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}Info;


//初始化
void ContactInit(Contact* con);
void ContactAdd(Contact* con);//添加
void ContactDel(Contact* con);//删除
void ContactMorify(Contact* con);//修改

void ContactFind(Contact* con);//查找
void ContactShow(Contact* con);//展示
//销毁
void ContactDestroy(Contact* con);

SeqList.h :

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"Contact.h"

typedef struct ConPeoInfo SLDataType;
typedef struct SeqList
{
	SLDataType* arr;
	int size;//有效数据
	int capacity;//空间大小

}SL;

void SeqInit(SL* ps);//初始化

void SeqDestroy(SL* ps);//销毁

void SeqPushBack(SL* ps, SLDataType x);//尾插

void SeqPushFront(SL* ps, SLDataType x);//头插

void SeqPopBack(SL* ps);//尾删

void SeqPopBack(SL* ps);//头删

void SeqPrint(SL* ps);//打印

void SLErase(SL* ps, int pos);//指定删除

int SLFind(SL* ps, SLDataType x);//查找数据

//指定下标前插入数据
void SLInsert(SL* ps, int pop, SLDataType x);






SeqList.c :

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"



void SeqInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}//初始化

void SeqCheckcapa(SL* ps)//检查内存够不够,不够则增加
{
	assert(ps);
	if (ps->capacity == ps->size)
	{
		int Newcapecity = ps->capacity == 0 ? 4 : 2 * ps->capacity * sizeof(SLDataType);
		SLDataType* tem = (SLDataType*)realloc(ps->arr, Newcapecity  * sizeof(SLDataType));
		if (tem != NULL)
		{
			ps->arr = tem;
		}
	}
}


void SeqPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SeqCheckcapa(ps);

	ps->arr[ps->size++] = x;

}//尾插

void SeqPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SeqCheckcapa(ps);
	int i = 0;
	for (i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[0] = x;
	++ps->size;
}//头插

void SeqPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size >= 0);

	ps->size--;
}//尾删

void SeqPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size >= 0);
	int i = 0;
	for (i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;

}//头删

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SeqCheckcapa(ps);

	int i = 0;
	for (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(pos >= 0 && pos < ps->size);
	int i = 0;
	for (i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];

	}
	ps->size--;
}//指定下标删除

//int SLFind(SL* ps, SLDataType x)
//{
//	assert(ps);
//	int i = 0;
//	for (i = 0; i < ps->size; i++)
//	{
//		if (ps->arr[i] == x)
//		{
//			return i;
//		}
//	}
//	return -1;
//}//查找数据
//void SeqPrint(SL* ps)
//{
//	assert(ps);
//	int i = 0;
//
//	for (i = 0; i < ps->size; i++)
//	{
//		printf("%d ", ps->arr[i]);
//	}
//	printf("\n");
//}//打印



void SeqDestroy(SL* ps)
{
	assert(ps);
	free(ps->arr);

	if (ps->arr != NULL);
	{
		ps->arr = NULL;
	}
	ps->capacity = ps->size = 0;
}
//销毁

Contact.c :

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
#include"Contact.h"
#include<string.h>


void ContactInit(Contact* con)
{
	assert(con);
	SeqInit(con);
}//初始化
int FindByName(Contact* con, char name[])
{
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}
	
void ContactAdd(Contact* con)
{
	Info cpi;
	printf("请输入要添加的姓名:\n");
	scanf("%s", cpi.name);
	printf("请输入要添加的性别:\n");
	scanf("%s", cpi.gender);
	printf("请输入要添加的年龄:\n");
	scanf("%d", &cpi.age);
	printf("请输入要添加的电话:\n");
	scanf("%s", cpi.tel);
	printf("请输入要添加的地址:\n");
	scanf("%s", cpi.addr);

	SeqPushBack(con, cpi);

	
}//添加联系人

void ContactDel(Contact* con)
{
	char name[NAME_MAX];
	printf("请输入要删除的联系人姓名:\n");
	scanf("%s", name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("没有要删除的联系人数据!\n");
		return;
	}
	SLErase(con, find);
	printf("删除成功!\n");
}//删除

void ContactMorify(Contact* con)
{
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("通讯录中没有要修改的联系人信息!\n");
		return;
	}

	printf("请输入新的姓名:\n");
	scanf("%s", con->arr[find].name);
	printf("请输入新的性别:\n");
	scanf("%s", con->arr[find].gender);
	printf("请输入新的年龄:\n");
	scanf("%d", &con->arr[find].age);
	printf("请输入新的电话:\n");
	scanf("%s",con->arr[find].tel);
	printf("请输入新的地址:\n");
	scanf("%s",con->arr[find].addr);
	printf("修改成功!\n");
	
}//修改
void ContactFind(Contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人姓名:\n");
	scanf("%s", name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("要查找的联系人的数据不存在!\n");
		return;
	}
	printf("%5s  %5s  %5s  %5s %5s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("%s  %s  %d  %s  %s\n", con->arr[find].name,
		con->arr[find].gender,
		con->arr[find].age,
		con->arr[find].tel,
		con->arr[find].addr);
}
void ContactShow(Contact* con)
{
	int i = 0;
	printf("%5s  %5s  %5s  %5s %5s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (i = 0; i < con->size; i++)
	{
		printf("%s  %s  %d  %s  %s\n", con->arr[i].name,
			con->arr[i].gender,
			con->arr[i].age,
			con->arr[i].tel,
			con->arr[i].addr);

	}
}//所有联系人
void ContactDestroy(Contact* con)
{
	SeqDestroy(con);
}//销毁

test.c :

#define _CRT_SECURE_NO_WARNINGS 1
#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;
	int op = -1;
	ContactInit(&con);
	do
	{
		menu();
		printf("请选择您要进行的操作:\n");
		scanf("%d", &op);
		switch (op)
		{
		case 1:
			ContactAdd(&con);
			break;
		case 2:
			ContactDel(&con);
			break;
		case 3:
			ContactFind(&con);
			break;
		case 4:
			ContactMorify(&con);
			break;
		case 5:
			ContactShow(&con);
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}

	} while (op != 0);

	ContactDestroy(&con);

	//ContactTest01();
	return 0;
}

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

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

相关文章

数值分析笔记(二)函数插值

函数插值 已知函数 f ( x ) f(x) f(x)在区间[a,b]上n1个互异节点 { x i } i 0 n \{{x_i}\}_{i0}^{n} {xi​}i0n​处的函数值 { y i } i 0 n \{{y_i}\}_{i0}^{n} {yi​}i0n​&#xff0c;若函数集合 Φ \Phi Φ中函数 ϕ ( x ) \phi(x) ϕ(x)满足条件 ϕ ( x i ) y i ( i …

论文阅读:RAM++ | Open-Set Image Tagging with Multi-Grained Text Supervision

发表时间&#xff1a;2023年11月16 论文地址&#xff1a;https://arxiv.org/pdf/2310.15200 项目地址&#xff1a;https://github.com/xinyu1205/recognize-anything Recognize Anything Plus Model&#xff08;RAM&#xff09;&#xff0c;这是一种有效利用多粒度文本监督的开…

课时154:项目发布_手工发布_手工发布

1.2.3 手工发布 学习目标 这一节&#xff0c;我们从 基础知识、简单实践、小结 三个方面来学习 基础知识 简介 为了合理的演示生产环境的项目代码发布&#xff0c;同时又兼顾实际实验环境的资源&#xff0c;我们这里将 B主机和C主机 用一台VM主机来实现&#xff0c;A主机单…

电路笔记 :LM3481MM/NOPB升压模块,升压电路原理

LM3481MM/NOPB LM3481MM/NOPB 是德州仪器&#xff08;Texas Instruments&#xff09;的一款广泛应用的DC-DC控制器&#xff0c;常用于电源管理应用&#xff0c;特别是在需要升压&#xff08;boost&#xff09;、反激&#xff08;flyback&#xff09;、SEPIC或反向配置的场合。…

【Ardiuno】实验使用OPT语音模块播放语音(图文)

当我们需要在程序中播放语音内容时&#xff0c;就需要使用到语音模块&#xff0c;今天我们就来实验一下使用OPT语音模块来方法语音。 const int voicePin 5; const int voiceBusyPin 18; const int testLEDPin 2;unsigned long pmillis 0;int busyVal 0; …

Go源码--sync库(3):sync.Pool(2)

回收 回收其实就是将 pool.local 置为空 可以让垃圾回收器回收 我们来看下 源码 func init() {// 将 poolCleanup 注册到 gc开始前的准备工作处理器中在 STW时执行runtime_registerPoolCleanup(poolCleanup) }这里注册了清理程序到GC前准备工作 也就是发生GC前需要执行这段代…

【每日随笔】摩托车控车 ① ( 油离配合 | 落脚油离配合 - 不给油 | 落脚油离配合 - 给油 | 正式油离配合 | 骑行姿态注意事项 )

文章目录 一、找 " 离合结合点 "二、落脚油离配合 ( 不给油 )1、该科目练习目的2、起步姿态3、开始练习 三、落脚油离配合 ( 给油 )1、练习目的2、熟悉油门转速3、练习步骤 四、正式油离配合1、练习目的2、练习步骤3、练习效果 五、骑行姿态注意事项1、基本骑行姿态2…

正能量情感语录热门素材文案去哪里找?文案素材网站分享

正能量情感语录热门素材文案去哪里找&#xff1f;文案素材网站分享 想为你的作品注入正能量和情感温度&#xff1f;不知如何获取热门情感语录素材&#xff1f;别担心&#xff0c;今天我将为大家推荐一些海外知名的素材网站&#xff0c;让你轻松找到受欢迎的文案素材&#xff…

对不起了,QQ和微信,我选择用它!

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 每当我们需要在电脑和手机之间传输文件、在学习和工作时与朋友/同事传输文件&#xff0c;相信大多都会使用微信或者QQ。 但是在分享一些软件apk等安装包时&#xff0c;微信和QQ会将其…

.gitignore文件忽略的内容不生效问题解决

文章目录 ①&#xff1a;现象②&#xff1a;原因③&#xff1a;解决 ①&#xff1a;现象 在已经提交过的git管理的项目中&#xff0c; 新增加一个.gitignore文件&#xff0c;文件内忽略内容不生效或者修改.gitignore文件之后&#xff0c;文件内新增的忽略内容不生效 ②&#…

ImageNet-1k 测试集 两大坑

1、官方网站提交test set标签时&#xff0c;千万不能提交zip文件&#xff0c;即便明文说可以 https://image-net.org/challenges/LSVRC/eval_server.php 不然就会浪费一次提交机会&#xff0c;直接提交submission.txt就可以&#xff0c;注意每排5个预测结果&#xff0c;用于计…

第 2 章:Spring Framework 中的 IoC 容器

控制反转&#xff08;Inversion of Control&#xff0c;IoC&#xff09;与 面向切面编程&#xff08;Aspect Oriented Programming&#xff0c;AOP&#xff09;是 Spring Framework 中最重要的两个概念&#xff0c;本章会着重介绍前者&#xff0c;内容包括 IoC 容器以及容器中 …

【UML用户指南】-16-对高级结构建模-构件

目录 1、概念 2、构件与接口 3、可替换性 4、组织构件 5、端口 6、内部结构 6.1、部件 6.2、连接件 7、常用建模技术 7.1、对结构类建模 7.2、对API建模 构件是系统中逻辑的并且可替换的部分&#xff0c;它遵循并提供对一组接口的实现。好的构件用定义良好的接口来定…

nginx全解

一、Nginx配置文件 1.1 主配置文件 主配置文件位置&#xff1a;nginx.conf tip&#xff1a;安装方式不同&#xff0c;路径不同 #主配置文件格式 ​ main block&#xff1a;主配置段&#xff0c;即全局配置段&#xff0c;对http,mail都有效 ​ #配置Nginx服务器的事件模块相…

Gstreamer学习3----灌数据给管线之appsrc

参考资料 Basic tutorial 8: Short-cutting the pipeline gstreamer向appsrc发送帧画面的代码_gst appsrc可变帧率-CSDN博客 在官网教程Basic tutorial 8: Short-cutting the pipeline 里面&#xff0c;讲了一个例子&#xff0c;push音频数据给管线&#xff0c;视频的例子更…

DP读书:《半导体物理学(第八版)》(四)半导体的导电性-玻尔兹曼-电导率

第四章 半导体的导电性 4.1 载流子的漂移运动和迁移率4.1.1欧姆定律4.2.2漂移速度和迁移4.1.3半导体的电导率和迁移率 4.2 载流子的散射4.2.1载流子散射的概念4.2.2半导体主要散射机构 4.3迁移率与杂质浓度和温度的关系4.3.1平均自由时间混合和散射概率的关系4.3.2电导率、迁移…

[C++]使用yolov10的onnx模型结合onnxruntime和bytetrack实现目标追踪

【官方框架地址】 yolov10yolov10框架&#xff1a;https://github.com/THU-MIG/yolov10 bytetrack框架&#xff1a;https://github.com/ifzhang/ByteTrack 【算法介绍】 Yolov10与ByTetrack&#xff1a;目标追踪的强大组合 Yolov10和ByTetrack是两种在目标追踪领域具有显…

算法体系-21 第二十一 暴力递归到动态规划(三)

一 最长回文子串 1.1 描述 给定一个字符串str&#xff0c;返回这个字符串的最长回文子序列长度 比如 &#xff1a; str “a12b3c43def2ghi1kpm” 最长回文子序列是“1234321”或者“123c321”&#xff0c;返回长度7 1.2 分析 1.2.1 先将原传逆序&#xff0c;求原串和反转后的…

代理IP协议有何区别?深入了解 SOCKS5、HTTP 代理

在数字通信领域&#xff0c;数据安全和匿名性都是非常重要的指标。互联网的不断发展催生了几种协议&#xff0c;每种协议都有独特的优势和挑战。其中&#xff0c;SOCKS5 代理、HTTP代理最为广泛使用&#xff0c;下面给大家一起讨论&#xff0c;HTTP代理与 SOCKS5代理&#xff0…

基于微信小程序的在线答题小程序设计与实现

个人介绍 hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的…