通讯录(顺序表实现)


  • 点击表格内对应链接跳转对应内容⬇️⬇️⬇️
作者主页 吃透C语言专栏 数据结构 Gitee仓库

文章目录

SeqList.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
//顺序表初始化
void SLInit(SL* ps)
{
	ps -> arr = NULL;
	ps->capacity = ps->size = 0;
}

//顺序表销毁
void SLDestroy(SL* ps)
{
	assert(ps);
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

//顺序表扩容
void SLCheckCapacity(SL* ps)
{
	if (ps->capacity == ps->size)
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * sizeof(ps->capacity);
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));

		//扩容失败
		if (tmp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		//扩容成功
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
}
//顺序表打印
//void SLPrint(SL* ps)
//{
//	for (int i = 0; i < ps->size; i++)
//	{
//		printf("%d ", ps->arr[i]);
//	}
//	printf("\n");
//}

//顺序表头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);//传进来的不能为NULL
	SLCheckCapacity(ps);
	for (int i = ps ->size;i > 0;i--)
	{
		ps->arr[i] = ps->arr[i-1];
	}
	ps->arr[0] = x;
	ps->size++;
}

//顺序表尾插
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
	
}


//顺序表头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 1;i < ps ->size;i++  )
	{
		ps->arr[i - 1] = ps->arr[i];
	}
	ps->size--;
}

//顺序表尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);

	ps->size--;
}

//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	if (pos >= 0 && pos <= ps->size)
	{
		for (int 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->size);
	if (pos >= 0 && pos < ps->size)
	{
		for (int i = pos;i<ps ->size - 1;i++)
		{
			ps->arr[i] = ps->arr[i + 1];
		}
	}
	ps->size--;
}

//顺序表中查找x
//int SLFind(SL* ps, SLDataType x)
//{
//	assert(ps);
//	for (int i = 0; i < ps->size; i++)
//	{
//		if (ps->arr[i] == x)
//		{
//			return i;
//		}
//
//	}
//	return -1;
//}

SeqList.h

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"Contact.h"//需要里面定义的结构体数据类型

//动态顺序表
typedef Info SLDataType;//重命名这个顺序表里面元素的类型
typedef struct SeqList
{
	SLDataType* arr;//动态内存空间的地址:指针变量
	int capacity;//顺序表的大小
	int size;//顺序表实际存储的元素的个数
}SL;

//顺序表初始化
void SLInit(SL* ps);//只能传址调用,因为这个函数实现的就是初始化,在这之前顺序表没有初始化,无法进行传值调用

//顺序表头插和尾插
void SLPushFront(SL* ps,SLDataType x);
void SLPushBack(SL* ps, SLDataType x);

//顺序表的头删和尾删
void SLPopFront(SL* ps);
void SLPopBack(SL* ps);

//指定位置之前插入数据
void SLInsert(SL* ps,int pos,SLDataType x);

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

//顺序表销毁
void SLDestroy(SL* ps);

//顺序表打印
void SLPrint(SL* ps);

//顺序表中查找x
//int SLFind(SL* ps, SLDataType x);

Contact.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"//数据类型是结构体,定义在Contact.h里面
#include"SeqList.h"//需要里SeqList.h面已经实现好了的函数

int FindByName(Contact* pcon, char name[]);

//初始化函数
void ContactInit(Contact* pcon)
{
	SLInit(pcon);
}
//销毁函数
void ContactDesTroy(Contact* pcon)
{
	SLDestroy(pcon);
}


