顺序表详解及应用(通讯录的实现)

一.线性表

线性表:n个具有相同特性的的数据元素的有限序列。线性表是一种在实际中广泛应用的数据结构,常见的线性表:顺序表,链表,栈,队列,字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

二.顺序表

1.概念

顺序表是一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数据上完成数据的增删查改。

2.结构分类

顺序表一般可分为

(1)静态顺序表:使用定长数组存储元素

静态顺序表的缺陷:空间给少了不够用,空间给多了造成浪费 。

(2)动态顺序表:使用动态开辟的数组存储

3.动态顺序表的实现

SeqList.h 

//将int重命名为SLDateType(将SL中部分数据类型为int的用SLDateType代替)
typedef int SLDateType;
//定义顺序表的结构——动态顺序表
typedef struct SeqList
{
	SLDateType* arr;
	int size;//有效数据个数
	int capacity;//空间大小
}SL;
//顺序表初始化
void* SLInit(SL* ps);
//顺序标的销毁
void* SLDestory(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);
//打印顺序表
void SLPrint(SL s);
(1)顺序表的初始化
//顺序表的初始化
void* SLInit(SL* ps)
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
(2)顺序表的销毁
//顺序标的销毁
void* SLDestory(SL* ps)
{
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
(3)顺序表申请空间
//顺序表申请空间
void* SLCheckCapacity(SL* ps)
{
	//插入数据之前先看空间够不够
	if (ps->size == ps->capacity)
	{
		//申请空间(增容用realloc)
		// 增容通常来说是成倍速数的增加,一般是两倍或者三倍
		//三目操作符
		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;
	}
}
(4)顺序表的尾插
//顺序表的尾插
void* SLPushBack(SL* ps, SLDateType x)
{
	assert(ps);
	//插入数据之前先看空间够不够
	SLCheckCapacity(ps);
	ps->arr[ps->size++] = x;
}
(5)顺序表的头插
//顺序标的头插
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];
	}
	//空出来的第一位插入x
	ps->arr[0] = x;
	//注意一定要size++
	ps->size++;
}
(6)顺序表的尾删
//顺序表的尾删
void* SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);
	//直接删除,不用管顺序表中原本存储的数据
	--ps->size;
}
(7)顺序表的头删
//顺序表的头删
void* SLPopFront(SL* ps)
{
	assert(ps);
	//将顺序表中数据整体向前移一位
	for (int i = 0; i<ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	//有效数据个数也要减小
	--ps->size;
}
(8)在指定位置前插入数据 
//在指定位置前插入数据
void SLInsert(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert((pos > 0) && (pos <= ps->size));
	SLCheckCapacity(ps);
	//让pos之后的数据整体向后挪一位
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}
(9)删除指定位置的数据 
//删除指定位置的数据
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--;
}
(10)查找
//查找
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;
}
(11)打印顺序表
//打印顺序表
void SLPrint(SL s)
{
	int i = 0;
	for (i = 0; i < s.size; i++)
	{
		printf("%d ", s.arr[i]);
	}
	printf("\n");
}

三.顺序表的应用—基于动态顺序表实现通讯录

1.功能要求

(1)至少能存储100个人的通讯信息

(2)能够保存用户信息:名字,性别,年龄,电话,地址等

(3)增加联系人信息

(4)删除指定联系人

(5)查找指定联系人

(6)修改指定联系人

(7)显示联系人信息

2.代码实现

(1)Contact.h

//Contact.h
#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100

//用户数据
typedef struct PersonInfo

{
	char name[NAME_MAX];
	char gender[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char adder[ADDR_MAX];
}PeoInfo;

//前置声明
//给顺序表改名叫通讯录
//typedef SL contact;//错误的,SL是在结构体定义完之后的重命名(找不到)
typedef struct SeqList Contact;//前置声明

//通讯录的操作实际上就是对顺序表的操作 
//初始化通讯录
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);

(2)Contact.c

