【数据结构】:顺序表及其通讯录应用

这篇具有很好参考价值的文章主要介绍了【数据结构】:顺序表及其通讯录应用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.前置知识

1.数据结构

1.1为什么会存在数据结构?

我们常常接触到诸如生活中的姓名、身份证、网页内的图片、视频等各种各样的信息,这些信息就是我们常说的数据。在使用这些数据时,我们发现随着数据的增加,当我们要单独寻找某一个数据时就会非常困难,就像图书馆内书籍如果没有按一定的顺序排放,及时我们知道我们要找的书籍叫什么,我们也无法在浩如烟海的书籍内找到它。

【数据结构】:顺序表及其通讯录应用,c语言,开发语言,数据结构

同理,程序中如果不对数据进行管理,可能会导致数据丢失、操作数据困难、野指针等情况。
因此,对于数据,我们需要向像图书馆排列图书一样,采用以一定的形式将数据组织起来,方便日后进行调用。

总结:数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在⼀种或多种特定关系的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么方式构成,以及数据元素之间呈现的结构。

1.2数据结构之线性表

(1)线性表的定义

线性表(linear list)是n个具有相同特性的数据元素的有限序列。具有逻辑上线性,物理存储上不一定连续的特性。 线性表是⼀种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

(2)线性表结构特点
 (a)逻辑结构:逻辑上是线性结构,也就说是连续的⼀条直线。

【数据结构】:顺序表及其通讯录应用,c语言,开发语言,数据结构

通过线性表进行组织管理的数据逻辑上呈现由前到后,一对一的线性关系,可以通过如C语言中的结构体与指针来实现该线性逻辑下的一个一个数据的访问,就好像这些数据都是穿在一条线上的一样。

(b)物理结构:物理结构上并不⼀定是连续的(如顺序表物理上连续,链表不连续)

线性表在物理上存储时,通常以数组和链式结构的形式存储。以数组为例,我们都知道数组中每个元素的存储是在内存中开辟一块练习的空间进行存放,元素的地址是连续的,这就是物理结构连续的意思

【数据结构】:顺序表及其通讯录应用,c语言,开发语言,数据结构

但是如链式结构,用来存放不同元素的空间时用一块就申请一块,通过指针来实现不同空间的串连,不同空间地址并不是连续的,不具有物理结构上的连续性。

【数据结构】:顺序表及其通讯录应用,c语言,开发语言,数据结构

二.顺序表

1.为什么要有顺序表

在C语言中数组其实就是能算一种基本的数据结构,数组有助于我们实现对数组的查找、修改、调用等多种功能。看似功能强大,但其实远远不够。

现在假定数组有10个空间,已经使用了5个,向数组中插入数据步骤:

求数组的长度,求数组的有效数据个数,向下标为数据有效个数的位置插入数据(注意:这里是

否要判断数组是否满了,满了还能继续插入吗).....

再假设数据量非常庞大,频繁的获取数组有效数据个数会还会影响程序执行效率。因此我们需要学习其他数据结构,来提升效率。

而顺序表就在数组的基础上对其进行了封装,在其基础上实现了常用的增删改查等功能接口。

2.静态顺序表的定义

a.特点:

底层创建定长数组来存储元素,为对数组进行增删查改的操作,我们还需要创建一个变量来记录已存放有效的数据个数。

【数据结构】:顺序表及其通讯录应用,c语言,开发语言,数据结构

b.缺点:存储空间过大或过小

由于实际生活中,我们往往并不能准确预计实际使用时需要存放数据数量,而且由于静态顺序表底层是使用数组,大小固定,因此往往会出现空间申请过大或过小的情况,如果空间申请过大,那么会白白消耗大量的资源,如果空间申请过小,再对顺序表操作,则会出现数据丢失的情况。上述两种情况都会给公司造成大量的损失。因此,并不推荐屏幕前的读者使用静态顺序表。

3.动态顺序表的定义

a.特点:

动态顺序表定义时,不会直接创建,大小固定的数组,而是创建一个指针来配合之后的realloc来动态申请空间使用。同时由于动态申请空间大小,空间大小时变化的,因此除了需要变量来记录存放的数据个数,我们还需要记录已申请的空间大小。

