【数据结构】顺序表实操——通讯录项目

Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~
💥💥个人主页:奋斗的小羊
💥💥所属专栏:C语言

🚀本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为展示我的学习过程及理解。文笔、排版拙劣,望见谅。


目录

  • 前言
  • 1、创建结构体类型
  • 2、通讯录的初始化和销毁
  • 3、通讯录的增删查改
    • 3.1 添加联系人
    • 3.2 删除联系人
    • 3.3 展示联系人
    • 3.4 修改联系人
    • 3.5 查找联系人
  • 4、通讯录菜单
  • 5、通讯录项目代码
  • 总结

前言

本篇文章将介绍一个运用顺序表的例子——通讯录项目。
通讯录我们都知道,细细一想通讯录不就是一个顺序表吗?在通讯录中以一个联系人为单位,存储着若干个联系人的各种信息,我们也可以对通讯录中的联系人信息进行相应的增删查改操作。但是上篇文章的顺序表存的只是整型数据,而在本文联系人的信息可不只是整形数据,如果想把一个联系人的各种信息以一个联系人为单位存储,就需要用到我们之前学到的内置类型——结构体类型。
接下来将详细介绍基于顺序表的通讯录项目搭建的具体过程。
本文将延用上篇文章中实现好的顺序表代码,具体请看—>顺序表


1、创建结构体类型

我们需要存联系人的姓名、性别、年龄、电话、地址等信息,如果把联系人看作一个单位,就需要一个类型能将联系人的这些信息储存,我们很容易的就能想到自定义类型——结构体类型。
所以第一步我们需要创建一个结构体类型来保存联系人的这些信息。

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

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

我们将保存名字等信息的数组大小用宏代替,这样方便后续可能的更改。
创建好用于保存联系人信息的结构体类型后,接着就需要将顺序表头文件中的动态顺序表管理的数据类型替换掉,不要忘了包含相应的头文件。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "contact.h"

//顺序表管理数据的类型
//typedef int sl_data_type;
typedef peoinfo sl_data_type;

//动态顺序表
typedef struct seqlist
{
	sl_data_type* arr;
	int size;//数据个数
	int capacity;//空间大小
}SL;

2、通讯录的初始化和销毁

我们操作通讯录,实际上就是操作顺序表

那么通讯录的初始化和销毁,实际上就是顺序表的初始化和销毁。
为了方便识别,我们在通讯录头文件中给struct seqlist重新改个名字就叫contact。要想使用顺序表头文件中的struct seqlist原本是需要在通讯录头文件包含顺序表头文件的,但是顺序表头文件中已经包含了通讯录头文件,而我们知道头文件是不能互相包含的,那为了在通讯录头文件中使用struct seqlist,需要在使用前进行前置类型声明。
contact.h:

//给顺序表改一个名字
typedef struct seqlist contact;//前置声明

//通讯录的初始化
void contact_init(contact* con);
//通讯录的销毁
void contact_destroy(contact* con);

contact.c:

#include "contact.h"
#include "seqlist.h"

//通讯录的初始化
void contact_init(contact* con)
{
	//通讯录的初始化实际就是顺序表的初始化
	sl_init(con);
}

//通讯录的销毁
void contact_destroy(contact* con)
{
	sl_destroy(con);
}

3、通讯录的增删查改

3.1 添加联系人

在通讯录中添加联系人实际上就是上篇文章中的在顺序表中插入一个整型数据,只不过在这里把一个联系人当作一个单位。
首先我们需要一个结构体变量来存联系人的各种信息,然后再将这个结构体变量插入到通讯录(顺序表)中,插入方式可以有多种。

//通讯录添加数据
void contact_add(contact* con)
{
	//获取用户输入的信息
	//将用户输入的信息存到结构体变量中
	peoinfo info;
	printf("请输入要添加的联系人姓名:\n");
	scanf("%s", info.name);
	printf("请输入要添加的联系人性别:\n");
	scanf("%s", info.gender); 
	printf("请输入要添加的联系人年龄:\n");
	scanf("%d", info.age);
	printf("请输入要添加的联系人电话:\n");
	scanf("%s", info.tel);
	printf("请输入要添加的联系人地址:\n");
	scanf("%s", info.addr);

	//将结构体数据插入到通讯录(顺序表)中
	sl_push_back(con, info);
}

