【数据结构与算法】顺序表增删查改的实现(动态版本+文件操作)附源码

news2024/11/23 11:34:19

目录

一.前言

二.顺序表

1.概念及结构

2.顺序表结构体的定义

3.初始化顺序表,销毁顺序表和打印

3.接口

a.尾插 SepListpushback   头插 SepListpushfront

b.尾删  SepListpopback  头删  SepListpopfront

c.查询  SepListsearch

d.修改  SepListmodify

三.源码

SepList.h

SepList.c

test.c

四.顺序表的问题及思考


一.前言

其实顺序表的增删查改和前面的通讯录差不多,可以说通讯录的底层原理就是顺序表。如果你会写通讯录,那么顺序表也不是问题。所以这篇文章不会讲得太详细,如果你有不懂的地方,请看前面通讯录的实现过程,那里讲的非常详细。通讯录

二.顺序表

1.概念及结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储;

在数组上完成数据的增删查改。

顺序表分为静态顺序表和动态顺序表,由于静态顺序表的实用性不高,所以博主在此就不讲述了,主要讲解动态顺序表。

2.顺序表结构体的定义

#define INIT_CAPACITY  5   //顺序表的默认容量

typedef int SLdatatype;    //使用 typedef 对类型重定义,方便后续修改

typedef struct SepList
{
	SLdatatype* arr;  //后续对 arr 进行动态内存开辟
	int sz;   //记录当前数据的个数
	int capacity;  //顺序表的容量
}SepList;

3.初始化顺序表,销毁顺序表和打印

初始化

void download(SepList* ps)   //从文件中读取数据
{
	FILE* pf = fopen("SepList.txt", "r");
	assert(pf);
	while (fscanf(pf, "%d", &ps->arr[ps->sz]) != EOF)
	{
		ps->sz++;
		expcapacity(ps);
	}
	fclose(pf);
	pf = NULL;
}

void SepListinit(SepList* ps)
{
	ps->arr = (SLdatatype*)calloc(INIT_CAPACITY, sizeof(SLdatatype)); //动态内存开辟默认容量
	assert(ps->arr);  //判断是否开辟成功,若失败会直接报错,终止程序的运行
	ps->sz = 0;     //初始化当前数据量为1
	ps->capacity = INIT_CAPACITY;   //初始成默认容量
	download(ps);  //初始化时从文件中读取数据
}

销毁

void SepListdestroy(SepList* ps)  //销毁的同时将数据保存到文件中
{
	int i = 0;
	FILE* pf = fopen("SepList.txt", "w");
	assert(pf);
	for (i = 0; i < ps->sz; i++)
	{
		fprintf(pf, "%d", ps->arr[i]);
	}
	free(ps->arr);
	ps->arr = NULL;
	ps->sz = 0;
	ps->capacity = INIT_CAPACITY;
	fclose(pf);
	pf = NULL;
}

打印

void SepListprint(SepList* ps)
{
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
		printf("%d  ", ps->arr[i]);
	}
	printf("\n");
}

3.接口

a.尾插 SepListpushback   头插 SepListpushfront

需要注意的是在插入数据前,需要判断顺序表是否已经满了,所以就需要写一个扩容函数,这和通讯录那里得逻辑是一致的。

扩容  expcapacity 

void expcapacity(SepList* ps)
{
	if (ps->sz == ps->capacity)
	{
		SLdatatype* tmp = (SLdatatype*)realloc(ps->arr, sizeof(SLdatatype) * 2 * ps->capacity);   //使用realloc 函数扩容
		assert(tmp);
		ps->arr = tmp;  //注意要把tmp赋给原来得指针,否则在一些情况下会出问题
		ps->capacity = 2 * ps->capacity;
	}
}

尾插 SepListpushback

void SepListpushback(SepList* ps, SLdatatype x)  //这个SLdatatype 是我们之前重定义得类型
{
	expcapacity(ps);  //判断顺序表是否已满
	ps->arr[ps->sz] = x;
	ps->sz++;  //当前数据量 +1
}

头插 SepListpushfront

头插就是把当前有的数据全部向后移1位,把第一个位置空出来,此时仍需判断顺序表是否已满。