【数据结构】:顺序表及其通讯录应用,c语言,开发语言,数据结构

b.缺点:

1.中间/头部的插入删除,时间复杂度为O(N)

2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。

3. 增容⼀般是呈2倍的增长,势必会有⼀定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空。

但相对与静态顺序表较好,推荐使用。

4.实现增删查改功能的封装

(注:基于动态顺序表实现,由于静态顺序表较为简单并且不常使用,笔者便不再过多赘述,后文会给出基于静态顺序表现的通讯录。)

1.顺序表初始化

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

}

由于我们是使用SLInit来初始化数序表,这就意味着顺序表未初始化,如果函数参数为结构体这里系统就会报错,因为参数为结构体是传值调用,形参是实参的拷贝,但是实参有没有初始化,因此这里便会报错,assert断言防止传入空指针,增强代码韧性,初始时未申请空间,未添加数据指针arr置为NULL,size,capacity赋值0.

2.顺序表的销毁

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

我们需要将指针arr指向的realloc申请的空间释放掉,再将野指针arr置为NULL,数据清空,size、capacity置为空。

3.申请空间

#define INIT_CAPACITY 4
//申请空间
void SLCheckCapacity(SL* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity = 0 ? INIT_CAPACITY : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc:");
			exit(1);
		}
		else
		{
			ps->arr = tmp;
			ps->capacity = newcapacity;
		}
	}
}

申请空间前我们需要先判断通过已存储的数据个数与空间个数是否相等来判断空间是否足够,如果

已开辟空间为0;我们先赋予它一个初始大小空间,如果不为0,我们再按每次2倍大小进行扩容(2倍空间扩容是较好选择,具体原因设计数学论证,笔者在此不过多赘述)。申请新空间无误后,我们用arr来指向这片空间。,并将capacity大小更正。

4.数据前插

【数据结构】:顺序表及其通讯录应用,c语言,开发语言,数据结构

void SLPushFront(SL* ps, SLDataType data)
{
	assert(ps);
	SLCheckCapacity(ps);

	int i = 0;
	for (i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}


	ps->arr[0] = data;
	ps->size++;
}

数据前插之前我们通过申请空间函数完成是否申请、申请一系列操作。之后再将原有数据后移一位,完成插入,现有数据+1,size更正。

5.数据尾插

void SLPushBack(SL* ps, SLDataType data)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = data;
}

先判断空间是否足够,再在最后一个有效数据之后添加数据,更正size。

6.打印顺序表数据

//打印数据
void SLPrint(SL ps)
{
	int i = 0;
	for (i = 0; i < ps.size; i++)
	{
		if (ps.arr[i] >= 'a' && ps.arr[i] <= 'z' || ps.arr[i] >= 'A' && ps.arr[i] <= 'Z')
		{
			printf("%c ", ps.arr[i]);
		}
		else
		{
			printf("%d ", ps.arr[i]);
		}
	}


	printf("\n");
}

笔者这边假设数组内存储的数据是字母或者数字来打印的,其实数据的类型远不是只有这两种,不过大体就是这样,根据存储数据类型来循环打印

7.数据头删

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


}

前删的话不是真的将数据从数组内移除,我们通过将头数据之后的数据前移,头数据就会被覆盖掉,然后记录数据个数的size-1,这样即使原有arr[size-1]位置还留存尾部的数据,之后我们通过size-1后的size来对数组操作时,留存的数据,我们也访问不到了,就相当于删除了。

8.数据尾删

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

我们只需要size-1,那么跟据size对数组访问时,我们是无法,访问到最后一个数据,也就相当于删除掉了。

9.查找指定数据

//查找数据
int  SLFind(SL ps, SLDataType s)
{
	int i = 0;
	for (i = 0; i < ps.size; i++)
	{
		if (s == ps.arr[i])
		{
			printf("找到了,下标位置为%d\n", i);
			return i;
		}
	}
	if (i == ps.size)
	{
		puts("很遗憾,找不到数据");
		return EOF;
	}
}

我们根据size记录的数据的个数循环访问数组进行比对查找。、

10.数据指定位置插入

//指定位置插入
void SLInsert(SL* ps, int pos, SLDataType data)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	SLCheckCapacity(ps);


	int i = 0;
	for (i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];


	}
	ps->arr[pos] = data;
	ps->size++;


}

