探索C语言数据结构:利用顺序表完成通讯录的实现

news2024/11/18 3:27:50

在好久之前我就已经学习过顺序表,但是在前几天再次温习顺序表的时候,我惊奇的发现顺序编表可以完成我们日常使用的通讯录的功能,那么今天就来好好通过博客总结一下通讯录如何完成吧。

常常会回顾努力的自己,所以要给自己的努力留下足迹。

为今天努力的自己打个卡,留个痕迹吧

                                                                                                        2024.04.20     小闭


顺序表

顺序表在好久之前就已经写过一篇博客了,如果没了解过顺序表的佬,可以先去了解一下唔。传送门:http://t.csdnimg.cn/DhcZ7icon-default.png?t=N7T8http://t.csdnimg.cn/DhcZ7

了解过顺序表的就可以跟着往下看看如何使用顺序表来实现通讯录,下面先给大家展示一下顺表的C语言代码,不然等下就对通讯录的一些知识点给搞迷糊了。

顺序表是我们对数据进行管理的一种简单结构,他的底层就是数组,这里我们对数组进行封装就形成了我们的通讯录。

顺序表的头文件 "SL.h"

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include"Contact.h"

typedef struct Contact Datetype;

struct SEQlist
{
	Datetype*  a;
	int size;
	int capacity;

};





typedef struct SEQlist SL;
void Init(SL* s);
void Print(SL* s);
void pushFront(SL* s, Datetype x);

void INti(SL* s);
void tCheckCapacity(SL* s);
void SeqListPushBack(SL* s, Datetype x);
void SeqListPopBack(SL* s);
void SeqListPushFront(SL* s, Datetype x);
void SeqListPopFront(SL s);
void SeqListDestory(SL* s);
void SeqListinsert(SL* s, int pos,Datetype x);
void SeqListdel(SL* s, int pos);

顺序表的“.c”文件SL.c 

#define _CRT_SECURE_NO_WARNINGS 1
#include "SL.h"

//void Print(SL* s)
//{
//	for (int i = 0; i < s->size; i++)
//	{
//		printf("%d ", s->a[i]);
//	}
//	printf("\n");
//}




void Init(SL* s)
{

	s->a = NULL;
	s->size = 0;         // 表示数组中存储了多少个数据
	s->capacity = 0;   数组实际能存数据的空间容量是多大 


}

void CheckCapacity(SL* s)
{
	// 如果没有空间或者空间不足,那么我们就扩容
	if (s->size == s->capacity)
	{
		int newcapacity = s->capacity == 0 ? 4 : s->capacity * 2;
		Datetype* tmp = (Datetype*)realloc(s->a, newcapacity * sizeof(Datetype));
		if (tmp == NULL)
		{
			printf("realloc 失败\n");
			exit(-1);
		}

		s->a = tmp;
		s->capacity = newcapacity;
	}
}


void SeqListPushBack(SL* s, Datetype x)
{
	CheckCapacity(s);

	s->a[s->size] = x;
	s->size++;
}

void SeqListPopBack(SL* s)
{

	// 暴力处理方式
	assert(s->size > 0);
	s->size--;
}


void SeqListPushFront(SL* s, Datetype x)
{
	CheckCapacity(s);

	// 挪动数据
	int end = s->size - 1;
	while (end >= 0)
	{
		s->a[end + 1] = s->a[end];
		--end;
	}
	s->a[0] = x;
	s->size++;
}

void SeqListPopFront(SL* s)
{
	assert(s->size > 0);

	// 挪动数据
	int begin = 1;
	while (begin < s->size)
	{
		s->a[begin - 1] = s->a[begin];
		++begin;
	}

	s->size--;
}


void SeqListDestory(SL* s)
{
	free(s->a);
	s->a = NULL;
	s->capacity = s->size = 0;
}


void SeqListinsert(SL* s,int pos, Datetype x)
{

	assert(s);
	assert(pos >= 0 && pos<=s->size);
	CheckCapacity(s);

	for (int i = s->size; i > pos; i--)
	{
		s->a[i] = s->a[i - 1];

	}
	s->a[pos] = x;
	s->size++;

}


void SeqListdel(SL* s, int pos)
{

	assert(s);
	assert(pos >= 0 && pos < s->size);

	for (int i = pos; i < s->size-1; i++)
	{
		s->a[i] = s->a[i + 1];
	}
	
	
	s->size--;

}

 上面的两段代码包含了顺序表的,格式化,销毁,头插,尾插,头删,尾删,指定位置插入。


通讯录的实现

首先我们要知道通讯录里有什么?我们当然知道里面有联系人的姓名,性别,年龄,电话,地址。