void SepListpushfront(SepList* ps, SLdatatype x)
{
    expcapacity(ps); 
	int end = ps->sz - 1;  //注意这里要 -1 
	for (; end >= 0; end--)
	{
		ps->arr[end + 1] = ps->arr[end];
	}
	ps->arr[0] = x;  将数据赋给下标为0的位置,完成头插
	ps->sz++;
}

b.尾删  SepListpopback  头删  SepListpopfront

在删除前,我们需要判断顺序表中是否有数据,如果没有,那么则不需要删除。

尾删  SepListpopback 

void SepListpopback(SepList* ps)
{
	assert(ps->sz > 0);  //判断顺序表中是否有数据,如果没有会直接报错,终止程序的运行
	ps->sz--;
}

头删  SepListpopfront

头删就是把所有数据向前移动1位

void SepListpopfront(SepList* ps)
{
	assert(ps->sz > 0);
	int begain = 0;
	for (; begain < ps->sz-1; begain++)
	{
		ps->arr[begain] = ps->arr[begain + 1];
	}
	ps->sz--;
}

c.查询  SepListsearch

查询前需要判断顺序表是否有数据。

void SepListsearch(SepList* ps)
{
	if (ps->sz == 0)
	{
		printf("无数据可供查找\n");
		return;
	}
	SLdatatype x = 0;
	int count = 0;
	SLdatatype* tmp = (SLdatatype*)calloc(ps->sz, sizeof(SLdatatype));  //要查询的数据可能有重复,所以定义一个数组来存储
	assert(tmp);
	printf("请输入要查询的数据:>");
	scanf("%d", &x);
	int i = 0,flag = 0;
	for (i = 0; i < ps->sz; i++)
	{
		if (ps->arr[i] == x)
		{
			flag = 1;
			tmp[count++] = i;
		}
	}
	if (flag == 0)
		printf("无此数据\n");
	else
	{
		printf("查到了,下标是:> ");
		for (i = 0; i < count; i++)
			printf("%d  ", tmp[i]);
	}
	free(tmp);
	tmp = NULL;
	printf("\n");
}

d.修改  SepListmodify

void SepListmodify(SepList* ps)
{
	if (ps->sz == 0)
	{
		printf("无数据可供修改\n");
		return;
	}
	SLdatatype x = 0;
again:
	printf("请输入要修改的数据:>");
	scanf("%d", &x);
	int i = 0, pos = 0;
	int flag = 0;
	for (i = 0; i < ps->sz; i++)
	{
		if (ps->arr[i] == x)
		{
			flag = 1;
			pos = i;
			break;
		}
	}
	if (flag == 0)
	{
		printf("要修改的数据不存在,重新输入\n");
		goto again;
	}
	else
	{
		printf("开始修改:>");
		scanf("%d", &ps->arr[pos]);
		printf("修改成功\n");
	}
}

三.源码

SepList.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>


#define INIT_CAPACITY  5

typedef int SLdatatype;

typedef struct SepList
{
	SLdatatype* arr;
	int sz;
	int capacity;
}SepList;

//初始化
void SepListinit(SepList* ps);
//销毁
void SepListdestroy(SepList* ps);
//扩容
void expcapacity(SepList* ps);
//打印
void SepListprint(SepList* ps);
//尾插
void SepListpushback(SepList* ps, SLdatatype x);
//头插
void SepListpushfront(SepList* ps, SLdatatype x);
//尾删
void SepListpopback(SepList* ps);
//头删
void SepListpopfront(SepList* ps);
//查询
void SepListsearch(SepList* ps);
//修改
void SepListmodify(SepList* ps);

SepList.c

#define _CRT_SECURE_NO_WARNINGS

#include "SepList.h"


void download(SepList* ps)
{
	FILE* pf = fopen("SepList.txt", "r");
	assert(pf);
	while (fscanf(pf, "%d", &ps->arr[ps->sz]) != EOF)
	{
		ps->sz++;
		expcapacity(ps);
	}
	fclose(pf);
	pf = NULL;
}

void SepListinit(SepList* ps)
{
	ps->arr = (SLdatatype*)calloc(INIT_CAPACITY, sizeof(SLdatatype));
	assert(ps->arr);
	ps->sz = 0;
	ps->capacity = INIT_CAPACITY;
	download(ps);
}