插入数据时,我们需先明确插入位置pos,作为控制i的大小的数据,不能为负数,必须小于size(否则会发生数组越界访问)。然后要插入位置及之后的数据向后移动一位,然后将插入位置赋值为要插入的数据。

11.数据指定位置删除

//指定位置删除
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--;


}

插入数据时,我们需先明确插入位置pos,作为控制i的大小的数据,不能为负数,必须小于size(否则会发生数组越界访问)。然后要插入位置之后的数据向前移动一位,覆盖要删除的数据,size--,使得无法再访问最后一个多余数据。

5.顺序表的应用:通讯录

C语言基础要求:结构体、动态内存管理、顺序表、文件操作

1.基于动态顺序表实现通讯录

功能要求:

1)至少能够存储100个⼈的通讯信息 2)能够保存用户信息:名字、性别、年龄、电话、地址等

3)增加联系人信息 4)删除指定联系人 5)查找制定联系人 6)修改指定联系人 7)显示联系人信息(8)加载保存历史信息

功能实现:

1.单个联系人信息的集中存储:
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100

//前置声明

typedef struct SeqList contact;

//用户数据

typedef struct PersonInfo
{
	char name[NAME_MAX];
	char gender[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];

}PeoInfo;

我们通过将与联系人相关的姓名、性别、年龄、电话、地址等属性集中在一起创建一个结构体来

集中存储。为方便修改数据,我们使用预处理指令来定义相关量。同时为符合我们的主题,我们将struct SeqList 重新命名为contact。

2.初始化通讯录
//初始化通讯录

void InitContact(contact* con)
{
	assert(con);
	SLInit(con);
}

初始化是通过我们之前封装的初始化功能完成的。

3.添加通讯录数据
int FindByName(contact* con, char* Name)
{
	assert(con);
	assert(Name);
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->arr[i].name, Name))
		{
			return i;
		}
	}
	return EOF;
}
void AddContact(contact* con)
{
	assert(con);

	PeoInfo peniof ;
	puts("请输入要添加的联系人姓名:");
	scanf("%s", peniof.name);
	int find = FindByName(con, peniof.name);
	if (find >= 0)
	{
		puts("您要添加的联系人已存在!");
		ShowContact(con);
		return;
	}	
	puts("请输入要添加的联系人的性别:");
	scanf("%s", peniof.gender);
	puts("请输入要添加的联系人的年龄:");
	scanf("%d", &peniof.age);
	puts("请输入要添加的联系人的电话:");
	scanf("%s", peniof.tel);
	puts("请输入要添加的联系人的地址:");
	scanf("%s", peniof.addr);

	SLPushBack(con, peniof);

	puts("添加成功!");
}

首先我们先创建存放联系人信息的结构体,然后在正式添加数据之前我们需要跟据我们输入的姓名与顺序表中存储的arr[i].name来比较判断通讯录中是否已有该联系人信息,避免重复添加,之后想结构体内每个成员挨个输入,最后再用我们封装的头插或尾插功能插入数据(头插或尾插的选择看个人喜好)。

4.删除通讯录数据
int FindByName(contact* con, char* Name)
{
	assert(con);
	assert(Name);
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->arr[i].name, Name))
		{
			return i;
		}
	}
	return EOF;
}
void DelContact(contact* con)
{
	assert(con);
	char name[NAME_MAX];
	puts("请输入要删除的联系人的姓名");
	scanf("%s",&name);

	int find = FindByName(con, name);
	if (find < 0)
	{
		puts("您要添加的联系人信息不存在,删除失败");
		return;
	}
	SLErase(con, find);
	puts("删除成功!");

}

在正式添加数据之前我们需要跟据我们输入的姓名与顺序表中存储的arr[i].name来比较判断通讯录中是否已有该联系人信息,避免空删,之后根据名字查找函数,找到要删除联系人信息存储位置,用封装的SLErase函数来删除

