C语言实现顺序表

news2024/12/22 11:43:58

绪论

        从本章开始就是开始数据结构的开端,本章将会写出数据结构中的顺序表的代码实现,多会以注释的方法来描述一些细节(注释是我们程序员必须常用的工具)。

     

话不多说安全带系好,发车啦(建议电脑观看)。


附:红色,部分为重点部分;蓝颜色为需要记忆的部分(不是死记硬背哈,多敲);黑色加粗或者其余颜色为次重点;黑色为描述需要


目录

1.线性表

2.顺序表

2.1顺序表的结构:

2.1.1 顺序表的初始化:

2.1.2 顺序表的摧毁

2.1.3 顺序表的放入数据

2.1.4 顺序表的删除数据

2.1.5 打印顺序表的数据       

2.2顺序表的源代码:


1.线性表

知识点:

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

细节(注意点):

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


2.顺序表

知识点:

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储(本质就是一个数组只不过用结构体包装了一下)。

顺序表分为静态顺序表(实现开辟好数组的空间大小)以及动态顺序表(用动态内存管理的方式来进行内存管理)

细节:

我们要实现一个顺序表的话首先我们要知道顺序表的框架

  1. 顺序表的结构体
    1. 数组(a)
    2. 顺序表中的元素个数(size)
    3. 容量(用于动态顺序表,是动态申请的大小,用于和元素个数比较判断申请空间是否足够)
  2. 有了这个结构后,我们就需要实现一个顺序表的基本功能
    1. 将数据放进顺序表中
    2. 将顺序表中的数据删除
    3. 初始化顺序表(主要针对于动态开辟空间提前申请空间)
    4. 归还(摧毁)所借的空间
    5. 将顺序表中的数据打印出来

下面这要讲的是动态的顺序表、如果需要静态的将结构体中的容量去掉,再把数组改一下即可(若有问题的话可以评论我都会看),我们就把顺序表想成一个数组就能很好的理解了


2.1顺序表的结构:

顺序表所要的结构是由数组、元素个数、容量组成的

代码实现如下:

typedef struct SeqList//将结构体名称重命名为
{
	SLDataType* a;//开辟SLDataType(用typedef重定义类型名,这样方便与改变结构体内的数据类型)类型的空间
//数组的本质是指针所以为了更方便理解就直接写成指针的形式SLDataType* a 
	int size;//元素个数
	int capacity;//容量
}SeqList;//重命名为SeqList 这样方便后面使用
//宏定义如下:
//#define SLDataType int 
//使用结构体类型
//SeqList s;即可
//不用写成 struct SeqList s;

2.1.1 顺序表的初始化:

将容量capacity和个数size进行简单的初始化,主要是申请一片空间来给a来存数据

代码如下:

void InitSeqList(SeqList* obj)//将结构体用指针接收
{
	assert(obj);
	obj->capacity = INIT_CAPACITY;//通过指针来访问结构体中的成员,将capacity先初始化为INIT_CAPACITY(用宏来确定capacity的起始大小,这样方便后改变)
	obj->size = 0;//0个成员
	obj->a = (SLDataType*)malloc(sizeof(SLDataType) * obj->capacity);//malloc动态申请结构体大小的capacity个空间
	if (obj->a == NULL)//判断一下是否申请成功
	{
		perror("malloc");//如果失败就报错
		return;
	}
}

//宏
//#define INIT_CAPACITY 4 (这是应该定义在头文件中的)

//调用的方法
//SeqList s;(应该定义在测试test.c文件中)
//InitSeqList(&s);

//而一般的结构的实现又是放在SeqList.c的文件中,这样来进行分源管理

2.1.2 顺序表的摧毁

顺序表的摧毁主要是为了将向操作系统借的空间归还,以及再将容量和元素个数归为0

void DestorySeqList(SeqList* obj)//指针接收结构
{
	assert(obj);//判断结构是否为空,防止访问到NULL指针(这是一个好习惯)
	free(obj->a);//直接释放所借用的空间
	obj->a = NULL;//再将其置为NULL
	obj->capacity = obj->size = 0;//将容量和个都置为0,摧毁了自然就没了
}

//调用方法
//SeqList s;
//DestorySeqList(&s);

2.1.3 顺序表的放入数据

1.从尾部插入数据