测试:

void test()
{
	contact con;// == SL sl;
	contact_init(&con);
	contact_add(&con);
	contact_destroy(&con);
}

int main()
{
	test();
	return 0;
}

请添加图片描述

可以看到我们成功地添加了一个联系人。


3.2 删除联系人

删除联系人操作有个大前提,就是要删除的这个联系人必须存在,否则无法删除。
怎么判断要删除的这个联系人是否存在呢?
首先我们需要获取要删除的这个联系人的信息,然后在通讯录中查找,如果找到了就可以执行删除操作,如果没找到就不能进行删除操作。
联系人的信息有好几个,我们可以任意选择其中的一个信息来判断是否存在这个联系人。

int find_by_name(contact* con, char name[])
{
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->arr[i].name, name))
		{
			//找到了
			return i;
		}
	}
	return -1;
}

//通讯录删除数据
void contact_delete(contact* con)
{
	//前提是要删除的这个联系人存在
	char name[NAME_MAX];
	printf("请输入您想删除的联系人姓名:\n");
	scanf("%s", name);
	int ret = find_by_name(con, name);
	if (ret < 0)
	{
		printf("联系人不存在!\n");
		//直接返回
		return;
	}
	
	//删除指定位置的数据
	sl_erase(con, ret);
	printf("删除成功!\n");
}

上面我们是通过联系人的姓名来判断是否存在这个联系人,姓名是字符串,比较字符串需要用到字符串比较函数strcmp,使用这个函数需要包含头文件<string.h>
如果找到匹配的姓名,则返回这个姓名对应联系人对应的下标,再调用顺序表中删除指定位置数据的函数删除这个联系人。

请添加图片描述


3.3 展示联系人

我们平时使用的通讯录是可以展示联系人的各种信息的,这里我们也简单地实现一下,将所有联系人的信息打印出来供使用者看。

//通讯录数据展示
void contact_show(contact* con)
{
	//打印表头
	printf("%2s %8s %8s %8s %8s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("———      ———      ———      ———      ———\n");
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		printf("%2s %7s %7d %9s %9s\n", con->arr[i].name,
			con->arr[i].gender,
			con->arr[i].age,
			con->arr[i].tel,
			con->arr[i].addr);
	}
}

在这里插入图片描述


3.4 修改联系人

修改联系人信息也有个大前提,就是要修改的这个联系人必须存在,才能被修改。

//通讯录修改
void contact_modify(contact* con)
{
	//前提是要修改的联系人存在
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", name);
	int ret = find_by_name(con, name);
	if (ret < 0)
	{
		printf("联系人不存在!\n");
		return;
	}

	//修改指定位置的数据
	printf("请输入新的姓名:\n");
	scanf("%s", con->arr[ret].name);
	printf("请输入新的性别:\n");
	scanf("%s", con->arr[ret].gender);
	printf("请输入新的年龄:\n");
	scanf("%d", &con->arr[ret].age);
	printf("请输入新的电话:\n");
	scanf("%s", con->arr[ret].tel);
	printf("请输入新的地址:\n");
	scanf("%s", con->arr[ret].addr);

	printf("修改成功!\n");
}

在这里插入图片描述


3.5 查找联系人

我们可以延用之前写好的根据联系人姓名来查找联系人的find_by_name函数。

