C语言实现顺序表--数据结构

news2024/10/6 10:29:02

在这里插入图片描述

  • 魔王的介绍:😶‍🌫️一名双非本科大一小白。
  • 魔王的目标:🤯努力赶上周围卷王的脚步。
  • 魔王的主页:🔥🔥🔥大魔王.🔥🔥🔥
    请添加图片描述
    ❤️‍🔥大魔王与你分享:“提亚马特都有失去主动的一天,更何况是满身破绽的你呢”。

文章目录

  • 一、前言
  • 二、顺序表实现
    • 1、创建结构体
    • 2、初始化
    • 3、销毁
    • 4、检查
    • 5、打印
    • 6、尾插
    • 7、尾删
    • 8、头插
    • 9、头删
    • 10、查找
    • 11、插入
    • 12、删除
    • 13、注意事项
  • 三、总代码
    • SeqList.h
    • SeqList.c
    • Test.c
  • 四、总结

一、前言

顺序表是线性表的一种,它就如同字面意思一般,在内存是按顺序存储的,如果你还不理解,那你想想你一直用的数组,它就是顺序表的原理,在内存中连续存放的,因此地址也是连续的。如图:

在这里插入图片描述

二、顺序表实现

1、创建结构体

虽然顺序表只是单纯的一个数组,但是要知道,我们在使用顺序表时,需要增删查改这些操作,那么对于在内存中连续存贮的顺序表,我们怎样快速找到它呢,我们怎样确定这个顺序表有几个元素呢,那就需要定义一个变量来记录这个顺序表的元素。至于为什么让他们俩连起来弄在结构体里,那当然是因为这样可以避免传一堆参数,没弄好自己就蒙了,命名了一堆的变量名,所以我们让他们放在结构体里,方便一起操作。

当然,因为要实现的顺序表是动态的,也就是会自己扩容,避免空间不够或者空间浪费,所以我们在结构体里还需要弄一个新的变量,那就是记录当前顺序表的大小。当元素个数与顺序表的大小相等时,我们就需要扩容了。

代码:

#define InitCapacity 5

typedef int SLDateType;

typedef struct SeqList
{
	SLDateType* a;
	int size;
	int capacity;
}SL;

2、初始化

创建完这个结构体,我们需要给结构体里的元素初始化,封装成一个函数,在给数组指针初始化时,我们给他一个初始大小,等以后不够再自动扩容。

代码:

void SLInit(SL* pc)
{
	assert(pc);
	pc->a = (SLDateType*)malloc(sizeof(SLDateType) * InitCapacity);
	pc->size = 0;
	pc->capacity = InitCapacity;
}

3、销毁

因为是动态开辟的,所以内存是再堆区的,当我们用完如果不销毁,那么只能等程序结束才会自动销毁,如果没结束不会自动释放,所以当我们用完后需要手动释放。

代码:

void SLDestroy(SL* pc)
{
	assert(pc);
	free(pc->a);
	pc->size = 0;
	pc->capacity = 0;
	pc->a = NULL;
}

4、检查

现在我们来实现刚才一直说的扩容,当顺序表容量满的时候,我们需要扩容,那么怎样检查又怎样扩容呢,请看下面代码实现。

代码:

void SLCheck(SL* pc)
{
	assert(pc);
	if (pc->capacity == pc->size)
	{
		int* str = realloc(pc->a, pc->capacity * sizeof(SLDateType) * 2);
		if (str == NULL)
		{
			perror("realloc fail");
			return;//返回之后的流程是什么:会打印出开辟失败的一行信息,但接下来的步骤还会进行,比如越界什么的,强行执行后面的操作。
		}
		else
		{
			pc->a = str;
			str = NULL;
		}
		pc->capacity = pc->capacity * 2;
	}
}

注意在扩容时,需要先用一个临时指针操作,否则如果开辟失败,返回一个空指针,空指针的值赋给了原本的指针,那么这个数组的地址就找不到了,那么损失就大了。所以当开辟成功时,再把这个临时指针的值赋给新指针,并把临时指针置空,防止野指针。

5、打印

为了验证等会下面的增删查改,我们先实现一个打印函数,然后等写好功能后来验证。

代码:

void SLPrint(SL* pc)
{
	assert(pc);
	for (int i = 0; i < pc->size; i++)
	{
		printf("%d ", pc->a[i]);
	}
}

