数据结构——基于顺序表实现通讯录

news2024/11/24 19:49:35

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

1.1  功能要求

1)⾄少能够存储100个⼈的通讯信息

2)能够保存⽤⼾信息:名字、性别、年龄、电话、地址等
3)增加联系⼈信息
4)删除指定联系⼈
5)查找制定联系⼈
6)修改指定联系⼈
7)显⽰联系⼈信息

1.2   思路分析

我们之前创建的顺序表可以实现连续存储数据(类型可以为整型、字符等),但无论是哪种类型,存储信息都比较单一,但是通讯录存储信息比较多,有联系人姓名、性别、年龄等,所以我们把一个联系人的所有信息作为一个整体存储到顺序表,原来我们写的是整型作为数据存储每个数组元素空间,现在转化通讯录,把一个人的所有信息打包变为结构体然后存储到数组元素元素的空间,然后基于顺序表实现通讯录功能。

1.3 通讯录的实现

因为我们是基于顺序表实现通讯录,先将顺序表写好

1.3.1 顺序表

1.3.1.1  SeqList.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
//#include"Contact.h"
#define NAME_MAX 100
#define SEX_MAX 10
#define TEL_MAX 15
#define ADDR_AMX 20
struct ContactInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_AMX];
};
typedef struct ContactInfo  SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	int size;//空间有效数据
	int capacity;//空间大小
}SL;

//初始化和销毁
void SLInit(SL* ps);
void SLDestory(SL* ps);

//尾插和头插
void SLPushBack(SL* ps, SLDateType x);
void SLPushFront(SL* ps, SLDateType x);
//void SLPrint(SL* ps);

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

//在指定位置之前插入
void SLInsert(SL* ps, int pos, SLDateType x);
//删除指定位置
void SLDel(SL* ps, int pos);

注:这里值得注意的是我们将通讯信息结构体定义在SeqList.h中,然后重命名,后面的顺序表结构也是这样,那为什么不把通讯信息结构体定义在Contact.h,然后再SeqList.h中包含Contact.h,对typedef struct ContactInfo  SLDateType

这样看似没问题,实际会造成重命名的问题,所以我们字书时要规范。

输出结果:

1.3.1.2  SeqList.c
#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
void SLInit(SL* ps)
{
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}
void SLDestory(SL* ps)
{
	if (ps->a)
		free(ps->a);
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}
int  SLCheckCapacity(SL* ps)
{
	assert(ps);
	int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
	if (ps->size == ps->capacity)//进行扩容
	{
		SLDateType* ret = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
		if (ret == NULL)
		{
			perror("realloc fail:");
			return 1;
		}
		ps->a = ret;
		ps->capacity = newcapacity;
	}
}

void SLPushBack(SL* ps, SLDateType x)//1.若空间足够,进行插入  2.若空间不够,进行扩容(以1.5或2倍原来大小进行扩容)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}
//void SLPrint(SL* ps)
//{
//	assert(ps);
//	for (size_t i = 0; i < ps->size; i++)
//	{
//		printf("%d ", ps->a[i]);
//	}
//	printf("\n");
//}
void SLPushFront(SL* ps, SLDateType 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++;
}