5.展示通讯录数据
int FindByName(contact* con, char* Name)
{
	assert(con);
	assert(Name);
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->arr[i].name, Name))
		{
			return i;
		}
	}
	return EOF;
}
void ShowContact(contact* con)
{
	assert(con);
	if(0 == con->size)
	{
		puts("通讯录中未存储任何信息,无法展示");
		return;
	}
	int i = 0;
	for(i = 0;i < con->size;i++)
	{
		printf("联系人%d\n", i + 1);
		printf("姓名:%-s\n", con->arr[i].name);
		printf("性别:%-s\n", con->arr[i].gender);
		printf("年龄:%-d\n", con->arr[i].age);
		printf("电话:%-s\n", con->arr[i].tel);
		printf("地址:%-s\n", con->arr[i].addr);
	}
}

判断通讯录是否存放信息,如果有,挨个循环打印联系人信息

6.查找通讯录数据
void FindContact(contact* con)
{
	assert(con);
	char name[NAME_MAX];
	puts("请输入要查找的联系人的姓名");
	scanf("%s", &name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		puts("您要查找的联系人信息不存在,查找失败!");
		return;
	}
	puts("查找成功!联系人信息如下:");
	printf("联系人%d\n", find+1);
	printf("姓名:%-s\n", con->arr[find].name);
	printf("性别:%-s\n", con->arr[find].gender);
	printf("年龄:%-d\n", con->arr[find].age);
	printf("电话:%-s\n", con->arr[find].tel);
	printf("地址:%-s\n", con->arr[find].addr);
}

这里笔者是根据姓名查找对应联系人在通讯录中的位置(读者可根据自己喜好设置),然后根据位置访问打印,当然出于用户体验的考量,笔者还根据位置来显示联系人一二三。

7.修改通讯录数据
void contactmenu()
{
	puts("****请选择您要修改的内容****");
	puts("*******1.联系人姓名*******");
	puts("*******2.联系人性别*******");
	puts("*******3.联系人年龄*******");
	puts("*******4.联系人电话*******");
	puts("*******5.联系人地址*******");
	puts("*******0.退出修改 ********");

}
void ModifyContact(contact* con)
{
	assert(con);
	char name[NAME_MAX];
	puts("请输入要修改的联系人的姓名");
	scanf("%s", &name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		puts("您要添加的联系人信息不存在,修改失败");
		return;
	}
	int num = 0;
	while (1)
	{
		contactmenu();
		scanf("%d", &num);
		if (0 == num)
		{
			puts("修改结束");
			break;
		}
		puts("修改开始!");
		switch (num)
		{
		case 1:
			scanf("%s", con->arr[find].name);
			puts("修改成功");
			break;
		case 2:
			scanf("%s", con->arr[find].gender);
			puts("修改成功");
			break;
		case 3:
			scanf("%d", &con->arr[find].age);
			puts("修改成功");
			break;
		case 4:
			scanf("%s", con->arr[find].tel);
			puts("修改成功");
			break;
		case 5:
			scanf("%s", con->arr[find].addr);
			puts("修改成功");
			break;
		default:
			puts("输入错误请重新输入");
			break;
		}
	}
}

这里修改笔者根据姓名查找通讯录中有无该要修改的联系人,然后笔者设计了一个修改界面,通过while循环与switch选择结构让用户能够自己选择修改什么信息,如果不愿意继续修改则可以直接退出。

8.保存历史通讯录信息
//保存通讯录
void SaveContact(contact* con)
{
	FILE* pf = fopen("contact.txt", "wb");
	if(NULL == pf)
	{
		perror("fopen");
		exit(1);
	}
	int i = 0;
	for(i = 0;i < con->size;i++)
	{
		fwrite(con->arr + i, sizeof(PeoInfo), 1, pf);
	}
	puts("通讯录数据保存成功!");
	fclose(pf);
	pf = NULL;
}

考虑存储联系人数据可能包含各种形式的数据,读取时要考虑多种对应格式较为麻烦,这里笔者采用二进制写入的的方式将输入数据写入到文件中保存起来。

9.加载历史通讯录信息
void LoadContact(contact* con)
{
	assert(con);
	FILE* pf = fopen("contact.txt","rb");
	if(NULL == pf)
	{
		perror("fopen:");
		exit(1);
	}
	PeoInfo info;
	while(fread(&info,sizeof(PeoInfo),1,pf))
	{
		SLPushBack(con, info);
	}
	fclose(pf);
	pf = NULL;
	puts("通讯录历史数据加载成功!");
}