6、尾插

首先来实现一下尾插,在尾插时,第一步当然是判断顺序表是否满了,如果,满了我们还插入内容,那就越界访问了。这一步弄完,我们直接插入值就行了,插入到下标为元素个数的位置即可,因为数组下标是从0开始的。最后就是让我们结构体里统计个数的那个变量加一就行了。

代码:

void SLPushBack(SL* pc, SLDateType x)
{
	assert(pc);
	SLCheck(pc);
	pc->a[pc->size] = x;
	pc->size++;
}

7、尾删

尾删特别简单,先判断该顺序表是否有内容,如果有,那么直接让个数减一就ok了,其他不用管,因为打印是根据个数打印的。

代码:

void SLPopBack(SL* pc)
{
	assert(pc);
	assert(pc->size);
	pc->size--;
}

8、头插

头插比较麻烦,说的麻烦是效率麻烦,因为需要逐个遍历,全部都向后移动一位,然后让size+1。实现并不难,因为顺序表整体都是简单的。

代码:

void SLPushFront(SL* pc, SLDateType x)
{
	assert(pc);
	SLCheck(pc);
	for (int end = pc->size - 1; end >= 0; end--)
	{
		pc->a[end + 1] = pc->a[end];
	}
	pc->a[0] = x;
	pc->size++;
}

9、头删

头删和头插一样,都是需要逐个遍历,这个是都向前移动一位,然后让size-1。

代码:

void SLPopFront(SL* pc)
{
	assert(pc);
	assert(pc->size);
	for (int begin = 1; begin <= pc->size - 1; begin++)
	{
		pc->a[begin - 1] = pc->a[begin];
	}
	pc->size--;
}

10、查找

查找也和简单,就是从第一个元素逐个遍历,然后返回找到的位置下标,如果没有找到,就返回-1。

代码:

int SLFind(SL* pc, SLDateType x)
{
	assert(pc);
	assert(pc->size);
	for (int i = 0; i < pc->size; i++)
	{
		if (x == pc->a[i])
		{
			return i;
		}
	}
	return -1;
}

11、插入

实现了头插尾插, 那如果我们想从内部插入呢,其实原理是一样的,让某个地方之后的都向后移动一位,当然这之前需要判断是否满了。最后size+1。

代码:

void SLInsert(SL* pc, int pos, SLDateType x)
{
	assert(pc);
	int end = pc->size - 1;
	if (pos >= 0 && pos <= pc->size)
	{
		SLCheck(pc);
		while (end >= pos)
		{
			pc->a[end + 1] = pc->a[end];
			end--;
		}
		pc->a[pos] = x;
		pc->size++;
	}
}

12、删除

实现了头删和尾删,如果我们想从内部某个位置删除,就需要再写一个代码了,原理也是一样的,先判断有没有元素,然后让从这个位置之后的都向前进一。最后size-1。

代码:

void SLErase(SL* pc, int pos)
{
	assert(pc);
	assert(pc->size);//可有可无
	int begin = pos + 1;
	if (pos >= 0 && pos < pc->size)
	{
		while (begin < pc->size)
		{
			pc->a[begin - 1] = pc->a[begin];
			begin++;
		}
		pc->size--;
	}
}

13、注意事项

  • 我们在进行插入时,挪动元素位置需要先挪后边再挪前边,否则会覆盖原数组的值,移动后所对应的就不是原来的值了。
  • 相同的,在进行删除时,也需要考虑这方面,不过跟插入是相反的,我们需要先挪动前边的,不然会覆盖原数组的值,移动后就不是原来数组的值了。

三、总代码

SeqList.h

SeqList.h

#pragma once

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

#define InitCapacity 5

typedef int SLDateType;

typedef struct SeqList
{
	SLDateType* a;
	int size;
	int capacity;
}SL;

//初始化
void SLInit(SL* pc);

//结束,销毁
void SLDestroy(SL* pc);

//检查是否需要扩容
void SLCheck(SL* pc);

//打印
void SLPrint(SL* pc);

//尾插
void SLPushBack(SL* pc, SLDateType x);

//尾删
void SLPopBack(SL* pc);

//头插
void SLPushFront(SL* pc, SLDateType x);

//头删
void SLPopFront(SL* pc);

//查找
int SLFind(SL* pc, SLDateType x);