bool SLIsEmpty(SL * ps)//若返回值为假,则有数据,反之,则无
{
	assert(ps);
	return ps->size == 0;
}
void SLPopBack(SL* ps)
{
	assert(ps);
	//还需要判断是否有数据
	assert(!SLIsEmpty(ps));
	ps->size--;
}
void SLPopFront(SL* ps)
{
	assert(ps);
	//还需要判断是否有数据
	assert(!SLIsEmpty(ps));
	for (size_t i = 0; i < ps->size-1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}



// 在指定位置之前插入
void SLInsert(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	//防止越界访问
	

	assert(pos>= 0 && pos<= ps->size);//端点位置为头插和尾插
	for (size_t i = ps->size; i >pos; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[pos] = x;
	ps->size++;
}
//删除指定位置
void SLDel(SL* ps, int pos)
{
	assert(ps);
	assert(!SLIsEmpty(ps));
	
	assert(pos>= 0 && pos< ps->size);//端点位置为头删和尾删
	for (size_t i = pos; i < ps->size-1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

1.3.2  通讯录的初始化+销毁

1.3.2.1 Contact.h
#define _CRT_SECURE_NO_WARNINGS


typedef  struct ContactInfo CInfo;
typedef struct SeqList Contact;//将顺序表重命名为通讯录(这里只是声明,无需包含Seqlist.h)

//通讯录的初始化和销毁
void ContactInit(Contact* con);
void ContactDestroy(Contact* con);

注:这里没有包含SeqList.h,为什么可以重定义结构体和顺序表呢?

因为这里我们只是声明,没有使用,当在text.c使用时,它就会将Contact.h的CInfo和Contact

展开。

 1.3.2.2 Contact.c
#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
#include"SeqList.h"
#include <stdlib.h>
#include<stdio.h>
#include<assert.h>
void ContactInit(Contact* con)
{
	SLInit(con);
}
void ContactDestroy(Contact* con)
{
	SLDestory(con);
}

这里直接借用顺序表实现

1.3.3   通讯录的添加+删除

1.3.3.1 Contact.h
//通讯录的初始化和销毁
void ContactInit(Contact* con);
void ContactDestroy(Contact* con);
1.3.3.2 Contact.c
void ContactAdd(Contact* con)
{
	assert(con);
	 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);
		//将数据进行尾插
		SLPushBack(con,info);

}
int FindByName(Contact* con,char name[])
{
	
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->a[i].name, name)==0)
		{
			return i;
		}
	}
	return -1;
}

void ContactDel(Contact* con)
{
	assert(con);
	
	char name[NAME_MAX];
	printf("需要删除的姓名:\n");
	scanf("%s", name);
	//先查找该信息位置
	int ret=FindByName(con,name);
	if (ret < 0)
	{
		printf("没找到该联系人\n");
		return 1;
	}
	SLDel(con, ret);//删除指定位置
}

注: info.name这个是数组名,所以不用取地址

1.3.4  查看通讯录 

1.3.4.1 Contact.h
//查看通讯录
void ContactShow(Contact* con);
1.3.4.2  Contact.c
void ContactShow(Contact* con)
{
	assert(con);
	assert(con->a);
	printf("%-4s%-4s%-4s%-4s%-4s\n", "姓名", "性别", "年龄", "电话", "住址");
	for (int i = 0; i < con->size;i++)
	{
		printf("%-4s %-4s %-4d%-4s%-4s\n",
			con->a[i].name, con->a[i].sex, con->a[i].age, con->a[i].tel, con->a[i].addr);
	}
}

1.3.5  修改通讯录

1.3.5.1 Contact.h
//修改通讯录
void ContactChange(Contact* con);
1.3.5.2 Contact.c
void ContactChange(Contact* con)
{
	assert(con);
	

	char name[NAME_MAX];
	printf("需要修改的姓名:\n");
	scanf("%s",name);
	//先查找该信息位置
	int ret = FindByName(con, name);
	if (ret < 0)
	{
		printf("没找到该联系人\n");
		return 1;
	}
	
	printf("请输入修改的姓名:\n");
	scanf("%s",con->a[ret].name);
	printf("请输入修改的性别:\n");
	scanf("%s", con->a[ret].sex);
	printf("请输入修改的年龄:\n");
	scanf("%d", &con->a[ret].age);
	printf("请输入修改的电话号码:\n");
	scanf("%s", con->a[ret].tel);
	printf("请输入修改的地址:\n");
	scanf("%s", con->a[ret].addr);
	printf("修改成功!\n");
	
}

1.3.6 查找指定联系人 

1.3.6.1 Contact.h
//查找指定联系人
void ContactFind(Contact* con);
1.3.6.2 Contact.c
void ContactFind(Contact* con)
{
	assert(con);
	char name[NAME_MAX];
	printf("需要查找的姓名:\n");
	scanf("%s", name);
	//先查找该信息位置
	int ret = FindByName(con, name);
	if (ret < 0)
	{
		printf("没找到该联系人\n");
		return 1;
	}
	printf("%-4s%-4s%-4d%-4s%-4s\n",
		con->a[ret].name, con->a[ret].sex, con->a[ret].age, con->a[ret].tel, con->a[ret].addr);
}

