基于顺序表实现简易通讯录

目录

前言

通讯录前的准备

顺序表代码

理解通讯录与顺序表的关系

通讯录Contact.h文件

1.创建联系人信息结构体(数据类型)

2.完整代码:

通讯录Contact.c文件

1.通讯录的初始化

 2.通讯录的销毁

3.通讯录添加数据

4.通讯录删除数据

5.展示通讯录数据

6.通讯录的修改

7.查找联系人并展示其信息

使用通讯录

后记


前言

大家好鸭!这里是小鸥~

在上篇博客小鸥带领大家实现了一个顺序表,那么我们就趁热打铁,实现一个基于顺序表的通讯录项目吧!(完整代码会附带在文章末尾)

通讯录前的准备

在创建通讯录之前,由于本次通讯录基于动态顺序表实现,所以现附上上篇博客中的顺序表,具体实现请参考上篇博客——《数据结构の顺序表》

顺序表代码

具体实现见上一篇《数据结构の顺序表》

SeqList.c文件(函数实现):

#include "SeqList.h"

//初始化
void SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
//销毁
void SLDestroy(SL* ps)
{
	if(ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
打印
//void SLPrint(SL* ps)
//{
//	for (int i = 0; i < ps->size; i++)
//	{
//		printf("%d ", ps->arr[i]);
//	}
//	fputs("\n", stdout);
//}
//扩容
void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = (ps->capacity == 0 ? 4 : 2 * ps->capacity);
		SLDateType* tmp = (SLDateType*)realloc(ps->arr, newcapacity * sizeof(SLDateType));
		if (tmp == NULL)//动态内存开辟失败
		{
			perror("realloc fail!");
			exit(1);
		}
		//动态内存开辟成功
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
}
//尾插
void SLPushBack(SL* ps, SLDateType x)
{
	assert(ps);
	//扩容
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}
//头插
void SLPushFront(SL* ps, SLDateType x)
{
	assert(ps);
	//申请空间
	SLCheckCapacity(ps);
	//将已有数据往后移一位
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	//将数据插入到第一位
	ps->arr[0] = x;
	//有效数据++
	ps->size++;
}
//尾删
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}
//头删
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	//数据往前移动一位
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	//有效数据--
	ps->size--;
}
//指定位置之前插入(下标位置)
void SLInsert(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);//防止指定位置pos越界
	//申请空间
	SLCheckCapacity(ps);
	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);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
查找
//int SLFind(SL* ps,SLDateType x)
//{
//	assert(ps);
//	for (int i = 0; i < ps->size; i++)
//	{
//		if (ps->arr[i] == x)
//			return i;//找到后返回下标
//	}
//	return -1;//没找到返回一个不可能的下标
//}

SeqList.h文件(包含函数):

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"
//typedef int SLDateType;
typedef peoInfo SLDateType;//将数据类型改为联系人结构体
//顺序表的创建
typedef struct SeqList
{
	SLDateType* arr;
	int size;//有效数据个数
	int capacity;//空间容量
}SL;

//初始化
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//打印
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);


//尾插
void SLPushBack(SL* ps, SLDateType x);
//头插
void SLPushFront(SL* ps, SLDateType x);
//尾删
void SLPopBack(SL* ps);	
//头删
void SLPopFront(SL* ps);

//指定位置之前插入(下标位置)
void SLInsert(SL* ps, int pos, SLDateType x);
//指定位置之前删除
void SLErase(SL* ps, int pos);
//查找
int SLFind(SL* ps, SLDateType x);

注:顺序表代码中注释的查找和打印函数,由于在通讯录中,顺序表储存的数据类型改变,所以不再适用,因此注释掉。SeqList.h文件中包含的Contact.h文件就是下文中要创建的通讯录的头文件。

理解通讯录与顺序表的关系

1.本次通讯录实现,是在顺序表基础上实现的,就是在顺序表的基础上,将动态顺序表中数组成员存储的数据类型改为本次通讯录需要的“联系人”结构体数据类型

2.通讯录在数据的增、删、查、改上都是基于顺序表中的函数实现的,是在顺序表的基础上,由于数据类型改变,做出了进一步的包装,本篇通讯录本质还是一个顺序表。

通讯录Contact.h文件

1.创建联系人信息结构体(数据类型)

在顺序表的总结篇中,我们演示用的数据类型是int,顺序表所存储的数据类型是可以自己定义的,今天的通讯录要使用的“联系人”数据类型就是使用结构体创建的自定义类型(包含在Contact.h头文件中)

#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;

本篇演示的通讯录联系人信息为姓名,性别,年龄,电话以及住址五个信息(可以自行添加其他需要的信息),再将联系人结构体重命名为peoInfo方便使用。

在定义成员数组的大小时,最好使用#define定义常量,这样更便于修改。

2.完整代码:

#pragma once
#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;

//将顺序表重命名为通讯录方便理解
typedef struct SeqList Contact;

//通讯录的初始化
void ContactInit(Contact* con);
//通讯录的销毁
void ContactDesTroy(Contact* con);
//通讯录添加数据
void ContactAdd(Contact* con);
//通讯录删除数据
void ContactDel(Contact* con);
//展示通讯录数据
void ContactShow(Contact* con);
//通讯录的修改
void ContactModify(Contact* con);
//联系人查找并展示其信息
void ContactFind(Contact* con);

此处将顺序表重命名为Contact(通讯录)方便后文理解。

后文Contact.c文件中的函数实现将按照头文件中函数顺序来实现。

通讯录Contact.c文件

1.通讯录的初始化

由于通讯录的本质就是顺序表,所以初始化和顺序表是一样的,直接调用顺序表的初始化函数即可。

#include "Contact.h"
#include "SeqList.h"
//通讯录的初始化
void ContactInit(Contact* con)
{
	//实际上就是顺序表的初始化
	//直接调用顺序表的初始化函数就行
	SLInit(con);
}

 2.通讯录的销毁

也和初始化一样直接调用顺序表的销毁函数即可

//通讯录的销毁
void ContactDesTroy(Contact* con)
{
	//和初始化一样,直接调用顺序表的销毁函数即可
	SLDestroy(con);
}

3.通讯录添加数据

添加数据函数,由于此时顺序表中数组的数据类型是我们自己定义的“联系人”结构体,所以先创建一个新结构体info,将用户要添加的信息存储到这个结构体中,此时一个新的联系人也就创建完成了,再调用顺序表的尾插函数,将本次数据插入到顺序表中即可。

//通讯录添加数据
void ContactAdd(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);

	//使用顺序表的插入数据函数将信息加入到通讯录中
	SLPushBack(con,info);
}

总结步骤:

1.创建一个联系人结构体

2.引导用户输入联系人信息到结构体中;

3.将本次数据插入到顺序表中。

4.通讯录删除数据

由于在删除数据时要先知道本次想要删除的数据,即联系人是哪个,所以要先确定通讯录中是否存在该联系人,若存在,再进行下一步的删除操作,而查找一个联系人的是否存在的依据也不止一个,本次演示基于姓名的查找方式

//联系人查找(姓名)
int FindByName(Contact* con, char name[])
{
	assert(con);
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name) == 0)//使用strcmp函数比较字符串是否相同
			return i;//找到返回下标位置
	}
	return -1;
}

1.当查找到该姓名存在时,说明该联系人存在,返回该联系人在通讯录中的位置(即顺序表数组成员中元素的下标位置) ;若不存在,则返回一个不可能的下标位置-1。

2.该查找函数只在这些.c文件中的函数内部使用,在使用时不会直接调用,所以没有在Contact.h中声明。

 有了查找到联系人的方法之后,我们再实现删除操作的函数:

//通讯录删除数据
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");
}

 总结步骤:

1.用户输入要删除的联系人的姓名;

2.依据输入姓名调用查找函数,找到目标联系人的下标位置;

3.调用顺序表的指定位置删除函数,将该联系人信息从通讯录中删除

5.展示通讯录数据

即打印出现有通讯录的所有联系人信息;由于创建通讯录时存储的数据类型改变,所以上篇中顺序表以int类型为数据类型时的,打印顺序表的函数已经不再适用(SeqList.c中已经注释),此处为全新的函数。

//展示通讯录数据
void ContactShow(Contact* con)
{
	//打印表头
	printf("%s  %s  %s  %s  %s\n","姓名","性别","年龄","电话","地址");
	//遍历通讯录,按格式打印联系人信息
	for (int 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.先打印表头,以表示信息类别;

2.使用结构体指针访问结构体成员,并按格式打印出来(此处没有调整表头与数据的对齐,可自行调整需要的占位空间)。

6.通讯录的修改

修改通讯录中已经有的联系人信息,顺序表中没有这个功能的函数,且根据不同的数据类型,修改的方式可能不同,所以这里为针对联系人结构体数据类型的新函数。

//通讯录的修改
void ContactModify(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");
}

总结步骤:

1.输入要修改的联系人的姓名;

2.使用FindByName来查找该联系人的位置;

3.修改该位置上的联系人信息。

7.查找联系人并展示其信息

此处的查找函数不同于上文中查找联系人下标的FindByName函数,是给使用者使用的,查找是否存在,且打印目标信息的查找函数,所以要在Contact.h头文件中声明。

由于此查找函数的查找依据也是name,所以查找的过程可以直接调用上文的FindByName函数

//联系人查找并展示其信息
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("%s  %s  %s  %s  %s\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);
}

总结步骤:

1.输入要查找的联系人姓名;

2.调用查找函数(使用其他成员数据如:gender、age、tel、addr时的查找函数请自行模仿FindByName函数来实现);

3.输出表头和目标联系人的相关信息。

使用通讯录

当完善完成通讯录的各种功能后,我们创建一个test.c文件来测试其功能:

#include "SeqList.h"
//通讯录使用

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

}

int main()
{
    int Input = -1;
	Contact con;
	ContactInit(&con);//初始化
	do
	{
		menu();
		printf("请选择你的操作:\n");
		scanf("%d", &Input);
		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("退出通讯录...\n");
			break;
		default:
			printf("输入错误,请重新输入您的操作!\n");
		}
	} while (Input != 0);
	return 0;
}