//插入(从0开始,也就是按照的是下标而不是个数)
void SLInsert(SL* pc, int pos, SLDateType x);

//删除(从0开始,也就是按照的是下标而不是个数)
void SLErase(SL* pc, int pos);

SeqList.c

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqList.h"

void SLInit(SL* pc)
{
	assert(pc);
	pc->a = (SLDateType*)malloc(sizeof(SLDateType) * InitCapacity);
	pc->size = 0;
	pc->capacity = InitCapacity;
}

void SLDestroy(SL* pc)
{
	assert(pc);
	free(pc->a);
	pc->size = 0;
	pc->capacity = 0;
	pc->a = NULL;
}

void SLCheck(SL* pc)
{
	assert(pc);
	if (pc->capacity == pc->size)
	{
		int* str = realloc(pc->a, pc->capacity * sizeof(SLDateType) * 2);
		if (str == NULL)
		{
			perror("realloc fail");
			return;//返回之后的流程是什么:会打印出开辟失败的一行信息,但接下来的步骤还会进行,比如越界什么的,强行执行后面的操作。
		}
		else
		{
			pc->a = str;
			str = NULL;
		}
		pc->capacity = pc->capacity * 2;
	}
}

void SLPrint(SL* pc)
{
	assert(pc);
	for (int i = 0; i < pc->size; i++)
	{
		printf("%d ", pc->a[i]);
	}
}

void SLPushBack(SL* pc, SLDateType x)
{
	assert(pc);
	SLCheck(pc);
	pc->a[pc->size] = x;
	pc->size++;
}

void SLPopBack(SL* pc)
{
	assert(pc);
	assert(pc->size);
	pc->size--;
}

void SLPushFront(SL* pc, SLDateType x)
{
	assert(pc);
	SLCheck(pc);
	for (int end = pc->size - 1; end >= 0; end--)
	{
		pc->a[end + 1] = pc->a[end];
	}
	pc->a[0] = x;
	pc->size++;
}

void SLPopFront(SL* pc)
{
	assert(pc);
	assert(pc->size);
	for (int begin = 1; begin <= pc->size - 1; begin++)
	{
		pc->a[begin - 1] = pc->a[begin];
	}
	pc->size--;
}

int SLFind(SL* pc, SLDateType x)
{
	assert(pc);
	assert(pc->size);
	for (int i = 0; i < pc->size; i++)
	{
		if (x == pc->a[i])
		{
			return i;
		}
	}
	return -1;
}

void SLInsert(SL* pc, int pos, SLDateType x)
{
	assert(pc);
	int end = pc->size - 1;
	if (pos >= 0 && pos <= pc->size)
	{
		SLCheck(pc);
		while (end >= pos)
		{
			pc->a[end + 1] = pc->a[end];
			end--;
		}
		pc->a[pos] = x;
		pc->size++;
	}
}

void SLErase(SL* pc, int pos)
{
	assert(pc);
	assert(pc->size);//可有可无
	int begin = pos + 1;
	if (pos >= 0 && pos < pc->size)
	{
		while (begin < pc->size)
		{
			pc->a[begin - 1] = pc->a[begin];
			begin++;
		}
		pc->size--;
	}
}

Test.c

Test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqList.h"

void test1()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 0);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPushBack(&s, 5);
	SLPushBack(&s, 6);
	SLPopBack(&s);
	SLPushFront(&s, 9);
	SLPopFront(&s);
	SLPopFront(&s);
	SLPopFront(&s);
	SLPopFront(&s);
	int i = 0;
	i = SLFind(&s, 4);
	if (i != -1)
	{
		printf("下标为%d\n", i);
	}
	SLPrint(&s);
}
void test2()
{
	SL s;
	SLInit(&s);
	SLPushFront(&s, 3);
	SLInsert(&s, 0, 0);
	SLInsert(&s, 0, 1);
	SLInsert(&s, 0, 5);
	SLInsert(&s, 0, 6);
	SLInsert(&s, 0, 7);
	SLInsert(&s, 2, 8);
	SLInsert(&s, 0, 9);
	SLErase(&s, 2);
	SLPrint(&s);
}

void test3()
{
	SL s;
	SLInit(&s);
	SLPushFront(&s, 0);
	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 4);
	SLPushFront(&s, 5);
	SLPushFront(&s, 6);
	SLPrint(&s);
}
int main()
{
	//test1();
	//test2();
	test3();
	return 0;
}