1.3.7 菜单界面

为方便调用通讯录的各种功能,我们做一个菜单界面

1.3.7 .1 text.c
void menu()
{ 
	printf("******************    通讯录   **********************\n");
	printf("***   1.添加联系人          2.删除联系人       ******\n");
	printf("***   3.修改通讯录          4.查看指定联系人   ******\n");
	printf("***   5.查看通讯录          0.退出通讯录       ******\n");
	printf("*****************************************************\n");

}
int main()
{
	int n = -1;
	Contact con;
	 ContactInit(&con);
	
	do
	{
		menu();
		printf("请输入你的选择;\n");
		scanf("%d", &n);
		switch (n)
		{
		case 1:
			ContactAdd(&con);
			break;
		case 2:
			ContactDel(&con);
			break;
		case 3:
			ContactChange(&con);
			break;
		case 4:
			ContactFind(&con);
			break;
		case 5:
			ContactShow(&con);
			break;
		case 0:
			break;
		default:
			printf("输入错误,请从新输入!\n");
			break;
		}

	}while (n);
	ContactDestroy(&con);
	return 0;
}

1.3.8  测试界面

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Cloud智慧工地源码,利用计算机技术、互联网、物联网、云计算、大数据等新一代信息技术开发,微服务架构

智慧工地系统充分利用计算机技术、互联网、物联网、云计算、大数据等新一代信息技术&#xff0c;以PC端&#xff0c;移动端&#xff0c;设备端三位一体的管控方式为企业现场工程管理提供了先进的技术手段。让劳务、设备、物料、安全、环境、能源、资料、计划、质量、视频监控等…

UI设计工具都哪些常用的,推荐这5款

对于UI设计师来说&#xff0c;日常工作无非是围绕“需求分析”→设计实施→“开发交付”这三个环节来进行。 然而&#xff0c;在每个环节中&#xff0c;设计师使用的工具却完全不同。在这里&#xff0c;我收集整理了UI设计师在日常工作中常用的五种工具&#xff0c;希望能为新…

二叉树刷题——递归

JZ36 二叉搜索树与双向链表&#xff08;牛客&#xff09; 描述 输入一棵二叉搜索树&#xff0c;将该二叉搜索树转换成一个排序的双向链表。如下图所示 数据范围&#xff1a;输入二叉树的节点数 0≤10000≤n≤1000&#xff0c;二叉树中每个节点的值 0≤10000≤val≤1000 要求&…

Android 11 Framework 增加自定义API到系统中

基于 Android 11 源码 根据网上的教程, 自己先捣鼓一波: frameworks\base\services 创建 hzyd文件夹 Android.bp内容: android_library_import {name: "services.hzyd",aars: ["MobileSDK-release.aar"],sdk_version: "current", }修改 fra…

携程AI布局:三重创新引领旅游行业智能化升级

2023年10月24日&#xff0c;携程全球合作伙伴峰会在新加坡召开&#xff0c;携程集团联合创始人、董事局主席梁建章做了名为《旅游业是独一无二的最好的行业》的演讲&#xff0c;梁建章在演讲中宣布了携程生成式 AI、内容榜单、ESG 低碳酒店标准三重创新的战略方向。这些创新将为…

Python 获取cpu、内存利用率

获取cpu、内存利用率 # -*- coding: latin1 -*- import psutil cpuPercent 0 psutil.cpu_percent() while True:vm psutil.virtual_memory()memoryPercent vm.percentcpuPercent psutil.cpu_percent(1) *10print("cpuPercent:"str(cpuPercent)" %")prin…

三、IPSec VPN原理

IPSec 1、IPSec起源和定义2、IPSec原理2.1、IPSec协议框架2.1.1、安全联盟2.1.2、安全协议2.1.3、安全协议报文头结构2.1.4、封装模式2.1.5、加密和验证2.1.6、IKE安全机制 2.2、IPSec基本原理2.2.1、定义IPSec保护的数据流2.2.2、IKEv2协商安全联盟的过程 2.3、IPSec增强原理2…

