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


    一.通讯录的功能介绍

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

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

    (1). 功能要求

    1)至少能够存储100个人的通讯信息
    2)能够保存用户信息:名字、性别、年龄、电话、地址等
    3)增加联系人信息
    4)删除指定联系人
    5)查找制定联系人
    6)修改指定联系人
    7)显示联系人信息

    (2).重要思考

    思考1】用静态顺序表和动态顺序表分别如何实现
    思考2】如何保证程序结束后,历史通讯录信息不会丢失

    二. 通讯录的代码实现

    1.通讯录的底层结构(顺序表)

    (1)思路展示

    由于,通讯录是基于动态顺序表实现的,所以掌握基本的顺序表的结构代码,非常重要~!

    (2)底层代码实现(顺序表)

    1.

    SeqList.h
    
    • 1
    #pragma once
    #include"Contact.h"
    #include
    #include
    #include
    #include
    
    
    //typedef int SLDataType;
    //更改数据类型为通讯录数据类型
    //以下的方式任意选择即可
    typedef struct ContactInfo SLDataType;
    //typedef CInfo SLDataType;
    
    typedef struct SeqList
    {
    	SLDataType* a;
    	int size;//当前顺序表中的数据有效个数
    	int capacity;//顺序表的当前空间的大小
    }SL;
    //typedef struct SeqList SL;
    
    //对顺序表进行初始化
    void SLInit(SL* ps);
    void SLDestroy(SL* ps);
    //头部/尾部/插入/删除
    void SLPushBack(SL* ps, SLDataType x);
    void SLPushFront(SL* ps, SLDataType x);
    void SLPopBack(SL* ps);
    void SLPopFront(SL* ps);
    
    //任意位置/插入/删除
    void SLInsert(SL* ps, int pos, SLDataType x);
    void SLErase(SL* ps, int pos);
    
    //打印
    void SLPrint(SL* ps);
    bool SLIsEmpty(SL* ps);
    
    //查找
    bool SLFind(SL* ps, SLDataType x);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    2.

    SeqList.c
    
    • 1
    #include"SeqList.h"
    
    //初始化顺序表
    void SLInit(SL* ps)
    {
    	ps->a = NULL;
    	ps->size = ps->capacity = 0;
    }
    void SLDestroy(SL* ps)
    {
    	if (ps->a)
    		free(ps->a);
    	ps->a = NULL;
    	ps->size = ps->capacity = 0;
    
    }
    
    void SLCheckCapacity(SL* ps)
    {
    	//空间不足以插入一个数据,需要扩容
    	if (ps->size == ps->capacity)
    	{
    		//扩容
    		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
    		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));
    		if (tmp == NULL)
    		{
    			perror("realloc Fail!\n");
    			return 1;
    		}
    		ps->a = tmp;
    		ps->capacity = newCapacity;
    	}
    }
    
    //尾插
    void SLPushBack(SL* ps, SLDataType x)
    {
    	//判断顺序表是否为空
    	//assert(ps->a = NULL);
    	//暴力方式
    	assert(ps);
    	//柔和的方式
    	/*if (ps->a == NULL)
    		return;*/
    		//1)空间足够,直接插入
    		//2)空间不够,需要扩容
    	SLCheckCapacity(ps);
    	//空间足够,直接插入
    	ps->a[ps->size++] = x;
    }
    //头插
    void SLPushFront(SL* ps, SLDataType x)
    {
    	assert(ps);
    
    	SLCheckCapacity(ps);
    	//空间足够,历史数据后移一位;
    	for (size_t i = ps->size; i > 0; i--)
    	{
    		ps->a[i] = ps->a[i - 1];
    	}
    	ps->a[0] = x;
    	ps->size++;
    }
    //尾删
    void SLPopBack(SL* ps)
    {
    	assert(ps);
    	assert(!SLIsEmpty(ps));
    	//ps->a[ps->size - 1] = 0;
    	ps->size--;
    }
    
    //头删
    void SLPopFront(SL* ps)
    {
    	assert(ps);
    	assert(!SLIsEmpty(ps));
    	for (size_t i = 1; i < ps->size - 1; i++)
    	{
    		//最后一次进来的是ps->a[ps->size-2]
    		ps->a[i] = ps->a[i + 1];//pa->a[ps->size-2]=ps->a[ps->size-1]
    	}
    	ps->size--;
    }
    
    
    //任意位置插入
    void SLInsert(SL* ps, int pos, SLDataType x)
    {
    	assert(ps);
    	//判断插入的位置是否在范围内
    	assert(pos >= 0 && pos <= ps->size);
    	SLCheckCapacity(ps);
    	//空间足够,把pos的位置及以后的数据往后移一位
    	//此处isize和ps->size-1都可以,但是后面的不步骤需要对应
    	for (size_t i = ps->size; i > pos; i--)
    	{
    		ps->a[i] = ps->a[i - 1];
    	}
    	/*for (size_t i = ps->size - 1; i > pos; i--)
    	{
    		ps->a[i+1] = ps->a[i];
    	}*/
    	ps->a[pos] = x;
    	ps->size++;
    
    }
    //任意位置删除
    void SLErase(SL* ps, int pos)
    {
    	assert(ps);
    	assert(!SLIsEmpty(ps));
    	assert(pos >= 0 && pos < ps->size);
    
    	//pos位置及以后的数据往前移动一位
    	for (size_t i = pos; i < ps->size - 1; i++)
    	{
    		ps->a[i] = ps->a[i + 1];
    	}
    	ps->size--;
    
    }
    
    void SLPrint(SL* ps)
    {
    	for (size_t i = 0; i < ps->size; i++)
    	{
    		printf("%d ", ps->a[i]);
    	}
    	printf("\n");
    }
    bool SLIsEmpty(SL* ps)
    {
    	assert(ps);
    	//这样是不对的,这只是判断空间是否足够
    	//return ps->size = ps->capacity;
    	return ps->size == 0;
    }
    
    //bool SLFind(SL* ps, SLDataType x)
    //{
    //	scanf("%d", &x);
    //	for (size_t i = 0; i < ps->size; i++)
    //	{
    //		if (ps->a[i] == x)
    //		{
    //			return true;
    //		}
    //	}
    //	return false;
    //}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154

    3.

    test.c
    
    • 1
    #include"SeqList.h"
    #include"Contact.h"
    
    //void SLtest()
    //{
    	//SL sl;
    	//SLInit(&sl);
    
    	顺序表的具体操作
    	尾插
    	//SLPushBack(&sl, 1);
    	//SLPushBack(&sl, 2);
    	//SLPushBack(&sl, 3);
    	//SLPushBack(&sl, 4);
    	//SLPrint(&sl);
    	头插
    	//SLPushFront(&sl, 5);
    	//SLPushFront(&sl, 6);
    	//SLPushFront(&sl, 7);
    	//SLPushFront(&sl, 8);
    	//SLPrint(&sl);
    
    	//尾删
    	//SLPopBack(&sl);
    	//SLPrint(&sl);
    	//SLPopBack(&sl);
    	//SLPrint(&sl);
    	头删
    	//SLPopFront(&sl);
    	//SLPrint(&sl);
    	//SLPopFront(&sl);
    	//SLPrint(&sl);
    
    	//任意位置插入删除
    	/*SLInsert(&sl, 0, 9);
    	SLPrint(&sl);
    	SLErase(&sl, 8);
    	SLPrint(&sl);
    
    	bool ret = SLFind(&sl, 9);
    	if (ret)
    		printf("找到了\n");
    	else
    		printf("没找到\n");
    	SLDestroy(&sl);*/
    //}
    void Contact01()
    {
    	contact con;
    	ContactInit(&con);
    	//往通讯录中插入数据
    	ContactAdd(&con);
    	ContactAdd(&con);
    	ContactShow(&con);
    
    	//从通讯录里删除指定的数据
    	ContactDel(&con);
    	ContactShow(&con);
    
    	//从通讯录里查找指定的联系人
    	ContactFind(&con);
    
    	//在通讯录里修改指定的联系人
    	ContactModify(&con);
    	ContactDestroy(&con);
    
    
    
    }
    void menu()
    {
    	printf("***************通讯录****************\n");
    	printf("***** 1.添加联系人  2.删除联系人*****\n");
    	printf("***** 3.修改联系人  4.查找联系人*****\n");
    	printf("***** 5.查看通讯录  0.退出通讯录*****\n");
    	printf("*************************************\n");
    
    
    }
    int main()
    {
    	//SLtest();
    	//Contact01();
    
    	int op = -1;
    	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("已退出通讯录\n");
    			break;
    		default:
    			printf("系统里没有找到你需要进行的操作,请重新输入:\n");
    			break;
    
    		}
    	} while (op != 0);
    	ContactDestroy(&con);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122

    2.通讯录上层代码实现(通讯录结构)

    (1).思路展示

    1)由于,通讯录是基于动态顺序表实现的。
    2)所以,通讯录上层代码,只需要在上上层代码的头文件代码中创建一个保存联系人的结构,然后再定义通讯录功能函数即可。
    3)接着在通讯录上层代码的源文件中将这些功能函数实现即可。
    4)基于前面,我们已经知道,通讯录是基于动态顺序表实现的,所以在实现通讯录功能函数时,只需要在通讯录上层代码的源文件中,加上顺序表的头文件就可以调运顺序表的函数来实现通讯录了。

    (2).上层代码实现(通讯录)

    1.

    Contact.h
    
    • 1
    #pragma once
    #define _CRT_SECURE_NO_WARNINGS 1
    
    
    
    
    //创建保存联系人的结构
    #define NAME_MAX 100
    #define SEX_MAX 10
    #define TEL_MAX 15
    #define ADDR_MAX 100
    
    struct ContactInfo
    {
    	char name[NAME_MAX];//名字
    	char sex[SEX_MAX];//性别
    	int age;//年龄
    	char tel[TEL_MAX];//电话
    	char addr[ADDR_MAX];//家庭住址
    };
    typedef struct ContactInfo CInfo;
    
    
    //通讯录底层是用顺序表来实现的
    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 ContactShow(contact* pcon);
    //查找联系人
    void ContactFind(contact* pcon);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    2.

    Contact.c
    
    • 1
    #include"Contact.h"
    #include"SeqList.h"
    
    
    //通讯录的初始化与销毁
    void ContactInit(contact* pcon)
    {
    	SLInit(pcon);
    }
    
    void ContactDestroy(contact* pcon)
    {
    	SLDestroy(pcon);
    }
    
    //添加联系人
    void ContactAdd(contact* pcon)
    {
    	//接下来获取的都是结构体CInfo结构体里要求的数据
    	CInfo info;
    	printf("请输入联系人姓名:\n");
    	scanf("%s", info.name);
    	printf("请输入联系人性别:\n");
    	scanf("%s", info.sex);
    	printf("请输入联系人年龄:\n");
    	scanf("%d", &info.age);
    	printf("请输入联系人电话:\n");
    	scanf("%s", info.tel);
    	printf("请输入联系人住址:\n");
    	scanf("%s", info.addr);
    
    	//联系人数据都获取到了,并保存到了结构体info中
    	//往通讯录(顺序表)中插入数据
    	SLPushBack(pcon, info);
    }
    
    int FindByName(contact* pcon, char name[])
    {
    	for (int i = 0; i < pcon->size; i++)
    	{
    		if (strcmp(pcon->a[i].name, name) == 0)
    		{
    			return i;
    		}
    	}
    	return -1;
    }
    
    //删除联系人
    void ContactDel(contact* pcon)
    {
    	//直接强制用户使用名称来查找
    	printf("请输入要删除的联系人姓名:\n");
    	char name[NAME_MAX];
    	scanf("%s", name);
    	int findidex = FindByName(pcon, name);
    	if (findidex < 0)
    	{
    		printf("要删除的联系人不存在!\n");
    		return;
    	}
    	//找到了,要删除findidex位置的数据
    	SLErase(pcon, findidex);
    	printf("删除成功\n");
    }
    
    //修改联系人选项
    void MondifyMenu()
    {
    	printf("***************修改联系人选项****************\n");
    	printf("***** 1.修改联系人名字  2.修改联系人性别*****\n");
    	printf("***** 3.修改联系人年龄  4.修改联系人电话*****\n");
    	printf("***** 5.修改联系人住址  0.退出删除选项*******\n");
    	printf("******************************************\n");
    }
    //修改联系人
    void ContactModify(contact* pcon)
    {
    	printf("请输入你需要修改的联系人:\n");
    	char name[NAME_MAX];
    	scanf("%s", name);
    	int find = FindByName(pcon, name);
    	if (find < 0)
    	{
    		printf("要修改的联系人不存在!\n");
    		return;
    	}
    	printf("找到了:\n");
    	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
    	printf("%-5s %-5s %-4d %-4s %-4s\n",
    		pcon->a[find].name,
    		pcon->a[find].sex,
    		pcon->a[find].age,
    		pcon->a[find].tel,
    		pcon->a[find].addr);
    	
    	int val = -1;
    	do
    	{
    		MondifyMenu();
    		printf("请选择你需要修改的信息:\n");
    		scanf("%d", &val);
    		switch (val)
    		{
    		case 1:
    			printf("请输入修改后的联系人姓名:\n");
    			scanf("%s", pcon->a[find].name);
    			break;
    		case 2:
    			printf("请输入修改后的联系人性别:\n");
    			scanf("%s", pcon->a[find].sex);
    			break;
    		case 3:
    			printf("请输入修改后的联系人年龄:\n");
    			scanf("%d", &pcon->a[find].age);
    			break;
    		case 4:
    			printf("请输入修改后的联系人电话:\n");
    			scanf("%s", pcon->a[find].tel);
    			break;
    		case 5:
    			printf("请输入修改后的联系人住址:\n");
    			scanf("%s", pcon->a[find].addr);
    			break;
    		case 0:
    			printf("修改成功\n");
    			printf("已退出删除联系人选项\n");
    			break;
    		default:
    			printf("没有找到要修改的选项 请重新选择:\n");
    			break;
    		}
    	} while (val != 0);
    
    	
    
    
    
    }
    //查看通讯录
    void ContactShow(contact* pcon)
    {
    	//打印表头
    	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
    	for (int i = 0; i < pcon->size; i++)
    	{
    		printf("%-5s %-5s %-4d %-4s %-4s\n", 
    			pcon->a[i].name,
    			pcon->a[i].sex,
    			pcon->a[i].age,
    			pcon->a[i].tel,
    			pcon->a[i].addr);
    	}
    
    
    }
    //查找指定联系人
    void ContactFind(contact* pcon)
    {
    	printf("请输入你要查找的联系人:\n");
    	char name[NAME_MAX];
    	scanf("%s", name);
    	int findidex = FindByName(pcon, name);
    	if (findidex < 0)
    	{
    		printf("你要查找的联系人不存在!\n");
    		return;
    	}
    	printf("找到了:\n");
    	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址");
    	printf("%-5s %-5s %-4d %-4s %-4s\n",
    			pcon->a[findidex].name,
    			pcon->a[findidex].sex,
    			pcon->a[findidex].age,
    			pcon->a[findidex].tel,
    			pcon->a[findidex].addr);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177

    3.通讯录代码运行展示(数据只用于测试,无实际意义)

    (1)测试展示

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    (2)升华总结

    这里只是展示基于动态顺序表实现通讯录的大致框架,和一些基本功能,有兴趣,能力的小伙伴,也可以下去拓展一下通讯录的其他功能,优化的更加完善,美观的通讯录。
    感谢学习!

  • 相关阅读:
    MATLAB中左边的大括号最后一行为什么会留很大的空白——解决
    火焰图简介
    Spring 中有哪些感知接口
    cpp11 return返回类对象的过程
    动手实践丨基于ModelAtrs使用A2C算法制作登月器着陆小游戏
    Web服务(03)——HTTP协议
    Flutter macOS 教程之 01 macOS App开发快速入门 (教程含源码)
    SpringBoot-基础配置
    Linux下 Alluxio 的编译和运行
    openHarmony UI开发
  • 原文地址:https://blog.csdn.net/qq_73900397/article/details/133817727