我们假设这个通讯录就储存这么些信息,那我们这些信息是不是我们所说的数据,前面我们往顺序表里储存的是整形数据那么现在我们数据类型改为这些信息不就好了,可能有人就会想这些信息有那么多,那我们的数据变量要一个一个建立出来吗?当然不是,代码要求的是简便,既然这些信息可能是不同数据类型,而且还不少,那么我们就可以用一个自定义类型-----结构体来作为数据类型的变量,然后结构体内部就可以储存这些信息,这样一来就简单多了。如下图所示:


有了大概的思路,然后就开始封装顺序表,然后就让它成为一个成熟的通讯录。

创建通讯录的信息结构体和通讯录节点

具体思路:首先我们在建立两个文件一个“Contact.c”,“Contact.h”文件,其中在“Contact.h”文件里定义好储存联系人信息的结构体和声明函数和头文件,

“Contact.h”

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define MAX_NAME 18
#define MAX_TEL 18
#define MAX_GENDER  10
#define MAX_ADDR 100



typedef struct Contact
{
	char name[MAX_NAME];
	char gender[MAX_GENDER];
	int age;
	char tel[MAX_TEL];
	char addr[MAX_ADDR];

}con;

typedef struct SEQlist Ct;

//通讯录的初始化
void ContactInit(Ct* pf);

//通讯录的销毁
void ContactDestory(Ct* pf);

//通讯录数据的添加
void ContactAdd(Ct* pf);

//通讯录数据的删除
void ContactDel(Ct* pf,char arr[]);

//通讯录的展示
void ContactShow(Ct* pf);

//通讯录的查找
void ContactFind(Ct* pf,char arr[]);

 这里我们加了一个typedef struct SEQLIST Ct;是为了让人一眼看出这是通讯录而不是一个普通的顺序表,也让我们能够好理解一些。

以及在“Contact.c”文件里写下完成通讯录的一些基本功能的代码。

那么我们可以写的通讯录功能有哪些呢?

通讯录的格式化

void ContactInit(Ct* pf)
{
	Init(pf);

}
void Init(SL* s)
{

	s->a = NULL;
	s->size = 0;         // 表示数组中存储了多少个数据
	s->capacity = 0;   数组实际能存数据的空间容量是多大 


}

 

其实这里的格式化就是将顺序表给格式化,会先将结构体数组a给赋为NULL,然后将容量

(int capacity)和有效数据数目(int size)置为0 

通讯录的销毁

void ContactDestory(Ct* pf)
{

	SeqListDestory(pf);

}
void SeqListDestory(SL* s)
{
	free(s->a);
	s->a = NULL;
	s->capacity = s->size = 0;
}

 通讯录的销毁也是一样的,直接调用链表的销毁就好了

通讯录数据的添加

void ContactAdd(Ct* pf)
{

	assert(pf);
	struct Contact a;
	printf("请输入你要添加联系人的姓名\n");
	scanf("%s", a.name);

	printf("请输入你要添加联系人的性别\n");
	scanf("%s", a.gender);

	printf("请输入你要添加联系人的年龄\n");
	scanf("%d", &(a.age));

	printf("请输入你要添加联系人的电话\n");
	scanf("%s", a.tel);

	printf("请输入你要添加联系人的地址\n");
	scanf("%s", a.addr);

	//往联系人里添加数据
	 SeqListPushBack(pf, a);

}
void SeqListPushBack(SL* s, Datetype x)
{
	CheckCapacity(s);

	s->a[s->size] = x;
	s->size++;
}

 因为要添加数据,那我们首先就需要获取这个数据,这里我们运用scanf来进行获取数据放到我们用来储存数据的结构体(struct Contact)中,然后再运用链表的尾插功能,将数据添加到我们的顺序表中。

通讯录数据的删除

我们要删除通讯录里的联系人,首先就得核对通讯录里是否有我们操作者想要删除的人,所以这里我们在写一个函数来进行找人,如果找到此人则返回此人在数组a的下标。,没有则打印“未找到该联系人”,并返回-1;然后在ContactDel中进行一下判断是否为-1,如果不为-1,就执行链表中的指定位置删除

//找到某位联系人的位置
int Findname(Ct* pf,char arr[])
{
	assert(pf);
	int i = 0;
	for (i = 0; i < pf->size; i++)
	{
		if (strcmp(arr, pf->a[i].name) == 0)
		{
			return i;

		}

	}
	printf("未找到该联系人\n");


}
//删除联系人
void ContactDel(Ct* pf)
{
	assert(pf);
	int arr[MAX_NAME];
	scanf("%s", arr);
	printf("请输入你要删除的联系人: ");

	int find=Findname(pf,arr);
	if (find != -1)
	{
		SeqListdel(pf, find);
	}

	
}

 

void SeqListdel(SL* s, int pos)
{

	assert(s);
	assert(pos >= 0 && pos < s->size);

	for (int i = pos; i < s->size-1; i++)
	{
		s->a[i] = s->a[i + 1];
	}
	
	
	s->size--;

}

 