//通讯录查找
void contact_find(contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人姓名:\n");
	scanf("%s", name);
	int ret = find_by_name(con, name);
	if (ret < 0)
	{
		printf("您要查找的联系人不存在!\n");
		return;
	}
	printf("%2s %8s %8s %8s %8s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("———      ———      ———      ———      ———\n");
	printf("%2s %7s %7d %9s %9s\n", con->arr[ret].name,
		con->arr[ret].gender,
		con->arr[ret].age,
		con->arr[ret].tel,
		con->arr[ret].addr);
}

请添加图片描述


4、通讯录菜单

在实现完通讯录的相关操作后,我们接着制作一个简易菜单。
这个方法我们以前使用过多次了,这里就不再赘述。
其中枚举类型定义在头文件contact.h中。

#include "seqlist.h"

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

int main()
{
	int input = 0;
	contact con;
	contact_init(&con);
	do
	{
		menu();
		printf("请选择您的操作:");
		scanf("%d", &input);
		switch (input)
		{
		case EXIT:
			printf("退出通讯录!\n");
			break;
		case ADD:
			contact_add(&con);
			break;
		case DELETE:
			contact_delete(&con);
			break;
		case MODIFY:
			contact_modify(&con);
			break;
		case FIND:
			contact_find(&con);
			break;
		case SHOW:
			contact_show(&con);
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);

	//销毁通讯录
	contact_destroy(&con);

	return 0;
}

5、通讯录项目代码

seqlist.h:

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "contact.h"

//顺序表管理数据的类型
//typedef int sl_data_type;
typedef peoinfo sl_data_type;

//动态顺序表
typedef struct seqlist
{
	sl_data_type* arr;
	int size;//数据个数
	int capacity;//空间大小
}SL;

//顺序表初始化
void sl_init(SL* ps);
//头插
void sl_push_front(SL* ps, sl_data_type x);
//尾插
void sl_push_back(SL* ps, sl_data_type x);
//在指定位置之前插入数据
void sl_insert(SL* ps, int pos, sl_data_type x);
//头删
void sl_pop_front(SL* ps);
//尾删
void sl_pop_back(SL* ps);
//删除指定位置的数据
void sl_erase(SL* ps, int pos);
//顺序表的查找
int sl_find(SL* ps, sl_data_type x);
//顺序表打印
void sl_print(const SL sl);
//顺序表销毁
void sl_destroy(SL* ps);

seqlist.c:

#define  _CRT_SECURE_NO_WARNINGS

#include "seqlist.h"

void sl_init(SL* ps)
{
	ps->arr = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

//检查是否有空间允许插入数据
void check_capacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//为了处理capacity为0的问题
		sl_data_type* tmp = (sl_data_type*)realloc(ps->arr, newcapacity * sizeof(sl_data_type));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		tmp = NULL;
		ps->capacity = newcapacity;//及时更新空间大小
	}
}

void sl_push_front(SL* ps, sl_data_type x)
{
	assert(ps != NULL);
	check_capacity(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 sl_push_back(SL* ps, sl_data_type x)
{
	assert(ps != NULL);
	check_capacity(ps);
	ps->arr[ps->size++] = x;
}

void sl_insert(SL* ps, int pos, sl_data_type x)
{
	assert(ps != NULL);
	assert(pos >= 0 && pos <= ps->size);//确保指定的位置是有效的
	check_capacity(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 sl_pop_front(SL* ps)
{
	assert(ps != NULL);
	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 sl_pop_back(SL* ps)
{
	assert(ps != NULL);
	assert(ps->size != 0);//顺序表为空不能删除
	ps->size--;
}

void sl_erase(SL* ps, int pos)
{
	assert(ps != NULL);
	assert(ps->size != 0);//实际下面的断言侧面完成了这句代码
	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 sl_find(SL* ps, sl_data_type x)
//{
//	assert(ps != NULL);
//	int i = 0;
//	for (i = 0; i < ps->size; i++)
//	{
//		if (ps->arr[i] == x)
//		{
//			return i;
//		}
//	}
//	return -1;
//}


//void sl_print(const SL sl)
//{
//	int i = 0;
//	for (i = 0; i < sl.size; i++)
//	{
//		printf("%d ", sl.arr[i]);
//	}
//	printf("\n");
//}

void sl_destroy(SL* ps)
{
	assert(ps != NULL);
	if (ps->arr != NULL)//动态内存函数开辟了空间
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

contact.h:

#pragma once

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

enum contact
{
	EXIT,
	ADD,
	DELETE,
	MODIFY,
	FIND,
	SHOW
};

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

//给顺序表改一个名字
typedef struct seqlist contact;//前置声明

//通讯录的初始化
void contact_init(contact* con);
//通讯录的销毁
void contact_destroy(contact* con);
//通讯录添加数据
void contact_add(contact* con);
//通讯录删除数据
void contact_delete(contact* con);
//通讯录修改
void contact_modify(contact* con);
//通讯录查找
void contact_find(contact* con);
//通讯录数据展示
void contact_show(contact* con);

contact.c:

#define  _CRT_SECURE_NO_WARNINGS

#include "contact.h"
#include "seqlist.h"
#include <string.h>

//通讯录的初始化
void contact_init(contact* con)
{
	//通讯录的初始化实际就是顺序表的初始化
	sl_init(con);
}

//通讯录的销毁
void contact_destroy(contact* con)
{
	sl_destroy(con);
}

//通讯录添加数据
void contact_add(contact* con)
{
	//获取用户输入的信息
	//将用户输入的信息存到结构体变量中
	peoinfo info;
	printf("请输入要添加的联系人姓名:\n");
	scanf("%s", info.name);
	printf("请输入要添加的联系人性别:\n");
	scanf("%s", info.gender); 
	printf("请输入要添加的联系人年龄:\n");
	scanf("%d", &info.age);
	printf("请输入要添加的联系人电话:\n");
	scanf("%s", info.tel);
	printf("请输入要添加的联系人地址:\n");
	scanf("%s", info.addr);

	//将结构体数据插入到通讯录(顺序表)中
	sl_push_back(con, info);
	printf("联系人添加成功!\n");
}

int find_by_name(contact* con, char name[])
{
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->arr[i].name, name))
		{
			//找到了
			return i;
		}
	}
	return -1;
}

//通讯录删除数据
void contact_delete(contact* con)
{
	//前提是要删除的这个联系人存在
	char name[NAME_MAX];
	printf("请输入您想删除的联系人姓名:\n");
	scanf("%s", name);
	int ret = find_by_name(con, name);
	if (ret < 0)
	{
		printf("联系人不存在!\n");
		//直接返回
		return;
	}
	
	//删除指定位置的数据
	sl_erase(con, ret);
	printf("删除成功!\n");
}

//通讯录数据展示
void contact_show(contact* con)
{
	//打印表头
	printf("%2s %8s %8s %8s %8s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("———      ———      ———      ———      ———\n");
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		printf("%2s %7s %7d %9s %9s\n", con->arr[i].name,
			con->arr[i].gender,
			con->arr[i].age,
			con->arr[i].tel,
			con->arr[i].addr);
	}
}

//通讯录修改
void contact_modify(contact* con)
{
	//前提是要修改的联系人存在
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", name);
	int ret = find_by_name(con, name);
	if (ret < 0)
	{
		printf("联系人不存在!\n");
		return;
	}

	//修改指定位置的数据
	printf("请输入新的姓名:\n");
	scanf("%s", con->arr[ret].name);
	printf("请输入新的性别:\n");
	scanf("%s", con->arr[ret].gender);
	printf("请输入新的年龄:\n");
	scanf("%d", &con->arr[ret].age);
	printf("请输入新的电话:\n");
	scanf("%s", con->arr[ret].tel);
	printf("请输入新的地址:\n");
	scanf("%s", con->arr[ret].addr);

	printf("修改成功!\n");
}

//通讯录查找
void contact_find(contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人姓名:\n");
	scanf("%s", name);
	int ret = find_by_name(con, name);
	if (ret < 0)
	{
		printf("您要查找的联系人不存在!\n");
		return;
	}
	printf("%2s %8s %8s %8s %8s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("———      ———      ———      ———      ———\n");
	printf("%2s %7s %7d %9s %9s\n", con->arr[ret].name,
		con->arr[ret].gender,
		con->arr[ret].age,
		con->arr[ret].tel,
		con->arr[ret].addr);
}

test.c:

#define  _CRT_SECURE_NO_WARNINGS

#include "seqlist.h"

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

int main()
{
	int input = 0;
	contact con;
	contact_init(&con);
	do
	{
		menu();
		printf("请选择您的操作:");
		scanf("%d", &input);
		switch (input)
		{
		case EXIT:
			printf("退出通讯录!\n");
			break;
		case ADD:
			contact_add(&con);
			break;
		case DELETE:
			contact_delete(&con);
			break;
		case MODIFY:
			contact_modify(&con);
			break;
		case FIND:
			contact_find(&con);
			break;
		case SHOW:
			contact_show(&con);
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);

	//销毁通讯录
	contact_destroy(&con);

	return 0;
}

总结

  • 通讯录其实就是顺序表,只是上文的顺序表存储的是整型数据,而本文的顺序表存储的结构体类型数据而已
  • 在本篇文章中我们更多的是对保存联系人信息的结构体类型进行相应的操作,通讯录实际上就是顺序表,而顺序表的相关操作是我们已经实现好了的,所以我们只需要拿来用就可以了
  • 通讯录就像是在顺序表的外面又包装了一层其他的操作,使其完成对联系人信息的增删查改操作

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

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

相关文章

堆排序的实现原理

一、什么是堆排序&#xff1f; 堆排序就是将待排序元素以一种特定树的结构组合在一起&#xff0c;这种结构被称为堆。 堆又分为大根堆和小根堆&#xff0c;所谓大根堆即为所有的父节点均大于子节点&#xff0c;但兄弟节点之间却没有什么严格的限制&#xff0c;小根堆恰恰相反&a…

使用Scala爬取安居客房产信息并存入CSV文件

使用Scala爬取安居客房产信息并存入CSV文件 本篇博客中&#xff0c;我们将介绍如何使用Scala语言编写一个简单的程序&#xff0c;来爬取安居客&#xff08;Anjuke&#xff09;网站上的房产信息&#xff0c;并将这些信息存储到CSV文件中。这个示例将涵盖HTTP请求、HTML解析、数…

掌握 Nuxt 3 中的状态管理:实践指南

title: 掌握 Nuxt 3 中的状态管理&#xff1a;实践指南 date: 2024/6/22 updated: 2024/6/22 author: cmdragon excerpt: 摘要&#xff1a;该文指南详述了Nuxt 3的概况与安装&#xff0c;聚焦于在Nuxt 3框架下运用Vuex进行高效的状态管理&#xff0c;涵盖基础配置、模块化实…

以太坊==给合约转入/查询合约剩余/合约转给某账户/结构体/MAP

转入 必须要定义该函数&#xff0c;或者定义fallback // 接收以太币 receive() external payable {} // Corrected Line // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;contract SimpleStorage {uint256 private storedData;// 事件&#xff0c;用于通知数据变更e…

使用 GitOps 进行防灾 MinIO

想象一下&#xff0c;您已经花费了无数小时来完善 Docker Swarm 设置&#xff0c;精心设计每项服务&#xff0c;并调整 CI/CD 管道以实现无缝自动化。现在&#xff0c;想象一下这个经过微调的系统被重置为原点&#xff0c;不是因为严重的故障或安全漏洞&#xff0c;而是因为数据…

并行计算之SIMD与SPMD

SIMD (Single Instruction Multiple Data) SIMD&#xff0c;也就是单指令多数据计算&#xff0c;一条指令可以处理多个数据。通过向量寄存器存储多个数据元素&#xff0c;并使用单条指令同时对这些数据元素进行处理&#xff0c;从而提高了计算效率。 代码示例&#xff1a; fl…

数据库设计概述-数据库设计内容、数据库设计方法(基于E-R模型的规范设计方法)

一、引言 如何利用关系数据库理论设计一个满足应用系统需求的数据库 二、数据库设计内容 1、数据库设计是基于应用系统需求分析中对数据的需求&#xff0c;解决数据的抽象、数据的表达和数据的存储结构等问题 2、其目标是设计出一个满足应用要求、简洁、高效、规范合理的数…

昇思25天学习打卡营第4天|数据变换(Transforms)

一、简介&#xff1a; 数据变换是指将已有的数据转换成可以提供给模型直接训练和验证的数据格式&#xff0c;在深度学习中一般被称为数据预处理&#xff0c;之前在昇思25天学习打卡营第3天|数据集Dataset-CSDN博客 介绍数据集的时候已经有了一个简单的使用&#xff0c;下面将具…

mac赛车竞速游戏:弯道卡丁车车手 for Mac 中文版下载

《弯道卡丁车车手》是一款刺激的卡丁车竞速游戏&#xff0c;玩家扮演的是赛道上的卡丁车车手&#xff0c;需要在曲线崎岖的赛道上驾驶卡丁车&#xff0c;与其他车手展开激烈的竞速比赛。 游戏中有多种赛道可以选择&#xff0c;每个赛道都有不同的难度和特点&#xff0c;玩家需…

双例集合(三)——双例集合的实现类之TreeMap容器类

Map接口有两个实现类&#xff0c;一个是HashMap容器类&#xff0c;另一个是TreeMap容器类。TreeMap容器类的使用在API上于HashMap容器类没有太大的区别。它们的区别主要体现在两个方面&#xff0c;一个是底层实现方式上&#xff0c;HashMap是基于Hash算法来实现的吗&#xff0c…

Apple - Advanced Memory Management Programming Guide 内存管理

翻译整理自&#xff1a;Advanced Memory Management Programming Guide&#xff08;Updated: 2012-07-17 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html#//apple_ref/doc/uid/10000011i 文章目录 一、关于…

算法题--华为od机试考试(整数对最小和、素数之积、找城市)

目录 整数对最小和 题目描述 注意 输出描述 示例1 输入 输出 说明 解析 答案 素数之积 题目描述 输入描述 输出描述 示例1 输入 输出 说明 示例2 输入 输出 说明 解析 找城市 题目描述 输入 输出 示例1 输入 输出 示例2 输入 输出 说明 解析…

嵌入式通信协议-----UART协议详解(基于智芯Z20k11X)

目录 一、简介 1.概念 2.结构 3.特点 4.优缺点 二、协议帧组成 1.起始位 2.数据位 3.奇偶校验位 4.停止位 三、UART通信过程 四、USART与UART区别 五、代码实现 1.硬件框图 2.软件实现 一、简介 1.概念 USART&#xff08;Universal Synchronous Asynchronous R…

相机的标定

文章目录 相机的标定标定步骤标定结果影响因素参数分析精度提升一、拍摄棋盘格二、提升标定精度 标定代码实现 相机的标定 双目相机的标定是确保它们能够准确聚焦和成像的关键步骤。以下是详细的标定步骤和可能的结果&#xff0c;同时考虑了不同光照条件和镜头光圈大小等因素对…

怎样去掉卷子上的答案并打印

当面对试卷答案的问题时&#xff0c;一个高效而简单的方法是利用图片编辑软件中的“消除笔”功能。这种方法要求我们首先将试卷拍摄成照片&#xff0c;然后利用该功能轻松擦除答案。尽管这一方法可能需要些许时间和耐心&#xff0c;但它确实为我们提供了一个可行的解决途径。 然…

Docker网络介绍

网络是虚拟化技术中最复杂的部分&#xff0c;也是Docker应用中的一个重要环节。 Docker中的网络主要解决容器与容器、容器与外部网络、外部网络与容器之间的互相通信的问题。 这些复杂情况的存在要求Docker有一个强大的网络功能去保障其网络的稳健性。因此&#xff0c;Docker…

windows10远程桌面端口,Windows 10远程桌面端口修改的两个方法

在Windows 10系统中&#xff0c;远程桌面功能允许用户通过网络从一台计算机远程访问和控制另一台计算机。默认情况下&#xff0c;远程桌面服务使用的端口是3389。然而&#xff0c;出于安全考虑&#xff0c;许多管理员和用户希望修改这一默认端口。本指南将详细介绍如何在Window…

柯桥商务英语培训|老外和你说Tom和Jack,可不是在说人名!所以是啥意思?

小明和小李&#xff0c;这两个人在中国相信没有谁不认识他们了。而且有关他们的梗更是传遍大街小巷。 例如&#xff1a;小明他爷爷活了103岁&#xff0c;小明做数学题&#xff0c;又或者是小李的老婆比小明小2岁等等。 其实在国外&#xff0c;也有这么两个人像小明、小李一样&a…

WPF/C#:显示分组数据的两种方式

前言 本文介绍自己在遇到WPF对数据进行分组显示的需求时&#xff0c;可以选择的两种方案。一种方案基于ICollectionView&#xff0c;另一种方案基于IGrouping。 基于ICollectionView实现 相关cs代码&#xff1a; [ObservableProperty] private ObservableCollection<Peo…

【mysql】常用操作:维护用户/开启远程/忘记密码/常用命令

一、维护用户 1.1 创建用户 -- 语法 > CREATE USER [username][host] IDENTIFIED BY [password];-- 例子&#xff1a; -- 添加用户user007&#xff0c;密码123456&#xff0c;并且只能在本地可以登录 > CREATE USER user007localhost IDENTIFIED BY 123456; -- 添加用户…