对应保存方式,笔者这里采用二进制读取方式,将单个联系人读取存放到联系人结构体中,再将联系人信息添加到结构体中。

10.销毁通讯录数据
void DestroyContact(contact* con)
{
	assert(con);
	int num = 0;
	scanf("%d",&num);
	puts("是否保存历史数据?");
	puts("0.不是 or 1.是");
	if (num)
	{
		SaveContact(con);
	}
	SLDestroy(con);
	puts("销毁成功!");
}

这里笔者先让用户决定是否保存历史数据,在进行通过动态顺序表封装的销毁功能进行销毁。

用户界面设计代码

void menu()
{
	puts("*********请选择您要进行的操作*******");
	puts("*******1.加载通讯录历史联系人信息****");
	puts("*******2.添加通讯录联系人信息*******");
	puts("*******3.删除通讯录联系人信息*******");
	puts("*******4.展示通讯录联系人信息*******");
	puts("*******5.查找通讯录联系人信息*******");
	puts("*******6.修改通讯录联系人信息*******");
	puts("*************0.退出程序************");

}


int main()
{

	int a = 0;
	contact con;
	InitContact(&con);
	while (1)
	{
		menu();
		scanf("%d", &a);
		if (0 == a)
		{
			break;
		}
		switch (a)
		{
		case 1:
			LoadContact(&con);
			break;
		case 2:
			AddContact(&con);
			break;
		case 3:
			DelContact(&con);
			break;
		case 4:
			ShowContact(&con);
			break;
		case 5:
			FindContact(&con);
			break;
		case 6:
			ModifyContact(&con);
			break;

		default:
			puts("输入错误请重新输入");
			break;
		}

	}
	DestroyContact(&con);

	return 0;
}

2.静态顺序表实现通讯录

注:与动态顺序表实现的通讯录相比较,静态顺序表实现通讯录会出现通许录满情况,添加前应该考虑是否通讯录已满,同时对于用来存放结构体的静态顺序表,由于数组与结构体特性,原本一些初始化会不太可行,因此笔者采用memset内存函数来直接全部“一键”初始化或者销毁。

附上源码:文章来源地址https://www.toymoban.com/news/detail-858702.html

//stactic_contact.h
#pragma once
#define NAME_MAX 10
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 10

//前置声明

typedef struct SeqList contact;

//通讯录修改菜单
void contactmenu();
//用户数据

typedef struct PersonInfo
{
	char name[NAME_MAX];
	char gender[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];

}PeoInfo;

//根据名字查找
int FindByName(contact* con, char* Name);

//加载通讯录信息
void LoadContact(contact* con);

//初始化通讯录

void InitContact(contact* con);

//添加通讯录数据

void AddContact(contact* con);

//删除通讯录数据

void DelContact(contact* con);

//展示通讯录数据

void ShowContact(contact* con);

//查找通讯录数据

void FindContact(contact* con);

//修改通讯录数据

void ModifyContact(contact* con);

//销毁通讯录数据

void DestroyContact(contact* con);

//stactic_seqlist.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#define ARR_MAX 10000
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include"Static_contact.h"

typedef PeoInfo SLDataType;

typedef struct SeqList
{
	SLDataType arr[ARR_MAX];
	int size;

}SL;

//初始化和销毁


void SLInit(SL* ps);
void SLDestroy(SL* ps);


//申请空间
void SLCheckCapacity(SL* ps);


//前插和尾插


void SLPushFront(SL* ps, SLDataType data);
void SLPushBack(SL* ps, SLDataType data);

//打印数组
void SLPrint(SL ps);


//头删和尾删
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//static_seqlist.c

//指定位置插入删除

void SLInsert(SL* ps, int pos, SLDataType data);
void SLErase(SL* ps, int pos);

#include"Static_seqlist.h"

//初始化
void SLInit(SL* ps)
{
	assert(ps);
	int i = 0;
	memset(ps->arr, 0, ARR_MAX * (sizeof(SLDataType)));
	ps->size = 0;
}
//销毁
void SLDestroy(SL* ps)
{
	assert(ps);
	memset(ps->arr, 0, ARR_MAX * (sizeof(SLDataType)));
	ps->size = 0;
}