通讯录的查找

这里我们scanf输入想要查找的联系人,调用查找函数返回得到该联系人的下标,之后再打印出来即可。

//找到某位联系人的位置
int Findname(Ct* pf,char arr[])
{
	assert(pf);
	int i = 0;
	for (i = 0; i < pf->size; i++)
	{
		if (strcmp(arr, pf->a[i].name) == 0)
		{
			return i;

		}

	}
	printf("未找到该联系人\n");


}
void ContactFind(Ct* pf)
{
	assert(pf);
	char arr[MAX_NAME];
	printf("请输入你要查找的联系人: ");
	scanf("%s", arr);
	int find=Findname(pf,arr);

	if (find != -1)
	{
		printf("找到该联系人了,其信息如下:\n");
		printf("姓名    性别     年龄     电话       地址\n");
		printf("%s      %s       %d        %s         %s",
		pf->a[find].name, pf->a[find].gender, pf->a[find].age, pf->a[find].tel, pf->a[find].addr);

	}

 

通讯录的展示

这里就是遍历顺序表,将每个数据给打印出来,只要注意打印格式即可,想要美观可以调好打印的距离。


//通讯录的展示
void ContactShow(Ct* pf)
{

	assert(pf);
	int i = 0;

	for (i = 0; i < (pf->size); i++)
	{
		printf("姓名    性别     年龄     电话       地址\n");
		printf("%s      %s       %d        %s         %s\n",
			pf->a[i].name, pf->a[i].gender, pf->a[i].age, pf->a[i].tel, pf->a[i].addr);


	}


}


可能有人会问,我储存的数据程序一结束,数据就不见了,这还叫通讯录吗?这样确实显得这个通讯录有点鸡肋,所以我们现在就可以再写一个函数,将数据放到文本文件中进行储存

void SaveContact(Ct* con) {
 FILE* pf = fopen("contact.txt", "wb");
 if (pf == NULL) {
 perror("fopen error!\n");
 return;
 }
 //将通讯录数据写⼊⽂件
 for (int i = 0; i < con->size; i++)
 {
 fwrite(con->a + i, sizeof(PeoInfo), 1, pf);
 }
 printf("通讯录数据保存成功!\n");
}

当然这里是以二进制文件储存的。 

这些功能都是在“Contact.c”里来完成的。


常常会回顾努力的自己,所以要给自己的努力留下足迹。

为今天努力的自己打个卡,留个痕迹吧

                                                                                                        2024.04.20     小闭
 

                          

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

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

相关文章

Games101-光线追踪(辐射度量学、渲染方程与全局光照)

Basic radiometry (辐射度量学) 光的强度假定l为10&#xff0c;但是10是什么。 Whitted-Style中间了很多不同简化&#xff0c;如能看到高光&#xff0c;表示做了布林冯着色&#xff0c;意味着一个光线打进来后会被反射到一定的区域里&#xff0c;而不是沿着完美的镜像方向&…

javaEE初阶——多线程(五)

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享关于多线程的文章第五篇关于 多线程代码案例二 阻塞队列 如果有不足的或者错误的请您指出! 目录 2.阻塞队列2.1常见队列2.2 生产者消费者模型有利于进行解耦合程序进行削峰填谷…

网站空间的类型包括

网站空间的类型包括许多不同的形式&#xff0c;每种形式都具有其独特的特点和用途。从个人博客到企业网站&#xff0c;从电子商务平台到社交网络&#xff0c;各种类型的网站都为用户提供了不同的体验和功能。在本文中&#xff0c;我们将探讨几种常见的网站空间类型&#xff0c;…

MYSQL之增删改查(中)

前言&#xff1a; 以下是MySQL最基本的增删改查语句&#xff0c;很多IT工作者都必须要会的命令&#xff0c;也 是IT行业面试最常考的知识点&#xff0c;由于是入门级基础命令&#xff0c;所有所有操作都建立在单表 上&#xff0c;未涉及多表操作。 4、“查”——之单表查询 My…

Linux的firewalld防火墙

介绍firewalld&#xff1a; ①、firewalld&#xff08;Dynamic Firewall Manager of Linux systems&#xff0c;Linux系统的动态防火墙管理器&#xff09;服务是默认的防火墙配置管理工具&#xff0c;它拥有基于CLI&#xff08;命令行界面&#xff09;和基于GUI&#xff08;图…

专业清洁工匠服务网站模板 html网站

目录 一.前言 二.页面展示 三.下载链接 一.前言 该HTML代码生成了一个网页&#xff0c;包括以下内容&#xff1a; 头部信息&#xff1a;指定了网页的基本设置和元数据&#xff0c;例如字符编码、视口大小等。CSS文件&#xff1a;引入了多个CSS文件&#xff0c;用于设置网页…

程序员自由创业周记#32:新产品构思

程序员自由创业周记#32&#xff1a;新产品构思 新作品 我时常把自己看做一位木匠&#xff0c;有点手艺&#xff0c;能做一些作品养活自己。而 加一、Island Widgets、Nap 就是我的作品。 接下来在持续维护迭代的同时&#xff0c;要开启下一个作品的创造了。 其实早在2022的1…

【leetcode面试经典150题】64. 删除排序链表中的重复元素 II(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

C++必修:从C语言到C++的过渡(上)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 1. 什么是C C&#xff08;c plus plus&#xff09;是一种计算机高级程序设计语言&…

链表经典算法OJ题目

1.单链表相关经典算OJ题目1&#xff1a;移除链表元素 思路一 直接在原链表里删除val元素&#xff0c;然后让val前一个结点和后一个节点连接起来。 这时我们就需要3个指针来遍历链表&#xff1a; pcur —— 判断节点的val值是否于给定删除的val值相等 prev ——保存pcur的前…

【详细讲解下Photoshop】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

OpenHarmony 网络管理-Socket连接

介绍 本示例主要演示了Socket在网络通信方面的应用&#xff0c;展示了Socket在两端设备的连接验证、聊天通信方面的应用。 效果预览 使用说明 1.搭建服务器环境&#xff1a;修改服务器脚本中的服务端IP地址&#xff0c;与本机IP地址保持一致&#xff0c;修改完成后双击运行脚…

手撸词法分析器(C/C++)

手撸词法分析器&#xff08;C/C&#xff09; 一.背景二.什么是词法分析器&#xff1f;三.代码四.思考 一.背景 这学期开设了编译原理&#xff0c;要求写个基本的词法分析器。所以博主就自己写了一份代码&#xff0c;也比较简单基础。 二.什么是词法分析器&#xff1f; 简单来…

Unity实现动态数字变化

最近的项目需要动态显示数字&#xff0c;所以使用Text组件&#xff0c;将数字进行变化操作过程记录下来。 一、UI准备 1、新建一个Text组件 2、新建C#脚本 3、将Text挂载到脚本上 二、函数说明 1、NumberChange 方法 NumberChange 方法接收四个参数&#xff1a;初始数字 in…

设备连接IoT云平台指南

一、简介 设备与IoT云间的通讯协议包含了MQTT&#xff0c;LwM2M/CoAP&#xff0c;HTTP/HTTP2&#xff0c;Modbus&#xff0c;OPC-UA&#xff0c;OPC-DA。而我们设备端与云端通讯主要用的协议是MQTT。那么设备端与IoT云间是如何创建通信的呢&#xff1f;以连接华为云IoT平台为例…

不容忽视的办公网络安全威胁 零信任或成破局关键

移动互联网、混合云和 SaaS 时代的来临&#xff0c;让企业的办公网络环境发生着巨大变化&#xff0c; BYOD、移动办公以及访问云端 SaaS 应用的场景已经越来越频繁&#xff0c;在方便协作、提升效率的同时&#xff0c;潜在的安全威胁以及管理困境也日益突出。比如&#xff1a; …

快速入门Spring Data JPA

Spring Data JPA是Spring Data框架的一小部分&#xff0c;它能够让开发者能够更加简单的对数据库进行增删改查。 由于Spring Data JPA可以自动生成SQL代码所以一般情况下&#xff0c;简单的增删查改就可以交给Spring Data JPA来完成&#xff0c;而复杂的动态SQL等用MyBatis来完…

免费使用ChatGPT 4.0 和 文心一言 4.0

前言 今天给大家分享如何免费使用ChatGPT4.0 和 文心一言 4.0&#xff0c;废话就不多说了&#xff0c;我们直接入正题。 ChatGPT 4.0 先来看看如何免费使用ChatGPT 4.0 进入Coze登录 https://www.coze.com 选择大圣-GPT-4 文心一言 4.0 通过文心智能体平台&#xff0c;就…

[阅读笔记20][BTX]Branch-Train-MiX: Mixing Expert LLMs into a Mixture-of-Experts LLM

这篇论文是meta在24年3月发表的&#xff0c;它提出的BTX结构融合了BTM和MoE的优点&#xff0c;既能保证各专家模型训练时的高度并行&#xff0c;又是一个统一的单个模型&#xff0c;可以进一步微调。 这篇论文研究了以高效方法训练LLM使其获得各领域专家的能力&#xff0c;例如…

C++智能指针(二十)

一.RAII&#xff08;Resource Acquisition Is Initialization&#xff09; RAII资源获取即初始化&#xff0c;RAII的思想就是在构造时初始化资源&#xff0c;或者托管已经构造的资源。在析构的时候释放资源。一般不允许复制或赋值&#xff0c;并且提供若干的资源访问的方法。比…