void SepListdestroy(SepList* ps)
{
	int i = 0;
	FILE* pf = fopen("SepList.txt", "w");
	assert(pf);
	for (i = 0; i < ps->sz; i++)
	{
		fprintf(pf, "%d", ps->arr[i]);
	}
	free(ps->arr);
	ps->arr = NULL;
	ps->sz = 0;
	ps->capacity = INIT_CAPACITY;
	fclose(pf);
	pf = NULL;
}

void expcapacity(SepList* ps)
{
	if (ps->sz == ps->capacity)
	{
		SLdatatype* tmp = (SLdatatype*)realloc(ps->arr, sizeof(SLdatatype) * 2 * ps->capacity);
		assert(tmp);
		ps->arr = tmp;
		ps->capacity = 2 * ps->capacity;
	}
}

void SepListprint(SepList* ps)
{
	int i = 0;
	for (i = 0; i < ps->sz; i++)
	{
		printf("%d  ", ps->arr[i]);
	}
	printf("\n");
}

void SepListpushback(SepList* ps, SLdatatype x)
{
	expcapacity(ps);
	ps->arr[ps->sz] = x;
	ps->sz++;
}

void SepListpushfront(SepList* ps, SLdatatype x)
{
    expcapacity(ps);
	int end = ps->sz - 1;
	for (; end >= 0; end--)
	{
		ps->arr[end + 1] = ps->arr[end];
	}
	ps->arr[0] = x;
	ps->sz++;
}

void SepListpopback(SepList* ps)
{
	assert(ps->sz > 0);
	ps->sz--;
}

void SepListpopfront(SepList* ps)
{
	assert(ps->sz > 0);
	int begain = 0;
	for (; begain < ps->sz-1; begain++)
	{
		ps->arr[begain] = ps->arr[begain + 1];
	}
	ps->sz--;
}

//#define 

void SepListsearch(SepList* ps)
{
	if (ps->sz == 0)
	{
		printf("无数据可供删除\n");
		return;
	}
	SLdatatype x = 0;
	int count = 0;
	SLdatatype* tmp = (SLdatatype*)calloc(ps->sz, sizeof(SLdatatype));
	assert(tmp);
	printf("请输入要查询的数据:>");
	scanf("%d", &x);
	int i = 0,flag = 0;
	for (i = 0; i < ps->sz; i++)
	{
		if (ps->arr[i] == x)
		{
			flag = 1;
			tmp[count++] = i;
		}
	}
	if (flag == 0)
	{
		printf("无此数据\n");
	}
	else
	{
		printf("查到了,下标是:> ");
		for (i = 0; i < count; i++)
		{
			printf("%d  ", tmp[i]);
		}
	}
	free(tmp);
	tmp = NULL;
	printf("\n");
}

void SepListmodify(SepList* ps)
{
	if (ps->sz == 0)
	{
		printf("无数据可供修改\n");
		return;
	}
	SLdatatype x = 0;
again:
	printf("请输入要修改的数据:>");
	scanf("%d", &x);
	int i = 0, pos = 0;
	int flag = 0;
	for (i = 0; i < ps->sz; i++)
	{
		if (ps->arr[i] == x)
		{
			flag = 1;
			pos = i;
			break;
		}
	}
	if (flag == 0)
	{
		printf("要修改的数据不存在,重新输入\n");
		goto again;
	}
	else
	{
		printf("开始修改:>");
		scanf("%d", &ps->arr[pos]);
		printf("修改成功\n");
	}
}

test.c

#define _CRT_SECURE_NO_WARNINGS

#include "SepList.h"

void menu()
{
	printf("|----------------------顺序表----------------------|\n");
	printf("||*********************************************** ||\n");
	printf("||*******     1.尾插         2.头插        *******||\n");
	printf("||*******     3.尾删         4.头删        *******||\n");
	printf("||*******     5.查询         6.修改        *******||\n");
	printf("||*******     7.打印         0.退出        *******||\n");
	printf("||************************************************||\n");
	printf("|--------------------------------------------------|\n");
}