//修改操作函数
void ContactModify(Contact* pcon)
{
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", name);
	int findIndex = FindByName(pcon, name);
	if (findIndex < 0)
	{
		printf("要修改的联系人不存在!\n");
		return;
	}
	//找到了执行修改操作
	printf("请输入姓名:\n");
	scanf("%s", pcon->arr[findIndex].name);
	printf("请输入年龄:\n");
    scanf("%d", &pcon->arr[findIndex].age);
	printf("请输入性别:\n");
	scanf("%s", pcon->arr[findIndex].gender);
	printf("请输入电话:\n");
	scanf("%s", pcon->arr[findIndex].tel);
	printf("请输入地址:\n");
	scanf("%s", pcon->arr[findIndex].addr);

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


//增加函数
void ContactAdd(Contact* pcon)
{
    //底层调用的是之前顺序表尾插函数,把数据保存到realloc开辟的空间
	//之前存的数据类型是整型,这次存的类型是结构体
	
	//创建通讯录中的数据结构体变量
	Info info;
	printf("请输入联系人姓名:\n");
	scanf("%s", info.name);
	printf("请输入联系人年龄: \n");
	scanf("%d",&info.age);
	printf("请输入联系人性别:\n");
	scanf("%s", info.gender);
	printf("请输入联系人电话:\n");
	scanf("%s", info.tel);
	printf("请输入联系人地址:\n");
	scanf("%s", info.addr);

	//把创建好的联系人结构体数据变量作为数据,调用尾插函数,realloc函数开辟一个个结构体变量空间
	SLPushBack(pcon, info);
	   //void SLCheckCapacity(SL * ps)
	//{
	//	if (ps->capacity == ps->size)
	//	{
	//		int newcapacity = ps->capacity == 0 ? 4 : 2 * sizeof(ps->capacity);
	//		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));

	//		//扩容失败
	//		if (tmp == NULL)
	//		{
	//			perror("realloc");
	//			exit(1);
	//		}
	//		//扩容成功
	//		ps->arr = tmp;
	//		ps->capacity = newcapacity;
	//	}
	//}
	  // void SLPushBack(SL * ps, SLDataType x)
   //{
	  // assert(ps);
	  // SLCheckCapacity(ps);
	  // ps->arr[ps->size] = x;
	  // ps->size++;
   //}


}

//删除 修改 查找 查看 都需要指定成员是,删除删哪个的结构体数据,修改改哪个的结构体数据,查找找哪个的结构体数据,结构体中是按成员存放数据的
// 这个操作都需要通过指定一个成员,来定位到这个成员的结构体数据,而不是直接定位结构体,结构体是复合型,无法直接定位
//通过名字寻找
int FindByName(Contact* pcon,char name[])
{
	for (int i = 0; i < pcon->size; i++)
	{
		if(strcmp(pcon->arr[i].name, name) == 0)
		{
			//相等的话,strucmp返回值为0
			return i;//找到了对应名字的结构体数据的下标
		}
	}
	//没找到
	return -1;

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


//查找函数
void ContactFind(Contact* pcon)
{
	char name[NAME_MAX];
	scanf("%s", name);

	int findIndex = FindByName(pcon, name);
		if (findIndex < 0)
		{
			printf("该联系人不存在!");
			return;
		}
	//找到了,就打印该联系人的信息

	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("%s %s %d %s %s   \n ",
		pcon->arr[findIndex].name,
		pcon->arr[findIndex].gender,
		pcon->arr[findIndex].age,
		pcon->arr[findIndex].tel,
		pcon->arr[findIndex].addr
		);

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


//对已经存在了的数据操作,第一步就是找到这个数据,比如我要操作的数据是1,或者我操作的数据是nmae,
//想要操作这个数据,就要找到这个数据,找到了这个数据,就可以在这个数据的存放位置操作这个数据

Contact.h

c 复制代码
#pragma once

#define _CRT_SECURE_NO_WARNINGS 1
#define NAME_MAX 100
#define GENDER_MAX 10
#define TEL_MAX 12
#define ADDR_MAX 10
//通讯录数据类型
typedef struct PersonInfo
{
	char name[NAME_MAX];//名字
	int age;//年龄
	char gender[GENDER_MAX];//性别
	char tel[TEL_MAX];//电话
	char addr[ADDR_MAX];//地址
}Info;

//这个通讯录的本质就是顺序表,只是之前顺序表存的是整型元素,通讯录里面存的是结构体元素

//所以我们要使用之前的顺序表就要声明顺序表这个结构体的类型,就可以使用这个顺序表结构体了,和函数声明一样的原理
struct SeqList;
//需要SeqList.h里面定义的顺序表,因为要给顺序表结构改名为通讯录
//但是这个结构需要contact.h里面定义的数据,所以seqlist.h里面包含了contact.h所以contact.h想给顺序表结构体改名
//就不能包含它对应的头文件了,想用这个结构体,可以声明


typedef struct SeqList Contact;//把顺序表的结构体改个名字叫通讯录

//通讯录操作函数
//把对通讯录这个结构体的操作功能封装在函数里面

//通讯录的初始化
void ContactInit(Contact* pcon);
//通讯录的销毁
void ContactDesTroy(Contact* pcon);

//增加操作函数
void ContactAdd(Contact* pcon);
//删除操作函数
void ContactDel(Contact* pcon);
//修改操作函数
void ContactModify(Contact* pcon);
//查找操作函数
void ContactFind(Contact* pcon);
//查看通讯操作函数
void ContactShow(Contact* pcon);

Contest.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
//#include"Contact.h"在SeqList.h中已经包含了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 op = -1;
	//Contact 只是通讯录的类型,用这个类型创建一个通讯录结构体变量才是创建一个可以操作的通讯录,因为这个通讯录有了空间
	Contact con;
	ContactInit(&con);
	do
	{
		menu();
		printf("请选择你的操作:\n");
		scanf("%d", &op);
		switch (op)
		{
		case 1:
			//添加联系人
			ContactAdd(&con);
			break;
		case 2:
			//删除联系人
			ContactDel(&con);
			break;
		case 3:
			//修改联系人
			ContactModify(&con);
			break;
		case 4:
			//查找联系人
			ContactFind(&con);
			break;
		case 5:
			//查看通讯录
			ContactShow(&con);
			break;
		case 0:
			//退出
			printf("退出成功!");
			break;
		defult:
			printf("输入错误,请重新选择。。。");
			break;

		}

	} while (op);
	//不需要操作通讯录以后,退出选择,执行销毁操作函数
	ContactDesTroy(&con);
	return 0;
}

通讯录定义

定义:通讯录就是限定了存储的数据类型为结构体的的顺序表,之前我们实现的顺序表存的数据类型是内置类型整型,现在我们把存的数据变成自定义类型结构体,每一个成员都存储不同的数据,如姓名,年龄,性别,电话,地址,等信息


解析:也就是把realloc开辟的空间返回的地址转化成结构体类型的地址,这样通过这个结构体的指针变量就可以访问一个个结构体大小的空间,而这一个个结构体大小的空间,就是通讯录的联系人


所以通讯录就是顺序表中存储的数据指定为结构体类型


通讯录解析

文件 作用
Contest.c 调用通讯录操作函数,使用我们的通讯录,创建一个通讯录
Contact.h 包含能用到的头文件,已经声明我们的操作函数 ,实现通讯录数据的基本结构
Contact.c 通讯录操作函数的具体实现,也就是增删查改功能的实现

Contest.c文件解析

c 复制代码
int main()
{
	int op = -1;
	//Contact 只是通讯录的类型,用这个类型创建一个通讯录结构体变量才是创建一个可以操作的通讯录,因为这个通讯录有了空间
	Contact con;
	ContactInit(&con);
	do
	{
		menu();
		printf("请选择你的操作:\n");
		scanf("%d", &op);
		switch (op)
		{
		case 1:
			//添加联系人
			ContactAdd(&con);
			break;
		case 2:
			//删除联系人
			ContactDel(&con);
			break;
		case 3:
			//修改联系人
			ContactModify(&con);
			break;
		case 4:
			//查找联系人
			ContactFind(&con);
			break;
		case 5:
			//查看通讯录
			ContactShow(&con);
			break;
		case 0:
			//退出
			printf("退出成功!");
			break;
		defult:
			printf("输入错误,请重新选择。。。");
			break;

		}

	} while (op);
	//不需要操作通讯录以后,退出选择,执行销毁操作函数
	ContactDesTroy(&con);
	return 0;xiang
代码 解析
Contact con 根据通讯录结构体类型,创建通讯录结构体变量,给通讯录结构体类型申请空间
op = -1 同时作为do while 循环的判断条件 和 switch 语句的选项 ,把switch 语句设置在 do while 循环,进入do while 循环先打印菜单,然后输入op,设置通讯录操作都为非零,只有退出通讯录操作为0,这样op的值只要非零就一直执行对通讯录的增删查改操作,如果op的值为0的话 do while 循环判断为假,直接退出循环,也无法进行通讯录操作了
break case 只是进入switch 选项的入口,如果需要退出这个选项的话,只能通过break退出,否则进入这个选项了以后就会一直执行选项下的操作,直到遇到break才会退出

Contact.h 文件解析

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#define NAME_MAX 100
#define GENDER_MAX 10
#define TEL_MAX 12
#define ADDR_MAX 10
//通讯录数据类型
typedef struct PersonInfo
{
	char name[NAME_MAX];//名字
	int age;//年龄
	char gender[GENDER_MAX];//性别
	char tel[TEL_MAX];//电话
	char addr[ADDR_MAX];//地址
}Info;

定义通讯录数据类型,把通讯录数据类型也就是这个结构体重命名为 Info 方便我们待会使用通讯录中的数据类型。而每个成员的大小我们可以设置一个宏,这样方便我们之后修改成员大小,以及直观看出成员大小


c 复制代码
struct SeqList;
typedef struct SeqList Contact;
//通讯录的初始化
void ContactInit(Contact* pcon);
//通讯录的销毁
void ContactDesTroy(Contact* pcon);

//增加操作函数
void ContactAdd(Contact* pcon);
//删除操作函数
void ContactDel(Contact* pcon);
//修改操作函数
void ContactModify(Contact* pcon);
//查找操作函数
void ContactFind(Contact* pcon);
//查看通讯操作函数
void ContactShow(Contact* pcon);

我们需要把顺序表这个结构体改名为通讯录,但是顺序表定义在的SeqList.h文件需要Contact.h文件中的数据类型,所以SeqList.h已经包含了Contact.h这个文件,如果Contact.h这个文件再包含SeqList.h的话就会导致头文件重复包含,所以我们只是想把顺序表结构体改名的话,可以声明结构体类型然后进行改名,不用包含头文件,包含头文件拿到的是这整个结构体,包括结构体的成员,但是声明的话,只能看到这个结构体的类型,我们需要把类型重命名的话,使用结构体声明就行了。


其余就是对操作函数的声明


Contact.c

c 复制代码
#include"Contact.h"//数据类型是结构体,定义在Contact.h里面
#include"SeqList.h"//需要里SeqList.h面已经实现好了的函数

int FindByName(Contact* pcon, char name[]);

//初始化函数
void ContactInit(Contact* pcon)
{
	SLInit(pcon);
}
//销毁函数
void ContactDesTroy(Contact* pcon)
{
	SLDestroy(pcon);
}
要点 解析
#include"Contact.h"和#include"SeqList.h" 实现这个操作函数需要通讯录类型的结构体,因为,类型是在Contact.h文件中重命名的,而通讯录操作函数中有些函数底层调用嵌套的就是顺序表中的函数,所以需要包含SeqList.h文件
初始化函数 函数接收通讯录地址,也就是顺序表改名的结构体的地址,再函数内调用之前实现好了的SLInit函数实现对通讯录的初始化
销毁函数 同上一样,通讯录也就是顺序表,结构体类型完全一样只有里面成员指针类型不一样,但是并不影响调用,因为参数部分都是同一个结构体类型,都是sl改名后的contact类型的结构体,

c 复制代码
typedef Info SLDataType;//重命名这个顺序表里面元素的类型
typedef struct SeqList
{
	SLDataType* arr;//动态内存空间的地址:指针变量
	int capacity;//顺序表的大小
	int size;//顺序表实际存储的元素的个数
}SL;
c 复制代码
void ContactAdd(Contact* pcon)
{
    //底层调用的是之前顺序表尾插函数,把数据保存到realloc开辟的空间
	//之前存的数据类型是整型,这次存的类型是结构体
	
	//创建通讯录中的数据结构体变量
	Info info;
	printf("请输入联系人姓名:\n");
	scanf("%s", info.name);
	printf("请输入联系人年龄: \n");
	scanf("%d",&info.age);
	printf("请输入联系人性别:\n");
	scanf("%s", info.gender);
	printf("请输入联系人电话:\n");
	scanf("%s", info.tel);
	printf("请输入联系人地址:\n");
	scanf("%s", info.addr);

	//把创建好的联系人结构体数据变量作为数据,调用尾插函数,realloc函数开辟一个个结构体变量空间
	SLPushBack(pcon, info);

增加函数:接收通讯录结构体的地址,其实调用的依然是SLPushBack尾插操作函数,把整个结构体变量放入动态内存中。尾插的时候要进行扩容,按照存放的数据类型进行2倍扩容,所以我们之前定义的SLDtaeType数据类型就改成了Info结构体数据类型,尾插函数进行的操作就是把一整个结构体变量插入尾部。之前的尾插是通过结构体地址,找到存放空间地址,把第二个参数中的整型插入进去,之前的第二个参数整型是直接写在实参部分,因为内置类型整型可以直接写出来,但是现在尾插插入的数据是一个结构体,不能直接写在参数部分,只能接收一个结构体变量,然后再把这个结构体变量整个插入到动态内存的空间中,所以我们增加函数在调用尾插函数之前还有一个操作就是写尾插函数的第二个参数也就是通讯录成员,所以我们创建一个结构体变量,用的就是之前定义好的通讯录成员的结构体类型,用scanf对对应的成员空间赋值以后,把整个结构体变量作为SLPushBack的第二个参数,也就是尾插的数据,放入动态内存的空间中,这样每调用一次增加函数,我们就可以输入我们想要存放的通讯录成员,然后把这个结构体变量通过尾插函数整个插入我们的动态内存空间中


c 复制代码
//删除 修改 查找 查看 都需要指定成员是,删除删哪个的结构体数据,修改改哪个的结构体数据,查找找哪个的结构体数据,结构体中是按成员存放数据的
// 这个操作都需要通过指定一个成员,来定位到这个成员的结构体数据,而不是直接定位结构体,结构体是复合型,无法直接定位
//通过名字寻找
int FindByName(Contact* pcon,char name[])
{
	for (int i = 0; i < pcon->size; i++)
	{
		if(strcmp(pcon->arr[i].name, name) == 0)
		{
			//相等的话,strucmp返回值为0
			return i;//找到了对应名字的结构体数据的下标
		}
	}
	//没找到
	return -1;

 }

和之前的顺序表一样如果要删除修改或者查找,我们需要传入需要查找的对象,也就是结构体中的成员,之前顺序表中查找存放的整型数据的时候,只要直接输入想要查找的整型然后进行匹配即可,但是现在我们存放的数据类型是结构体类型,这样一个复合类型想查找只能查找里面的成员,所以我们要指定一个成员作为查找方式,在这里我们选择姓名这个字符数组成员作为查找的方式,需要寻找哪个结构体通讯数据,就通过查找每个结构体中的姓名字符数组定位到这个结构体数据的下标即可


所以函数通过两个参数,一个为通讯录指针,一个为数组首元素地址,通过for循环中变动的i作为strcmp函数中不断遍历下标 i 对应的结构体数据中的name成员来匹配我们输入的字符串name,直到遇到匹配成功的字符串 strcmp 函数的返回值为0 符合 if 判断条件,判断条件为真,返回匹配位置的结构体的下标,如果没找到的话返回-1用来待会使用FindByName函数的时候通过判断返回值来确定是否查找到该结构体成员。


c 复制代码
删除函数
void ContactDel(Contact* pcon)
{
	printf("请输入要删除的联系人的姓名:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int findIndex = FindByName(pcon, name);
	if (findIndex < 0)
	{
		printf("要删除的联系人不存在!");
		return;
	}
	SLErase(pcon, findIndex);
	printf("联系人删除成功!\n");
}


查找函数
void ContactFind(Contact* pcon)
{
	char name[NAME_MAX];
	scanf("%s", name);

	int findIndex = FindByName(pcon, name);
		if (findIndex < 0)
		{
			printf("该联系人不存在!");
			return;
		}
	//找到了,就打印该联系人的信息

	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("%s %s %d %s %s   \n ",
		pcon->arr[findIndex].name,
		pcon->arr[findIndex].gender,
		pcon->arr[findIndex].age,
		pcon->arr[findIndex].tel,
		pcon->arr[findIndex].addr
		);

}
查看函数
void ContactShow(Contact* pcon)
{
	for (int i = 0; i < pcon->size; i++)
	{
		printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf("%s %s %d %s %s   \n ",
			pcon->arr[i].name,
			pcon->arr[i].gender,
			pcon->arr[i].age,
			pcon->arr[i].tel,
			pcon->arr[i].addr
		);
	}
}
函数 解析
删除函数 void ContactDel(Contact* pcon) 删除函数最后调用的依然是 SLErase 函数。SLErase函数也就是顺序表中的指定位置删除数据函数,通过传进来的结构体类型找到对应的数据类型的指针变量,指针变量再通过函数的第二个参数也就是对应数据的下标,找到对应的数据把其后面的数据往前挪覆盖这个数据达到删除的效果。所以删除函数的作用就是创建一个字符数组让用户输入一个字符串存入该字符数组作为FindByName的第二个参数,通过判断FindByName的返回值是否小于0判断是否调用删除函数,如果小于0则说明查找的name不存在则直接退出函数不进行删除,如果不为0返回的就是对应的结构体数据的下标,把其赋给SLErase函数通过对应的下标找到对应的结构体数据删除该结构体数据
查找函数 void ContactFind(Contact* pcon) 查找函数不需要调用之前的顺序表查找函数了,因为通讯录中的数据类型变成了结构体类型,需要访问成员,查找成员,而不是顺序表中的整型直接可以查找,所以我们直接调用FindByName函数通过返回值来判断是否找到对应的成员name找到返回对应下标没找到返回-1,找到以后通过返回的下标去访问对应的结构体数据中的成员,并打印出来
查看函数 void ContactShow(Contact* pcon) 查看函数就是打印出来整个realloc开辟的的空间存入的所有结构体数据,通过 for 循环遍历整个存储空间把每一个下标对应的结构体数据打印出来

算法题

移除元素

c 复制代码
int removeElement(int* nums, int numsSize, int val) {
  int a = 0;
  int b = 0;
  while(a<numsSize)
  {
    if(nums[a] == val)
  {
    a++;
  }   
  else
  {
    nums[b++] = nums[a++];
  }
  }
  return b;
}

解析:需要也就是要在数组中删除val ,最后只打印非val的值,我们的思路既然最后只打印非val的值,那就用一个变量a作为数组的下标匹配val,如果下标a匹配到了val就让这个变量就让a++,只有匹配到非val的值就把这个非val的值赋给变量b下标对应的元素,而b是起始元素,如果a匹配到了非val的值赋给了b那么b就++,这样,只要遇到非val的值,就一定会按照顺序一个个放到数组前面去,把a<numsSize作为while循环的条件,只要a 没匹配到数组结尾就一直匹配,只有匹配到数组结尾了,说明全面非val的值都被找到了,停止循环,返回b,因为b对应的刚刚好就是非val的个数,因为放一个非val的值,b就+1,从0开始+。



合并两个有序数组

c 复制代码
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    int str = m - 1;//nums1元素比较下标
    int dest = n -1;//nums2元素比较下标
    int a = m + n - 1;//起始放置位置下标
    while(str>=0 && dest>=0)
    {
       if(nums1[str]<nums2[dest])
       {
          nums1[a--] = nums2[dest--];
       }
       else
       {
          nums1[a--] = nums1[str--];
       }
    }
       while(dest>=0)
       {
         nums1[a--] = nums2[dest--];
       }
    }

str 设置的是要被放入的数组的最后一个元素,也就是数组内最大一个元素的下标,dest 设置的是放入数组的最后一个元素的下标,a 设置的是要把元素放入的起始位置的下标,也就是str对应数组的最后一个空间的下标,从str对应的位置的元素 和 dest 对应的元素进行比较大小,也就是两个数组中最大的元素进行比较,谁大就放在被放入数组的末尾,放完之后被放入的位置-- 以及 str-- 或者 dest-- ,直到最后 str < 0 说明两个数组中最小的元素在dest这个数组中,str中最小的元素比dest 最小的元素大,所以str的元素依次往后放,放完了,str--就小于0了,但是我们的while 循环 只会把两个数组的元素比较之后把大的元素放在后面不会去管小的元素,所以当最小的元素在dest数组里面的时候,while 循环结束的时候,dest里面比str数组中最小元素小的元素不会动,所以我们要单独把dest数组中的元素放入str数组中,如果最小的元素在str的数组中的话,当dest放完的时候整个数组就排列好了,因为元素从一开始本来就是要放在str数组中的



  • 点击表格内对应链接跳转对应内容⬇️⬇️⬇️
作者主页 吃透C语言专栏 数据结构 Gitee仓库

相关推荐
不会C语言的男孩1 小时前
Linux 系统编程 · 第 1 章:Linux 系统概述
c语言·开发语言
2601_951645741 小时前
C语言环境搭建指南
c语言·编译器·开发环境·helloworld·集成开发环境
JieE2121 小时前
树与二叉树--JS实例
javascript·数据结构
To_OC1 小时前
搞懂二叉树递归遍历,我居然是从爬楼梯开始的
前端·javascript·数据结构
SongYuLong的博客1 小时前
openWRT补丁文件生成
c语言
Jerryhut2 小时前
opencv对齐算法及其应用
人工智能·opencv·算法
果丁智能2 小时前
智慧校园一卡通深度融合方案:基于超级SIM卡的手机碰一碰智能开锁技术落地实践
数据结构·人工智能·python·科技·算法·智能家居·信息与通信
满怀冰雪2 小时前
第13篇-栈算法入门-括号匹配-表达式与单调栈基础
java·算法
Irissgwe2 小时前
顺序表和链表
数据结构·c++·链表·c·顺序表·线性表