四、总结

在这里插入图片描述

✨请点击下面进入主页关注大魔王
如果感觉对你有用的话,就点我进入主页关注我吧!

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

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

相关文章

项目管理中引入PMO的应用研究——以H研究所为例

摘 要 本文从项目管理办公室&#xff08;PMO&#xff09;的基本内涵出发&#xff0c;探讨了PMO在以“项目”为主要工作组织方式的H研究所应用过程中发挥的作用、具有的优势、取得的成效与存在的不足&#xff0c;从而实现为企业培养专业的项目经理团队&#xff0c;为业务部门定…

Ubuntu20.04安装CUDA和CUDNN

CUDA是GPU深度学习的运行库&#xff0c;那么cuDNN就是训练加速工具&#xff0c;两者要相互配合使用&#xff0c;所以一般机器学习需要训练引擎(tensorflow-gpu) CUDA cuDNN使用。想不安装cuDNN是不可以的&#xff0c;而且cuDNN版本要和CUDA版本相互搭配。 1、前置工作 查看…

最新动态 | 大势智慧参加广东省应急测绘保障与安全生产演练

4月20日&#xff0c;2023年度广东省应急测绘保障与安全生产演练在台山市赤溪镇鱼塘湾举行。本次演练由广东自然资源厅主办&#xff0c;广东省国土资源测绘院、江门市自然资源局和台山市人民政府承办。在省市各指导单位与参演单位的多方协同与指挥下&#xff0c;应急测绘保障与安…

常用PLC学习资料下载地址

常见PLC的资料一般在官网都可以找到&#xff0c;今天整理一下&#xff0c;把西门子、三菱、欧姆龙、汇川四家品牌的官方下载地址直接贴出来供大家直接使用。 1、汇川技术官方网站 汇川技术 - 推进工业文明 共创美好生活 (inovance.com)https://www.inovance.com/2、汇川技术资料…

TCP重传、滑动窗口、流量控制、拥塞控制

目录 重传机制 #超时重传 SACK 方法 Duplicate SACK 滑动窗口 流量控制 窗口关闭 拥塞控制 慢启动 拥塞避免算法 拥塞发生 快速恢复 重传机制 TCP 实现可靠传输的方式之一&#xff0c;是通过序列号与确认应答。 在 TCP 中&#xff0c;当发送端的数据到达接收主机时…

rancher部署flink集群

rancher版本&#xff1a;v2.6.8 k8s版本&#xff1a;v1.22.13rke2r1 flink集群版本&#xff1a;1.15.0 flink安装模式&#xff1a;session cluster 写在前面&#xff1a;因为参照官网的说明安装过程中出现了很多问题&#xff0c;特记录于此&#xff0c;避免后续重复踩坑 目…

FE_CSS 精灵图技术 字体图标 CSS三角

一个网页中往往会应用很多小的背景图像作为修饰&#xff0c;当网页中的图像过多时&#xff0c;服务器就会频繁地接收和发送请求图片&#xff0c;造成服务器请求压力过大&#xff0c;这将大大降低页面的加载速度。 因此&#xff0c;为了有效地减少服务器接收和发送请求的次数&a…

国内申请日本专利有哪些流程?

日本2004年修订的实用新型法已经于2005年4月1日生效&#xff0c;在日本&#xff0c;“专利”这一概念限于发明&#xff0c;实用新型和外观设计均不称为专利。实用新型授权后&#xff0c;就叫实用新型权&#xff0c;并不叫专利权。而且&#xff0c;发明、实用新型和外观设计是“…

掘金Tiktok电商比亚马逊刺激多了

鑫优尚电子商务&#xff1a;万亿跨境电商市场&#xff0c;聚光灯照在了Tiktok&#xff08;抖音海外版&#xff09;身上。 美国、巴西、俄罗斯、越南……2017年年末才正式出海的Tiktok&#xff0c;仅在2年后便覆盖了150个国家和地区&#xff0c;多次登顶App Store下载量首位。 …

使用 Vaex 处理具有 2 亿行的数据集