//void SLCheckCapacity(SL* ps)
//{
//	assert(ps);
//	if (ps->size == )
//	{
//		int newcapacity = ps->capacity == 0 ? INIT_CAPACITY : 2 * ps->capacity;
//		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));
//		if (NULL == tmp)
//		{
//			perror("realloc:");
//			exit(1);
//		}
//		else
//		{
//			ps->arr = tmp;
//			ps->capacity = newcapacity;
//		}
//	}
//}


//前插
void SLPushFront(SL* ps, SLDataType data)
{
	assert(ps);
	int i = 0;
	for (i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}

	ps->arr[0] = data;
	ps->size++;
}

//后插
void SLPushBack(SL* ps, SLDataType data)
{
	assert(ps);
	ps->arr[ps->size++] = data;

}


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


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


}

//后删
void SLPopBack(SL* ps)
{
	assert(ps);
	ps->size--;
}


//随机插入
void SLInsert(SL* ps, int pos, SLDataType data)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	int i = 0;
	for (i = ps->size; i > pos; i--)
	{

		ps->arr[i] = ps->arr[i - 1];

	}

	ps->arr[pos] = data;
	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--;


}
//staric_contact.c
#include"Static_seqlist.h"

void menu()
{
	puts("*********请选择您要进行的操作*******");
	puts("*******1.加载通讯录历史联系人信息****");
	puts("*******2.添加通讯录联系人信息*******");
	puts("*******3.删除通讯录联系人信息*******");
	puts("*******4.展示通讯录联系人信息*******");
	puts("*******5.查找通讯录联系人信息*******");
	puts("*******6.修改通讯录联系人信息*******");
	puts("*************0.退出程序************");

}


void contactmenu()
{
	puts("****请选择您要修改的内容****");
	puts("*******1.联系人姓名*******");
	puts("*******2.联系人性别*******");
	puts("*******3.联系人年龄*******");
	puts("*******4.联系人电话*******");
	puts("*******5.联系人地址*******");
	puts("*******0.退出修改 ********");

}

//根据名字查找
int FindByName(contact* con, char* Name)
{
	assert(con);
	assert(Name);
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->arr[i].name, Name))
		{
			return i;
		}
	}
	return EOF;
}


//初始化通讯录

void InitContact(contact* con)
{
	assert(con);
	SLInit(con);
}

//加载通讯录信息
void LoadContact(contact* con)
{
	assert(con);
	FILE* pf = fopen("contact.txt", "rb");

	if (NULL == pf)
	{
		perror("fopen:");
		exit(1);
	}

	PeoInfo info;
	while (fread(&info, sizeof(PeoInfo), 1, pf))
	{
		SLPushBack(con, info);
	}

	fclose(pf);
	pf = NULL;
	puts("通讯录历史数据加载成功!");
}

//添加通讯录数据

void AddContact(contact* con)
{
	assert(con);
	PeoInfo peniof;
	if((sizeof(PeoInfo) * con->size ) >= ARR_MAX)
	{
		puts("通讯录可添加的名额已满,添加失败!");
		return;
	}
	puts("请输入要添加的联系人姓名:");
	scanf("%s", peniof.name);
	int find = FindByName(con, peniof.name);

	if (find >= 0)
	{
		puts("您要添加的联系人已存在!");
		ShowContact(con);
		return;
	}
	puts("请输入要添加的联系人的性别:");
	scanf("%s", peniof.gender);
	puts("请输入要添加的联系人的年龄:");
	scanf("%d", &peniof.age);
	puts("请输入要添加的联系人的电话:");
	scanf("%s", peniof.tel);
	puts("请输入要添加的联系人的地址:");
	scanf("%s", peniof.addr);

	SLPushBack(con, peniof);

	puts("添加成功!");
}


//删除通讯录数据

void DelContact(contact* con)
{
	assert(con);
	char name[NAME_MAX];
	puts("请输入要删除的联系人的姓名");
	scanf("%s", &name);

	int find = FindByName(con, name);
	if (find < 0)
	{
		puts("您要添加的联系人信息不存在,删除失败");
		return;
	}
	SLErase(con, find);
	puts("删除成功!");

}

//展示通讯录数据