int main()
{
	SepList s;
	SepListinit(&s);
	int input = 0;
	int x = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入要插入的数据:>");
			scanf("%d", &x);
			SepListpushback(&s,x);
			break;
		case 2:
			printf("请输入要插入的数据:>");
			scanf("%d", &x);
			SepListpushfront(&s, x);
			break;
		case 3:
			SepListpopback(&s);
			break;
		case 4:
			SepListpopfront(&s);
			break;
		case 5:
			SepListsearch(&s);
			break;
		case 6:
			SepListmodify(&s);
			break;
		case 7:
			SepListprint(&s);
			break;
		case 0:
			SepListdestroy(&s);
			printf("退出顺序表\n期待您的下次使用\n");
			break;
		default :
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

四.顺序表的问题及思考

问题:
1. 中间/头部的插入删除,时间复杂度为O(N);
2. 增容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗;
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
思考:如何解决以上问题呢?

   博主将在下一篇关于链表的文章中解决。


🐲👻关于顺序表的讲解就到这里了,若有错误或是建议欢迎小伙伴们指出。🐯🤖

🥰🤩希望小伙伴们可以多多支持博主哦。😍😃

😁😄谢谢你的阅读。😼😸

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

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

相关文章

搜索引擎 Elasticsearch 的三大坑

搜索引擎的坑 ES 搜索引擎系列文章汇总&#xff1a; 一、别只会搜日志了&#xff0c;求你懂点原理吧 二、ES 终于可以搜到”悟空哥“了&#xff01; 三、1W字&#xff5c;40 图&#xff5c;硬核 ES 实战 本文主要内容如下&#xff1a; 搜索引擎现在是用得越来越多了&#…

赛宁网安“网络安全卓越中心”:立足科技创新 推动网安产业高质量发展

​​2月22日上午&#xff0c;网络安全卓越中心CPCOE——圆桌论坛活动在南京召开。本次论坛由南京未来科技城主办&#xff0c;南京赛宁信息技术有限公司承办。论坛上&#xff0c;江苏省科协副主席、南京理工大学教授李千目&#xff0c;江苏省互联网协会副理事长兼秘书长刘湘生&a…

【Pytorch学习】获取当前的学习率Learning Rate(lr)

optimizer.state_dict()[param_groups][0][lr]from&#xff1a; https://blog.csdn.net/ftimes/article/details/120975402 PyTorch可视化动态调整学习率lr_scheduler&#xff1a;https://blog.csdn.net/ayiya_Oese/article/details/120704261 或者&#xff1a;scheduler.get_…

谷歌留痕代发技术指南_谷歌留痕怎么霸屏的?

本文主要分享谷歌留痕技术的一些常见问题&#xff0c;霸屏的原理是什么。 本文由光算创作&#xff0c;有可能会被修改和剽窃&#xff0c;我们佛系对待这种行为吧。 谷歌留痕也叫谷歌搜索留痕&#xff0c;那么谷歌搜索留痕的霸屏原理是什么&#xff1f; 答案是&#xff1a;利…

如何做好APP性能测试?

随着智能化生活的推进&#xff0c;我们生活中不可避免的要用到很多程序app。有的APP性能使用感很好&#xff0c;用户都愿意下载使用&#xff0c;而有的APP总是出现卡顿或网络延迟的情况&#xff0c;那必然就降低了用户的好感。所以APP性能测试对于软件开发方来说至关重要&#…

【Android视频号④ 问题总结】

这节坑比较多~ 差点没把我给整死&#xff01;&#xff01;&#xff01; 环境介绍 首先我调试都是root过的真机&#xff0c;但是生产环境都是没有Root的云机&#xff0c;属于自己改的Rom框架也不是XP或LSP 是技术人员利用Xposed源码改的框架 问题&解决 模块源码更改 这…

Leetcode第235题二叉搜索树的最近公共祖先|C语言

struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {if(root->val>p->val&&root->val<q->val)return root;//若p结点的值<q结点的值&#xff0c;而根节点的值位于两者之间&#xff0c;说明…

Java StringBuffer StringBuilder,超详细整理,适合新手入门

目录 一、StringBuffer和StringBuilder的区别是什么&#xff1f; 二、StringBuffer的示例 三、StringBuilder的示例 四、为什么StringBuffer和StringBuilder比String更适合在循环中使用&#xff1f; 五、如何将String对象转换为StringBuilder或StringBuffer对象&#xff1…

论文投稿指南——中文核心期刊推荐(综合性经济科学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

常见的排序算法 | 直接插入排序 | 希尔排序 | 选择排序 | 堆排序 | 冒泡排序 | 快速排序 | 归并排序 |(详解,附动图,代码)

思维导图&#xff1a; 一.插入排序 1.直接插入排序&#xff08;InsertSort&#xff09; ①手机通讯录时时刻刻都是有序的&#xff0c;新增一个电话号码时&#xff0c;就是使用插入排序的方法将其插入原有的有序序列。 ②打扑克 步骤&#xff1a; ①如果一个序列只有一个数&am…

【Android视频号③ Xposed插件编写】

这节 就是将frida代码翻译为Xposed 然后利用Sekiro服务进行接口调用 Xposed环境 我的测试环境是 LSPosed 它是完全兼容XP模块的 &#xff08;免重启调试起来方便一点&#xff09;下载后用Magisk安装即可. 模块编写可以参考这篇文章 XPosed模块编写教程 翻译代码 首先需要拦…

Java数据结构与算法第十一课---反射、枚举以及lambda表达式

一 : 反射 1.定义 Java的反射&#xff08;reflection&#xff09;机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c;都能够调用它的任意方法和属性&#xff0c;既然能拿到&#xff0c;那么…

k8s1.23.0+ubuntu20.04+docker23+hyperv

问题 k8s node节点加入到集群时卡住 “[preflight] Running pre-flight checks” # master节点重新生成加入命令 kubeadm token create --ttl 0 --print-join-command参考 注意 k8s1.24使用containerd而不再使用docker&#xff0c;因此使用k8s1.23版本 环境 k8s: 1.23.0 u…

【Python入门第十五天】Python字典

字典&#xff08;Dictionary&#xff09; 字典是一个无序、可变和有索引的集合。在 Python 中&#xff0c;字典用花括号编写&#xff0c;拥有键和值。 实例 创建并打印字典&#xff1a; thisdict {"brand": "Porsche","model": "911&q…

2023年湖北施工员怎么报考?甘建二告诉你

湖北施工员怎么报考&#xff1f;考施工员需要了解哪些知识呢&#xff1f;跟甘建二一起来看下 一、湖北施工员报名条件&#xff1a; 甘建二告诉你&#xff0c;施工员报名条件基本没有限制&#xff0c;年满18岁即可。个人名义都可以报考&#xff0c;限制不多&#xff0c;不是跟安…

20230223-EF6用原生的命令执行SQL命令

目录:一、环境说明二、背景三、示例代码四、思考总结一、环境说明本机环境&#xff1a;windows10 操作系统 使用工具&#xff1a;Visual Studio 2022 Net版本&#xff1a;Net6.0二、背景在使用winform EF 开发过程中&#xff0c;需要用到类似 QueryList QueryScalar 等功能的时…

MySQL中MVCC如何解决不可重复读以及幻读?

了解MVCC之前&#xff0c;我们首先需要了解以下两个概念&#xff1a;一致性非锁定读和锁定读&#xff0c;了解这两个概念之后我们在逐步分析MVCC。 一致性非锁定读和锁定读 一致性非锁定读(快照读) 对于 一致性非锁定读的实现&#xff0c;通常做法是加一个版本号或者时间戳字…

【12-JVM面试专题-垃圾回收器好坏评价的标准?吞吐量和响应时间?生产环境中,如何选择合适的垃圾收集器?如何判断是否使用G1垃圾收集器?】

垃圾回收器好坏评价的标准&#xff1f;吞吐量和响应时间&#xff1f;生产环境中&#xff0c;如何选择合适的垃圾收集器&#xff1f;如何判断是否使用G1垃圾收集器&#xff1f; 垃圾回收器好坏评价的标准&#xff1f;吞吐量和响应时间&#xff1f;生产环境中&#xff0c;如何选择…

python基于vue戒烟网站

可定制框架:ssm/Springboot/vue/python/PHP/小程序/安卓均可开发目录 开发语言&#xff1a;Python python框架&#xff1a;django/flask 软件版本&#xff1a;python 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;PyCharmscode 项目介…

Java常用算法

关于时间复杂度&#xff1a; 平方阶 (O(n2)) 排序 各类简单排序&#xff1a;直接插入、直接选择和冒泡排序。线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序。O(n1)) 排序&#xff0c; 是介于 0 和 1 之间的常数。希尔排序。线性阶 (O(n)) 排序 基数排序&#xff0c…