在这篇文章中,我们生成了 2 亿条时序人工数据,有 4 列,大小接近 12GB。使用 Pandas 库无法读取数据集并对其进行探索和可视化。与 pandas 相比,能够将字符串处理速度提高10-1000 倍。比spark快近十倍。 Pandas是用于数据科学案例研究的最受欢迎的库之一。它是探索性数据分…

rtthread默认网卡的操作

设置网卡优先级 在 RT-Thread 操作系统中&#xff0c;可以通过修改网卡的优先级来设置默认网卡。优先级越高的网卡会被优先选择为默认网卡。 下面介绍一些设置默认网卡优先级的方法&#xff1a; 在 RT-Thread 的网络配置文件 rtconfig.h 中&#xff0c;可以通过修改 NETIF_P…

SAP CAP篇一:快速创建一个Service,基于Java的实现

这个博客上&#xff0c;还没有写过SAP技术栈的东西&#xff0c;这次开个头&#xff0c;写个最近研究SAP CAP的摸索过程。虽然SAP CAP&#xff08;Cloud Application Model&#xff09;关注在Cloud的开发&#xff0c;我这些文章里面还是偏重本地上的尝试。 文章目录 前置内容现在…

当Kotlin Flow与Channel相逢

Flow之所以用起来香&#xff0c;Flow便捷的操作符功不可没&#xff0c;而想要熟练使用更复杂的操作符&#xff0c;那么需要厘清Flow和Channel的关系。 本篇文章构成&#xff1a; 1. Flow与Channel 对比 1.1 Flow核心原理与使用场景 原理 先看最简单的Demo&#xff1a; fun…

编写 LuCI CBI 模型

编写 LuCI CBI 模型 CBI模型是描述UCI配置文件结构的Lua文件&#xff0c;并且CBI解析器将lua文件转为HTML呈现给用户 。 所有 CBI 模型文件都必须返回类型为luci.cbi.Map的对象。 CBI 模型文件的范围由 luci.cbi 模块的内容和 luci.i18n 的转换函数自动扩展。 CBI控件类型汇总 …

如何使用ESP32-CAM构建一个人脸识别系统

有许多人识别系统使用签名、指纹、语音、手部几何、人脸识别等来识别人&#xff0c;但除了人脸识别系统。 人脸识别系统不仅可以用于安全目的来识别公共场所的人员&#xff0c;还可以用于办公室和学校的考勤目的。 在这个项目中&#xff0c;我们将使用 ESP32-CAM 构建一个人脸识…

eclipse for abap下载及配置安装

一&#xff0c;下载eclipse &#xff0c;地址 https://www.eclipse.org/downloads/download.php?file/oomph/epp/2023-03/R/eclipse-inst-jre-win64.exe 可以选择(大连东软信息学院)端口下载&#xff0c;这样开一些&#xff0c; 二&#xff1a;双击安装&#xff0c;安装FOR…

放弃手动测试,快来了解JMeter压测神器的安装和使用吧~~

目录&#xff1a;导读 引言 jmeter的安装 JMeter是干什么的 JMeter都可以做那些测试 JMeter的使用和组件介绍 下面我们进行XML格式的实战练习 jmeter与postman的区别 JSON的插件 另附视频教程资源 引言 你是否曾经为手动测试而苦恼&#xff1f;是不是觉得手动测试太费…

Windows Java JavaFX Idea 开发环境搭建

博文目录 文章目录 JavaFX 简单说明JavaFX 版本说明JavaFX 与 JDK 的关系JavaFX 与 JDK Modular (JDK 9 模块化系统)JavaFX 模块说明 (JavaFX 20)JavaFX Scene Builder构建 JavaFX 应用程序的两种选择 环境搭建 建议先阅读下方引用的官方文档, 与本章节做相互印证与理解版本选…

Vue 3组件传值 、组件通信

本文采用<script setup />的写法&#xff0c;比options API更自由。那么我们就来说说以下七种组件通信方式&#xff1a; props emit v-model refs provide/inject eventBus vuex/pinia 举个例子 本文将使用下面的演示&#xff0c;如下图所示&#xff1a; 上图中…

【社区图书馆】《新程序员005:开源深度指南 新金融背后的科技力量》

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰来给大家推荐一本书&#xff0c;此书的书名为新程序员005&#xff1a;开源深度指南 & 新金融背后的科技力量&#xff0c;为什么小雅兰今天要给大家推荐这样一本书呢&#xff1f;好啦&#xff0c;现在&#xff0c;…