要点:

1.创建一个通讯录,并初始化(不初始化将导致错误);

2.使用printf创建一个简易的菜单界面,将功能展示出来,使用switch语句来调用各个功能的函数

使用过程这里就不再演示了,亲各位读者亲自去动手试一试吧!

其实还可以加上文件管路的内容,做到将输入的联系人信息储存到文件中长期保存起来,不过这里就不做示范了,有兴趣的话大家可以讨论一下评论出来哦!

后记

本篇的通讯录的创建到这里也就结束啦!大家可以自己去试着敲一敲,动起手来,理解上会更加的深刻哦!

当然,如果有不足的地方欢迎大家在评论区友好的指出,大家互相进步O!

这里是小鸥,咱们下期不见不散~~

附完整Contact.c代码:

#include "Contact.h"
#include "SeqList.h"
//通讯录的初始化
void ContactInit(Contact* con)
{
	//实际上就是顺序表的初始化
	//直接调用顺序表的初始化函数就行
	SLInit(con);
}

//通讯录的销毁
void ContactDesTroy(Contact* con)
{
	//和初始化一样,直接调用顺序表的销毁函数即可
	SLDestroy(con);
}

//通讯录添加数据
void ContactAdd(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);

	//使用顺序表的插入数据函数将信息加入到通讯录中
	SLPushBack(con,info);
}

//联系人查找(姓名)
int FindByName(Contact* con, char name[])
{
	assert(con);
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name) == 0)//使用strcmp函数比较字符串是否相同
			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 ContactShow(Contact* con)
{
	//打印表头
	printf("%s  %s  %s  %s  %s\n","姓名","性别","年龄","电话","地址");
	//遍历通讯录,按格式打印联系人信息
	for (int 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 ContactModify(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("%s  %s  %s  %s  %s\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);
}

  • 65
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
首先,我们需要定义通讯录的联系人实体类: ```java public class Contact { private String name; private String phoneNumber; private String email; public Contact(String name, String phoneNumber, String email) { this.name = name; this.phoneNumber = phoneNumber; this.email = email; } public String getName() { return name; } public String getPhoneNumber() { return phoneNumber; } public String getEmail() { return email; } @Override public String toString() { return "Name: " + name + ", Phone number: " + phoneNumber + ", Email: " + email; } } ``` 接下来,我们需要实现顺序表类: ```java public class ContactList { private Contact[] contacts; private int size; public ContactList(int capacity) { contacts = new Contact[capacity]; size = 0; } public int getSize() { return size; } public void addContact(Contact contact) { if (size == contacts.length) { throw new RuntimeException("Contact list is full"); } contacts[size++] = contact; } public Contact getContact(int index) { if (index < 0 || index >= size) { throw new RuntimeException("Invalid index"); } return contacts[index]; } public void removeContact(int index) { if (index < 0 || index >= size) { throw new RuntimeException("Invalid index"); } for (int i = index; i < size - 1; i++) { contacts[i] = contacts[i + 1]; } contacts[size - 1] = null; size--; } public void updateContact(int index, Contact contact) { if (index < 0 || index >= size) { throw new RuntimeException("Invalid index"); } contacts[index] = contact; } public Contact[] getAllContacts() { Contact[] result = new Contact[size]; for (int i = 0; i < size; i++) { result[i] = contacts[i]; } return result; } } ``` 然后,我们可以在主函数中使用顺序表类来实现通讯录: ```java public static void main(String[] args) { ContactList contactList = new ContactList(10); contactList.addContact(new Contact("Alice", "1234567890", "alice@example.com")); contactList.addContact(new Contact("Bob", "2345678901", "bob@example.com")); contactList.addContact(new Contact("Charlie", "3456789012", "charlie@example.com")); contactList.removeContact(1); contactList.updateContact(0, new Contact("Alice", "0987654321", "alice@example.com")); Contact[] contacts = contactList.getAllContacts(); for (Contact contact : contacts) { System.out.println(contact); } } ``` 输出结果: ``` Name: Alice, Phone number: 0987654321, Email: alice@example.com Name: Charlie, Phone number: 3456789012, Email: charlie@example.com ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值