尾部插入就比较的简单了,因为顺序表其实是一个数组所以直接在最后位置插入数据就行(此时最后位置的下标就是元素个数

void SeqListBackPush(SeqList* obj, SLDataType x)//将结构体用指针接收通过指针来找到成员,x是所要尾插的数据
{
	assert(obj);//判断结构体是否为NULL

	If_Add_Capacity(obj);//判断数据是否已经把所借的容量填满了

	obj->a[(obj->size)++] = x;//在a的最后位置插入数据,可以发现其实size个数就是最后位置的下标
}

但要注意判断容量是否满足,如果容量已经是满的了(size == capacity)就需要扩容,If_Add_Capacity (判断是否要增容)

void If_Add_Capacity(SeqList* obj)
{
	if (obj->size == obj->capacity)//判断已有成员个数是否等于容量,若等则进去
	{
		SLDataType* ptr = (SLDataType*)realloc(obj->a, sizeof(SLDataType) * obj->capacity * 2);//进来后就说明空间不够了,需要开空间
		//一般多直接开辟比容量大两倍的空间 即 对a开辟结构体大小为原capacity两倍的空间
		if (ptr == NULL)//判断是否申请成功
		{
			perror("realloc");//不成功则报错

			return;
		}
		obj->a = ptr;//因为可能是异地扩容所以还要将ptr赋值给数组a
		obj->capacity *= 2;//容量 乘于 2
		ptr = NULL;//无用的指针置为NULL(好习惯)
	}
}

2.从头部插入

在一个数组中若想从头部插入 你就需要把数据先全部往后挪动一位,再将这个数据存放到第一个位置处。

void SeqListFrontPush(SeqList* obj, SLDataType x)
{
	assert(obj);//判空

	If_Add_Capacity(obj);//判是否满了
	for (int i = obj->size; i > 0; i--)//将所有数据往后移一位
	{
		obj->a[i] = obj->a[i - 1];//此处只要是未满的就能直接就行移位并不会有事
	}
	obj->a[0] = x;//在a[0]位置处添加数据
	obj->size++;//元素个数++,这可别忘了!
}

3.指定位置插入

在满足pos位置是一个正常的位置的前提下,并且同样需要判断是否要扩容, 要在某个位置处插入,其本质其实和头插有些类似,需要把插的位置后的数据全部往后挪一位后,最后再在那个位置插入数据即可。


void SeqListInsert(SeqList* obj, int pos, SLDataType x)//在pos位置处添加数据
{
	assert(obj);//判空
	pos -= 1;//换成下标
	assert(pos >= 0 && pos <= obj->size);//判断这个位置是否有问题
	If_Add_Capacity(obj);//判断是否满了
	int i = obj->size;//和头插的方法几乎一样
	for (i; i > pos; i--)//将从位置处开始的数据全部往后挪一位
	{
		obj->a[i] = obj->a[i - 1];//从尾部开始防止覆盖
	}
	obj->a[i] = x;//在位置处插入数据
	obj->size++;//size++ 别忘了!
}

2.1.4 顺序表的删除数据

1. 从尾部删除

在删除之前我们需要判断一下是否还有数据在顺序表中(assert(obj->size > 0)),对于一个数组来说我们删除时直接对元素个数进行 - - 即可并不会去真正的删除,当下一次插入数据时就直接覆盖了,也不会有什么影响。

void SeqListBackPop(SeqList* obj)
{
	assert(obj);//判空
	assert(obj->size > 0);//为真就过、为假就会报错,若没有数据那就是有问题的

	obj->size--;//此处的尾删并不直接将空间归还,而仅仅只是把元素个数-1这样

	//就不会访问到,即使后面需要再次添加数据也就直接覆盖了,因为要归还空间的成本太高了
}

2.从头部删除

同样我们需要先判断一下顺序表中是否还有数据、对于头部删除来说直接将第一个数据覆盖了就好

void SeqListFrontPop(SeqList* obj)
{
	assert(obj);//判空
	assert(obj->size > 0);//判断是否有数据
	for (int i = 0; i < obj->size - 1; i++)//直接从第2个位置开始往前覆盖掉即可
	{
		obj->a[i] = obj->a[i + 1];
	}
	obj->size--;//注意要 - - 
}

3.指定位置删除

判断pos是否在顺序表中、最后将从pos+1位置开始数据覆盖即可。

void SeqListErase(SeqList* obj, int pos)
{
	assert(obj);//判空
	assert(obj->size > 0);//是否有数据

	pos -= 1;//换成下标
	assert(pos >= 0 && pos <= obj->size);//是否符合要求

	for (int i = pos; i < obj->size - 1; i++)//和头删对应此处就应该是从pos+1位置处开始往前覆盖
	{
		obj->a[i] = obj->a[i + 1];//将pos位置处先覆盖 , 然后以此往后
	}
	obj->size--;//注意 - -
}

2.1.5 打印顺序表的数据       

就和数组的打印一样,直接遍历打印即可

void SeqListPirnt(SeqList* obj)//指针接收结构体
{
	assert(obj);//判空
	for (int i = 0; i < obj->size; i++)//从下标为0的位置处开始往后遍历
	{
		printf("%d ", obj->a[i]);//结构体访问成员:*obj表示结构体 在 .访问 就还能写成 (*obj).a[i] 这两个是等价的一般喜欢用前面方法
	}
	printf("\n");//换行
}

如果有任何问题,欢迎讨论!


2.2顺序表的源代码:

我将全部放在一个里面对于分源内容请自行分开,或者直接合并也行(合并方法将声明以及包含自身的头文件去掉即可直接使用

//SeqList.h
#pragma once

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


#define INIT_CAPACITY 4
//sequence

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* a;
	int size;
	int capacity;
}SeqList;

void InitSeqList(SeqList * obj);
void DestorySeqList(SeqList* obj);

void SeqListBackPush(SeqList* obj,SLDataType x );

void SeqListBackPop(SeqList* obj);

void SeqListPirnt(SeqList* obj);

void SeqListFrontPush(SeqList* obj, SLDataType x);

void SeqListFrontPop(SeqList* obj);

void SeqListInsert(SeqList* obj, int pos, SLDataType x);

void SeqListErase(SeqList* obj, int pos);

//SeqList.c

 #define _CRT_SECURE_NO_WARNINGS 1

#include"SeqLIst.h"
//sequence 顺序

void If_Add_Capacity(SeqList* obj)
{
	if (obj->size == obj->capacity)
	{
		SLDataType* ptr = (SLDataType*)realloc(obj->a, sizeof(SLDataType) * obj->capacity * 2);
		if (ptr == NULL)
		{
			perror("realloc");

			return;
		}
		obj->a = ptr;
		obj->capacity *= 2;
		ptr = NULL;
	}
	return;
}

void InitSeqList(SeqList* obj)
{
	assert(obj);

	obj->capacity = INIT_CAPACITY;
	obj->size = 0;
	obj->a = (SLDataType*)malloc(sizeof(SLDataType) * obj->capacity);
	if (obj->a == NULL)
	{
		perror("malloc");
		return;
	}
}

void DestorySeqList(SeqList* obj)
{
	assert(obj);

	free(obj->a);
	obj->a = NULL;
	obj->capacity = obj->size = 0;
}

void SeqListBackPush(SeqList* obj, SLDataType x)
{
	assert(obj);
	
	If_Add_Capacity(obj);

	obj->a[(obj->size)++] = x;

}

void SeqListBackPop(SeqList* obj)
{
	assert(obj);
	assert(obj->size > 0);//为真就过、为假就会报错
	
	obj->size--;
}

void SeqListPirnt(SeqList* obj) 
{
	assert(obj);
	for (int i = 0; i < obj->size; i++)
	{
		printf("%d ", obj->a[i]);
	}
	printf("\n");
}


void SeqListFrontPush(SeqList* obj, SLDataType x)
{
	assert(obj);

	If_Add_Capacity(obj);
	for (int i = obj->size; i > 0; i--)
	{
		obj->a[i] = obj->a[i - 1];
	}
	obj->a[0] = x;
	obj->size++;
}

void SeqListFrontPop(SeqList* obj)
{
	assert(obj);
	assert(obj->size > 0);
	for (int i = 0; i < obj->size - 1; i++)
	{
		obj->a[i] = obj->a[i + 1];
	}
	obj->size--;
}

void SeqListInsert(SeqList* obj, int pos, SLDataType x)
{
	assert(obj);
	pos -= 1;//换成下标
	assert(pos >= 0 && pos <= obj->size);
	If_Add_Capacity(obj);
	int i = obj->size;
	for (i; i > pos; i--)//从最后开始将填充数据
	{
		obj->a[i] = obj->a[i - 1];
	}
	obj->a[i] = x;
	obj->size++;
}

void SeqListErase(SeqList* obj, int pos)
{
	assert(obj);
	assert(obj->size > 0);

	pos -= 1;//换成下标
	assert(pos >= 0 && pos <= obj->size);

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

}

//test.c
//测试是否能用

 #define _CRT_SECURE_NO_WARNINGS 1

#include"SeqLIst.h"

int main()
{
	SeqList s;
	InitSeqList(&s);
	SeqListPush(&s, 1);
	SeqListPush(&s, 2);
	SeqListPush(&s, 3);
	SeqListPush(&s, 4);
	SeqListPush(&s, 5);

	SeqListPop(&s);
	SeqListPop(&s);
	SeqListPop(&s);

	SeqListFrontPush(&s, 0);

	SeqListFrontPush(&s, -1);

	SeqListInsert(&s, 1, 3);
	SeqListErase(&s, 2);
	SeqListPirnt(&s);

	DestorySeqList(&s);

	return 0;
}

分源管理时的头文件 :

持续更新大量数据结构细致内容,三连关注哈

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

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

相关文章

分析:如何多线程运行测试用例

这是时常被问到的问题&#xff0c;尤其是UI自动化的运行&#xff0c;过程非常耗时&#xff0c;所以&#xff0c;所以多线程不失为一种首先想到的解决方案。 多线程是针对的测试用例&#xff0c;所以和selenium没有直接关系&#xff0c;我们要关心的是单元测试框架。 unittest …

生态伙伴 | 华秋硬创联合湾加速,共同加速企业发展

01 大赛介绍 中国硬件创新创客大赛始于2015年&#xff0c;由深圳华秋电子有限公司主办&#xff0c;至今已经成功举办八届&#xff0c;赛事范围覆盖华南、华东、华北三大地区&#xff0c;超10个省市区域。 大赛影响了超过45万工程师群体&#xff0c;吸引了35000多名硬创先锋报…

云可观测性技术的应用领域及价值有哪些?

随着云计算的迅速发展&#xff0c;云可观测性技术成为了越来越重要的一项技术。它可以帮助企业实时监测、分析和优化其在云环境中运行的应用程序和系统&#xff0c;那云可观测性技术的应用领域及价值有哪些&#xff1f; 一、应用性能监测与优化 云可观测性技术使得企业能够实时…

(字符串) 844. 比较含退格的字符串——【Leetcode每日一题】

❓844. 比较含退格的字符串 难度&#xff1a;简单 给定 s 和 t 两个字符串&#xff0c;当它们分别被输入到空白的文本编辑器后&#xff0c;如果两者相等&#xff0c;返回 true 。# 代表退格字符。 注意&#xff1a;如果对空文本输入退格字符&#xff0c;文本继续为空。 示例…

【SpringBoot】整合Elasticsearch 快速入门操作索引

官网操作文档&#xff1a;Elasticsearch Clients | Elastic 踩坑太多了。。。这里表明一下Spring Boot2.4以上版本可能会出现问题&#xff0c;所以我降到了2.2.1.RELEASE。对于现在2023年6月而言&#xff0c;Es版本已经到了8.8&#xff0c;而SpringBoot版本已经到了3.x版…

【实战】Python爬虫之代理使用详解

在Python爬虫中&#xff0c;代理的使用非常常见。代理的主要作用是隐藏客户端的真实IP地址&#xff0c;从而实现更高的网络访问速度和更好的访问隐私保护。下面我们将通过Python爬虫的实例&#xff0c;带你详细了解Python爬虫中代理的使用方法。 目录 ## 1. 代理原理和作用 …

多维度员工信息整合查询——红海云员工信息数字化管理实用指南(中)

红海云员工全生命周期数字化管理平台从信息源头开始管控员工数据质量&#xff0c;在员工数据的采集、更新、审核环节采用多种方式保障员工信息的准确性、完整性、时效性和一致性&#xff0c;为企业搭建坚实可靠的人力资源管理数字化基座。但在有了准确可靠的员工数据基础后&…

APP测试应该从哪些方面入手?其实就这几点

前言 还在苦恼怎么去测APP吗&#xff1f; 一定要记住这几个方向&#xff0c;然后流程化的去执行&#xff0c;一来严谨规范&#xff0c;二来不会有遗漏。 1、需求检查&#xff1a; 在需求评审的时候展现你的业务能力啦&#xff01;不过还是得口下留情哟。&#xff08;PM心里瑟…

GitOps指南

GitOps基于CICD和IaC&#xff0c;以一致的方式管理代码和部署&#xff0c;是DevOps最佳实践之一。本文完整介绍了GitOps的理念和实践&#xff0c;并介绍了Weave Cloud的GitOps模型和工具&#xff0c;从整体上提供了实践GitOps的路径和方案。原文&#xff1a;Guide To GitOps[1]…

C++中的一些小技巧,numeric_limits、static_cast、reinterpret_cast方法内存验证

1、获取指定类型的最大值和最小值 在准备求一堆double数据中的最大值最小值的时候&#xff0c;常规做法是预估这堆数据的最大最小值&#xff0c;然后进行比较求&#xff0c;在重构别人代码的时候发现&#xff0c;可以准确知道double类型最大值或者最小值&#xff0c;获取方法如…

Apikit 自学日记:分享 API 文档

开启/关闭在线分享 您可以在线分享项目给团队以外的人&#xff0c;其他人可以通过分享链接在线查看API文档并且进行API测试。通过这种方式查看API文档不需要注册账号&#xff0c;用户可方便查看接口文档和测试接口。 在项目内&#xff0c;点击进入项目管理菜单&#xff0c;选择…

银河麒麟部署达梦8数据库开发者版本详细教程

我的系统信息如下&#xff1a; 系统架构&#xff1a;X86架构 系统信息&#xff1a;银河麒麟&#xff08;V10&#xff09; CPU&#xff1a;interl E5 官方安装文档&#xff1a;安装及卸载 | 达梦技术文档 (dameng.com) 数据库下载&#xff1a; 下载地址&#xff1a;产品下载…

【深度学习】2-5 神经网络-批处理

批处理&#xff08;Batch Processing&#xff09;是指在深度学习中每次迭代更新模型参数时同时处理多个样本的方式。 批处理时要注意对应维度的元素个数要一致 关于之前手写数字识别的例子&#xff1a; 用图表示&#xff0c;可以发现&#xff0c;多维数组的对应维度的元素个数…

体验DIY物联网浏览器(谷歌内核兼容性好支持H264视频播放)

一、功能及快捷键说明(说明32位兼容64位,版本往下看) 功能及快捷键图说明,不可多得的浏览器,支持右键自定义菜单... 二、下载安装包 2.1 版本 100.0.230 (支持H264版本)介绍 cefsharp物联网浏览器-支持H264(100.0.230)_cefsharp h264_久爱物联网的博客-CSDN博客 …

《论文阅读》用于情感分析的融合预训练表情符号特征增强

《论文阅读》用于情感分析的融合预训练表情符号特征增强 前言简介模型构架实验结果总结前言 你是否也对于理解论文存在困惑? 你是否也像我之前搜索论文解读,得到只是中文翻译的解读后感到失望? 小白如何从零读懂论文?和我一起来探索吧! 今天为大家带来的是《Fusion Pr…

SonarScanner扫描本地项目代码

一、Windows系统扫描 下载SonarScanner 去SonarQube官网下载相应系统的SonarScanner 点这里跳转 设置环境变量 下载好试个压缩文件&#xff0c;解压到你想存放的位置&#xff0c;设置环境变量 新增变量名&#xff1a;SONAR_SCANNER_HOME&#xff0c;值&#xff1a;你解压Sona…

ansible知识

在物理机查看环境&#xff0c;[kioskfoundation0 ~]$ cat /etc/rht 先清空当前环境&#xff0c;[kioskfoundation0 ~]$ rht-clearcourse 0 再切换rh294环境&#xff0c;[kioskfoundation0 ~]$ rht-setcourse rh294 验证环境是否切换成功&#xff0c;[kioskfoundation0 ~]$ cat…

2023年6月DAMA-CDGA/CDGP数据治理工程师认证找这家

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

清北「学渣」创业心路:AI 新时代已来,不参与对不起自己

内容一览&#xff1a;近日&#xff0c;HyperAI 超神经有幸接触到 SegmentFault AIGC Hackathon 2023 北京站二等奖获得者 OAISIS 团队&#xff0c;与他们畅聊了本次参赛的心路历程以及比赛之外团队的工作和生活。交谈中&#xff0c;三位年轻人显露出的自信、沉着、从容令人印象…

自动识别字幕

抖音官方出品的视频剪辑工具&#xff0c;国内版本和网易见外工作台一样&#xff0c;智能生成字幕功能只能识别中文和英文两种语言。 但是剪映国际版就支持英语、日语、韩语、葡萄牙语、俄语、印度尼西亚语、西班牙语还有德语总共八种语言。 剪映国际版字幕小助手 地址&#x…