<1>通讯录的初始化
//通讯录的初始化
void InitContact(Contact* con)
{
	//实际上是进行顺序标的初始化(已经实现好了)
	SLInit(con);
}
<2>销毁通讯录数据
//销毁通讯录数据
void DestroyContact(Contact* con) 
{
	SLDestory(con);
}
<3>添加通讯录数据
//添加通讯录数据
void AddContact(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.adder);
	//往通讯录中添加联系人
	SLPushBack(con, info);

}
<4>查找数据是否存在
//查找数据是否存在
int FindName(Contact* con, char name[])
{
	for (int i = 0; i < con->size; i++)
	{
		if (strcmp(con->arr[i].name, name) == 0)//找到了
		{
			return i;//找到后要返回下标
		}
	}
	return -1;
}
<5>删除通讯录数据
//删除通讯录数据
void DelContact(Contact* con)
{
	//要删除的数据必须存在才能执行操作
	char name[NAME_MAX];
	printf("请输入要删除的联系人姓名\n");
	scanf("%s", &name);
	int find = FindName(con, name);
	if (find < 0)
	{
		printf("要删除的联系人数据不存在\n");
		return;
	}
	SLErase(con, find);
	printf("删除成功\n");
}
<6>展示通讯录数据
//展示通讯录数据
void ShowContact(Contact* con)
{
	//表头
	printf("%s %s %s %s %s\n", "姓名", "性别","年龄","电话","地址");
	//按照格式打印每个联系人的数据
	for (int i = 0; i < con->size; i++)
	{
		printf("%4s %4s %4d %4s %4s \n",
			con->arr[i].name,
			con->arr[i].gender,
			con->arr[i].age,
			con->arr[i].tel,
			con->arr[i].adder);
	}
}
<7>修改通讯录数据
//修改通讯录数据
void ModifyContact(Contact* con)
{
	//要修改的联系人数据是否存在
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名\n");
	scanf("%s", &name);
	int find = FindName(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].adder);
	
	printf("修改成功!\n");
}
<8>查找通讯录数据
//查找通讯录数据
void FindContact(Contact* con)
{
	//查找后要将全部信息打印出来
	char name[NAME_MAX];
	printf("请输入要查找的联系人姓名\n");
	scanf("%s", &name);
	int find = FindName(con, name);
	if (find < 0)
	{
		printf("查找的联系人数据不存在\n");
		return;
	}
	printf("%s %s %s %s %s \n", "姓名", "性别", "年龄", "电话", "地址");
	printf("%4s %4s %4d %4s %4s \n",
		con->arr[find].name,
		con->arr[find].gender,
		con->arr[find].age,
		con->arr[find].tel,
		con->arr[find].adder
		);
}

四.顺序表的问题和思考

1.问题:

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

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

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

2.思考:

如何解决以上问题?思考一下链表的结构。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一、计算机基础(Java零基础一)

&#x1f33b;&#x1f33b;目录 一、&#x1f33b;&#x1f33b;剖析学习Java前的疑问&#x1f33b;&#x1f33b;1.1 零基础学习编程1.2 英语不好能学吗&#xff1f;1.3 理解慢能学好吗&#xff1f;1.4 现在学Java晚吗&#xff1f;1.5 Java 和 Python 还有 Go 的选择1.6 Java…

Rust 使用egui创建一个简单的下载器demo

仓库连接: https://github.com/GaN601/egui-demo-download-util 这是我第一个rust gui demo, 学习rust有挺长时间了, 但是一直没有落实到实践中, 本着对桌面应用的兴趣, 考察了slint、egui两种框架, 最后还是选择了egui. 这篇博客同时包含我当前的一些理解, 但是自身技术有限,…

ESP8266基础资源了解

封装的硬件资源 参考1&#xff0c;参考2 常说的esp8266指的是有一个屏蔽罩盖着的模块&#xff0c;里面包含了esp8266芯片和一个能够存储数据和程序的flash&#xff0c;因为esp8266没有存储功能。 使用arduino常用的nodemcu是包含这个模块并含有电源LDO和串口下载的设计电路如…

WINDOWS下zookeeper突然无法启动但是端口未占用的解决办法(用了WSL)

windows下用着用着时候突然zookeeper启动不了了。netstat查也没有找到端口占用&#xff0c;就是起不来。控制台报错 java.lang.reflect.UndeclaredThrowableException: nullat org.springframework.util.ReflectionUtils.rethrowRuntimeException(ReflectionUtils.java:147) ~…

铁山靠之数学建模 - Matlab入门

Matlab基础 1. Matlab界面与基本操作1.1 matlab帮助系统1.2 matlab命令1.3 matlab功能符号1.4 matlab的数据类型1.5 函数计算1.6 matlab向量1.7 matlab多项式1.8 M文件1.9 函数文件1.10 matlab的程序结构1.11 echo、warning和error函数1.12 交互输入1.13 程序调试1.14 设置断点…

Centos固定静态ip地址

这里我用的是Vmware虚拟机搭建的三台机器 进入 cd /etc/sysconfig/network-scripts然后使用 ip addr命令&#xff0c;查看自己虚拟机的以太网地址。 我这里是ens33 上面的第一个选项是本地环回地址&#xff0c;不用管它 然后查看刚刚进入的network-scripts目录下的文件 找到…

Mybatis框架笔记:基础信息

1.Mybatis介绍 MyBatis本是apache的一个开源项目iBatis&#xff0c;2010年这个项目由apache software foundation迁移到了google code&#xff0c;并且改名为MyBatis。2013年11月迁移到Github。 iBATIS一词来源于“internet”和“abatis”的组合&#xff0c;是一个基于Java的持…

AI赋能EasyCVR视频汇聚/视频监控平台加快医院安防体系数字化转型升级