void ShowContact(contact* con)
{
	assert(con);
	if (0 == con->size)
	{
		puts("通讯录中未存储任何信息,无法展示");
		return;
	}
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		printf("联系人%d\n", i + 1);
		printf("姓名:%-s\n", con->arr[i].name);
		printf("性别:%-s\n", con->arr[i].gender);
		printf("年龄:%-d\n", con->arr[i].age);
		printf("电话:%-s\n", con->arr[i].tel);
		printf("地址:%-s\n", con->arr[i].addr);
	}
}

//查找通讯录数据

void FindContact(contact* con)
{
	assert(con);
	char name[NAME_MAX];
	puts("请输入要查找的联系人的姓名");
	scanf("%s", &name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		puts("您要查找的联系人信息不存在,查找失败!");
		return;
	}
	puts("查找成功!联系人信息如下:");
	printf("联系人%d\n", find + 1);
	printf("姓名:%-s\n", con->arr[find].name);
	printf("性别:%-s\n", con->arr[find].gender);
	printf("年龄:%-d\n", con->arr[find].age);
	printf("电话:%-s\n", con->arr[find].tel);
	printf("地址:%-s\n", con->arr[find].addr);
}

//修改通讯录数据

void ModifyContact(contact* con)
{
	assert(con);
	char name[NAME_MAX];
	puts("请输入要修改的联系人的姓名");
	scanf("%s", &name);
	int find = FindByName(con, name);
	if (find < 0)
	{
		puts("您要添加的联系人信息不存在,修改失败");
		return;
	}
	int num = 0;
	while (1)
	{
		contactmenu();
		scanf("%d", &num);
		if (0 == num)
		{
			puts("修改结束");
			break;
		}
		puts("修改开始!");
		switch (num)
		{
		case 1:
			scanf("%s", con->arr[find].name);
			puts("修改成功");
			break;
		case 2:
			scanf("%s", con->arr[find].gender);
			puts("修改成功");
			break;
		case 3:
			scanf("%d", &con->arr[find].age);
			puts("修改成功");
			break;
		case 4:
			scanf("%s", con->arr[find].tel);
			puts("修改成功");
			break;
		case 5:
			scanf("%s", con->arr[find].addr);
			puts("修改成功");
			break;
		default:
			puts("输入错误请重新输入");
			break;
		}
	}
}

//保存通讯录
void SaveContact(contact* con)
{
	FILE* pf = fopen("contact.txt", "wb");
	if (NULL == pf)
	{
		perror("fopen");
		exit(1);
	}
	int i = 0;
	for (i = 0; i < con->size; i++)
	{
		fwrite(con->arr + 1, sizeof(PeoInfo), 1, pf);
	}
	puts("通讯录数据保存成功!");
	fclose(pf);
	pf = NULL;
}

//销毁通讯录数据

void DestroyContact(contact* con)
{
	assert(con);
	SaveContact(con);
	SLDestroy(con);
	puts("销毁成功!");
}
//static_function.c
#include"Static_seqlist.h"



int main()
{

	int a = 0;
	contact con;
	InitContact(&con);
	while (1)
	{
		menu();
		scanf("%d", &a);
		if (0 == a)
		{
			break;
		}
		switch (a)
		{
		case 1:
			LoadContact(&con);
			break;
		case 2:
			AddContact(&con);
			break;
		case 3:
			DelContact(&con);
			break;
		case 4:
			ShowContact(&con);
			break;
		case 5:
			FindContact(&con);
			break;
		case 6:
			ModifyContact(&con);
			break;

		default:
			puts("选择错误,请重新选择!");
			break;
		}

	}
	DestroyContact(&con);

	return 0;
}