java配置GDAL

<gdal.version>3.7.0</gdal.version><!-- gdal--><dependency><groupId>org.gdal</groupId><artifactId>gdal</artifactId><version>${gdal.version}</version></dependency> GDAL环境安装 downlo…

华为OD机试 - 数组组成的最小数字 - 逻辑分析(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…

考研数据结构线性表看这篇就够了之顺序表(一)

目录 一.线性表 1.1 线性表的概念 1.2线性表的种类 1.2.1 静态线性表 1.2.2 线性表的动态存储 二动态顺序表的操作 2.1. 定义结构体与函数 2.2 初始化 2.2.1实参和形参的区别 2.2.2 用实参改变形参 题外话 int *p和int* p的区别 2.3 销毁 2.4 尾插 2.4.1 首先要判…

继承、菱形继承与虚拟继承

继承、菱形继承与虚拟继承 一、概念二、定义格式三、继承方式四、派生类继承基类成员访问方式的变化五、基类和派生类对象赋值转换1、概念2、示意图3、示例代码4、特点 六、继承中的作用域1、概念2、示例代码3、运行结果 七、派生类的默认成员函数1、调用方法2、示例代码3、运行…

【LeetCode刷题-排序】--147.对链表进行插入排序

147.对链表进行插入排序 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; this.next next; }…

必须收藏:IPv6核心知识梳理!!(原理+基础配置)

一、概述 由于NAT技术的应用&#xff0c;缓解了IPv4地址不足产生的问题&#xff0c;但是部署IPv6是解决IPv4地址不足的最终方案。当前世界上不同地区对部署IPv6的需求强烈程度不一&#xff0c;且当前IPv4网络仍然占主流地位&#xff0c;因此短时间内IPv6和IPv4将会共存。 IPv4网…

深入理解网络IO复用并发模型

本文主要介绍服务端对于网络并发模型以及Linux系统下常见的网络IO复用并发模型。文章内容一共分为两个部分。 第一部分主要介绍网络并发中的一些基本概念以及我们Linux下常见的原生IO复用系统调用&#xff08;epoll/select&#xff09;等。第二部分主要介绍并发场景下常见的网…

opencv dnn模块 示例(21) 目标检测 object_detection 之 yolov6

文章目录 1、YOLOv6介绍1.1、概述1.2、关键技术1.2.0、网络结构1.2.1、表征能力更强的 RepBi-PAN Neck 网络1.2.2、全新的锚点辅助训练&#xff08;Anchor-Aided Training&#xff09;策略1.2.3、无痛涨点的 DLD 解耦定位蒸馏策略 1.3、总结 2、测试2.1、官方项目测试2.2、open…

View绘制流程

在子线程中不能更新UI的前提是不触发 checkThread ,逐步委托给mParent检查线程 onCreate加载contentView 进行draw onStart onResume 可能也没有完成测量流程 setContentView: public abstract void setContentView(LayoutRes int resId); Activity 是由ActivityThread类中…

Linux友人帐之网络编程基础DNS服务器

一、DNS服务器 1.1概述 DNS&#xff08;Domain Name System&#xff09;是一种分布式系统&#xff0c;用于将域名映射到IP地址。它是互联网上的基础设施之一&#xff0c;作为一种网络协议&#xff0c;它将域名转换为对应的IP地址。DNS的主要功能是将易于记忆的域名转换为计算机…

Brave Game(博弈论巴什博弈)

Problem - 1846 #include<bits/stdc.h> using namespace std; int t,n,m; signed main(){scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);if(n%(m1)0) puts("second");else puts("first");}return 0; }

【带头学C++】----- 三、指针章 ---- 3.7 数组指针

3.7 数组指针 1.数组指针的概述 数组指针是一个指向数组的指针变量&#xff0c;是用来保存数组元素的地址。在C/C中&#xff0c;数组名代表了数组的首地址&#xff0c;可以被解释为一个指向数组第一个元素的指针。因此&#xff0c;一个指向数组的指针可以通过数组名来获…