近来&#xff0c;云南镇雄一医院发生持刀伤人事件持续发酵&#xff0c;目前已造成2人死亡21人受伤。此类事件在医院层出不穷&#xff0c;有的是因为医患纠纷、有的是因为打架斗殴。而且在每日大量流动的人口中&#xff0c;一些不法分子也将罪恶的手伸到了医院&#xff0c;实行扒…

健康知识集锦

页面 页面代码 <% layout(/layouts/default.html, {title: 健康知识管理, libs: [dataGrid]}){ %> <div class"main-content"><div class"box box-main"><div class"box-header"><div class"box-title"&g…

STM32 RTC的使用

注意 本文的总结基于STM32F103C8T6这款MCU&#xff1b;这款MCU的RTC没有硬件万年历功能&#xff0c;是通过RTC库的HAL_RTC_GetTime()函数将秒数转换成日期数据的&#xff1b; BCD格式 VS Binary格式 这个的BCD格式具体是指8421码&#xff0c;具体区别可以看如下代码&#xf…

《Python编程从入门到实践》day23

# 昨日知识点回顾 操控飞船移动发射子弹&#xff0c;删除屏幕之外的子弹 #今日知识点学习 第13章 外星人 13.1 项目回顾 项目添加新功能前审核既有代码&#xff0c;对混乱或低效的代码进行清理 13.2 创建第一个外星人 13.2.1 创建Alien类 # alien.py imp…

C++中的std::bind深入剖析

目录 1.概要 2.原理 3.源码分析 3.1._Binder分析 3.2._CALL_BINDER的实现 4.总结 1.概要 std::bind是C11 中的一个函数模板&#xff0c;用于创建一个可调用对象&#xff08;函数对象或者函数指针&#xff09;的绑定副本&#xff0c;其中一部分参数被固定为指定值&#xf…

摄像头参数笔记

DPI 每英寸多少像素点 例如&#xff1a; 例如要冲洗4*6英寸的照片&#xff0c;扫描精度必须是300dpi&#xff0c;那么文件尺寸应该是(4*300)*(6*300)1200像素*1800像素。 MP "MP"通常是"Megapixel"的缩写&#xff0c;意为“百万像素”。 2MP两百万像素…

YOLOv5改进 | 独家创新篇 | 利用MobileNetV4的UIB模块二次创新C3(全网独家首发)

一、本文介绍 本文给大家带来的改进机制是利用MobileNetV4的UIB模块二次创新C3&#xff0c;其中UIB模块来自2024.5月发布的MobileNetV4网络&#xff0c;其是一种高度优化的神经网络架构&#xff0c;专为移动设备设计。它最新的改动总结主要有两点&#xff0c;采用了通用反向瓶…

特征提取与深度神经网络(角点检测)

图像特征概述 图像特征表示是该图像唯一的表述&#xff0c;是图像的DNA HOG HOG &#xff08;Histogram of Oriented Gradients&#xff09;是一种用于目标检测的特征描述子。在行人检测中用的最多。HOG特征描述了图像中局部区域的梯度方向信息&#xff0c;通过计算图像中各个…

【教程向】从零开始创建浏览器插件(一)

第一步&#xff1a;创建一个自己的浏览器插件 在这篇博客中&#xff0c;我们将学习如何创建一个简单的浏览器插件。对于本教程&#xff0c;我们将以创建一个在浏览器中运行的基本插件为例&#xff0c;该插件能够通过点击插件图标来改变当前网页背景色。我们将使用Chrome扩展程…

关于 vs2019 c++ 20规范,STL 库提供的标准分配器 alloctor 及其 traits 及涉及分配器交换的全局函数 _Pocs

(1) 我们写 c 代码&#xff0c;使用 STL 库中的模板&#xff0c;很少自己写对象的分配器。用 STL 中的分配器也够用。研究 STL 中的分配器也可以为咱们自己写分配器提供参考。 咱们会遇到这样的场景&#xff0c;例如交换两个容器对象&#xff1a; list a ,b ; a .swap (b) ; 这…

CSS基础(CSS导入方式、选择器、属性)

层叠样式表&#xff08;Cascading Style Sheets&#xff0c;缩写为 CSS&#xff09;是一种样式表语言&#xff0c;用来描述 HTML 或 XML&#xff08;包括如 SVG、MathML 或 XHTML 之类的 XML 分支语言&#xff09;文档的呈现方式。CSS 描述了在屏幕、纸质、音频等其他媒体上的元…

Element ui input 限制只能输入数字,且只能有两位小数

<el-form-item label"整体进度&#xff1a;" prop"number"> <el-input v-model"formInline.number" input"handleInput" placeholder"百分比" clearable></el-input>% </el-form-item&g…

Re_Lasso

from sklearn.linear_model import LassoCV, Lasso import pandas as pd from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score from sklearn.model_selection import GridSearchCV# 读取数据…