到了这里,关于【数据结构】:顺序表及其通讯录应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【(数据结构) —— 顺序表的应用-通讯录的实现】

    C语言基础要求:结构体、动态内存管理、顺序表、文件件操作 (1). 功能要求 1)至少能够存储100个人的通讯信息 2)能够保存用户信息:名字、性别、年龄、电话、地址等 3)增加联系人信息 4)删除指定联系人 5)查找制定联系人 6)修改指定联系人 7)显示联系人信息 (2).重

    2024年02月08日
    浏览(48)
  • 数据结构课设—C语言实现通讯录管理系统(顺序表实现)

    这个项目是我大一时期数据结构的课程设计,在我潜心研究下出来的,对于当时的我来说算是非常满意啦,哈哈哈哈哈哈哈哈哈哈☆*: .。. o(≧▽≦)o .。.:*☆ 目录 一、引言 1.目的: 2.意义: 3.主要任务: 4.程序功能: 5.编译工具: 二、正文 1.系统模块: 2.算法流程图: 3.各

    2024年02月02日
    浏览(78)
  • 【(数据结构)—— 基于单链表实现通讯录】

    (1). 知识要求 C语言基础要求:结构体、动态内存管理、单链表、文件件操作 (2). 功能要求 1)至少能够存储100个人的通讯信息 2)能够保存用户信息:名字、性别、年龄、电话、地址等 3)增加联系人信息 4)删除指定联系人 5)查找制定联系人 6)修改指定联系人 7)显示联系

    2024年02月08日
    浏览(43)
  • 数据结构--学生通讯录管理系统

    文章目录 一、问题描述 二、系统功能设计 三、各个代码部分 四、整体代码及其运行 五、总结 学生通讯录管理系统--C语言实现 在现实中,用学号和姓名来记录学生需要花费大量的纸质材料,并且出现容易丢失、查找困难等问题。 “学生通讯管理系统”是为了帮助老师、同

    2024年02月11日
    浏览(59)
  • python数据结构实验设计(单链表):通讯录管理

    目录 摘要 一、课程设计目的及内容 创新功能: 二、算法及设计过程分析 1.总流程 2.主界面 3.文件处理与生成单链表 4.查看所有联系人信息 5.查看人数 6.查找联系人(以姓名或号码为依据) 7.对姓名或号码输入进行模糊查找  8.添加联系人 9.删除联系人  10.合并两个通

    2024年01月16日
    浏览(35)
  • C语言实现建立手机通讯录(顺序结构)

    今天来和大家分享一个简易通讯录(C语言实现) 首先要介绍一下通讯录的基本功能 添加联系人信息 删除指定联系人信息 查找指定联系人信息 修改指定联系人信息 显示所有联系人信息 总结,考虑到数据结构中的顺序表和单链表,我们可以采用这两种结构来实现。本文选择

    2024年02月07日
    浏览(41)
  • C++编程案例讲解-基于结构体的控制台通讯录管理系统

    添加联系人 :向通讯录中添加新人,信息包括(姓名、性别、年龄、联系电话、家庭住址)最多记录1000人 显示联系人 :显示通讯录中所有的联系人信息 删除联系人 :按照姓名进行删除指定联系人信息 查找联系人 :按照姓名查看指定联系人信息 修改联系人 :按照姓名重新

    2024年02月05日
    浏览(69)
  • 【C语言课设计划】个人通讯录管理系统(C语言大作业 链表 结构体 运行截图 完整代码)

    hello 大家好呀 这里是布丁学姐~ 今天给大家带来的是《C语言课设计划》的第一篇,个人通讯录管理系统 通讯录是当前社会每个人不可缺少的信息系统,利用C语言和Dve c++制作个人通讯录管理系统,从根本上改变纸质通讯录难以长久保存、容易丢失的弊端,从而提高信息管理和

    2024年02月02日
    浏览(105)
  • 数据结构例题代码及其讲解-顺序表

    静态分配内存及初始化 动态分配内存及初始化 01 对顺序表L进行遍历并输出每个数据元素的数据值 02 假设有一个顺序表L,其存储的所有数据元素均为不重复的正数,查找 L 中值为 e 的数据元素,若找到则返回其下标,若找不到则返回-1。 03 假设有一个顺序表 L,其存储的所有

    2024年02月10日
    浏览(41)
  • C语言---认识动态内存管理并实现一个动态通讯录:静态通讯录别来沾边

    👧个人主页:@小沈熬夜秃头中୧⍤⃝❅ 😚小编介绍:欢迎来到我的乱七八糟小星球🌝 📋专栏:C语言学习 🔑本章内容:动态内存管理 送给各位💌:当你的能力还驾驭不了你的目标时那你就应该沉下心来历练 记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~ 提示:以下是本篇

    2024年02月08日
    浏览(92)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包