数据结构:顺序表(C实现)

在这里插入图片描述

个人主页 水月梦镜花
个人专栏 C语言 ,数据结构


文章目录

  • 一、顺序表
  • 二、实现思路
    • 1.存储结构
    • 2.初始化顺序表(SeqListInit)
    • 3.销毁顺序表(SeqListDestroty)
    • 4.打印顺序表(SeqListPrint)
    • 5.顺序表尾插(SeqListPushBack)and检查容量(SeqListCheckCapacity)
    • 6.顺序表头插(SeqLsitPushFront)
    • 7.顺序表尾删(SeqListPopBack)
    • 8.顺序表头删(SeqListPopFront)
    • 9.顺序表查找(SeqListFind)
    • 10.在pos位置前插入元素(SeqListInsert)
    • 11.删除pos位置的值(SeqListErase)
  • 三、代码实现
  • 总结


一、顺序表

顺序表是用一段物理结构连续的存储单元依次存储数据元素的线性结构,一般采用数组存储。
顺序表一般分为两种:

  • 静态顺序表:使用定长数组实现
  • 动态顺数表:使用动态开辟的数组实现

本篇文章,顺序表是使用动态开辟的数组实现(动态顺序表)。要实现的功能如下:

//初始化顺序表
void SeqListInit(SeqList* ps);

//销毁顺序表
void SeqListDestroty(SeqList* ps);

//打印顺序表
void SeqListPrint(SeqList* ps);

//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDateType x);

//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDateType x);

//顺序表尾删
void SeqListPopBack(SeqList* ps);

//顺序表头删
void SeqListPopFront(SeqList* ps);

//顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);

//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDateType x);

//删除pos位置的值
void SeqListErase(SeqList* ps, int pos);

//检查容量
void SeqListCheckCapacity(SeqList* ps);

二、实现思路

画图理解起来更佳!!!

1.存储结构

我们重命名int类型为SLDataType,方便以后我们修改顺序表存储元素的类型。
指针data指向动态开辟的空间,变量sz记录有效的数据元素,变量capacity记录动态开辟空间的大小。

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* data;
	int sz;
	int capacity;
}SeqList;

2.初始化顺序表(SeqListInit)

动态开辟一块空间,用data指针保存空间首地址。
此时data指向空间中有效元素为0,使sz == 0,变量capacity在等于此时开辟空间的大小。

#define SIZE 4

void SeqListInit(SeqList* ps)
{
	ps->data = (SLDataType*)malloc(sizeof(SLDataType) * SIZE);
	if (ps->data == NULL)
	{
		perror("malloc");
		exit(-1);
	}

	ps->sz = 0;
	ps->capacity = SIZE;
}

3.销毁顺序表(SeqListDestroty)

free所开辟的空间,使data == NULL,此时数据有效元素为0,空间大小为0,那么sz = 0,capacity = 0;

//销毁顺序表
void SeqListDestroty(SeqList* ps)
{
	assert(ps);

	//free(ps);
	free(ps->data);
	ps->data = NULL;
	ps->sz = 0;
	ps->capacity = 0;
}

4.打印顺序表(SeqListPrint)

这个函数非常简单,只要遍历一遍所开辟的空间即可,注意范围是(0,sz)。

//打印顺序表
void SeqListPrint(SeqList* ps)
{
	assert(ps);

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

}

5.顺序表尾插(SeqListPushBack)and检查容量(SeqListCheckCapacity)

每次加入数据时,我们要先检查空间大小是否充足,再加入数据

  • 检查容量
    在尾插数据前,要检查空间大小是否充足(sz == capacity),如果空间大小不够,要扩大空间大小,capacity记录新的空间大小。

  • 尾插元素
    变量sz不仅代表空间有效元素个数,也代表了新数据元素将要放入的位置。所以尾插元素,只要空间大小充足,那么在data[sz]处放入数据即可,不要忘记sz要加一。

//检查容量
void SeqListCheckCapacity(SeqList* ps)
{
	SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * ps->capacity * 2);
	if (tmp == NULL)
	{
		perror("realloc");
		exit(-1);
	}

	ps->data = tmp;
	ps->capacity *= 2;
}



//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
	assert(ps);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	ps->data[ps->sz] = x;
	ps->sz++;
}

6.顺序表头插(SeqLsitPushFront)

顺序表除了尾插,尾删不用挪到数据,其它的增删都要挪到数据。
头插数据,要先检查空间大小,再向后挪到数据,将数据放入data[0]处,sz在加一。

//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDataType x)
{
	assert(ps);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	int end = ps->sz;
	while (end > 0)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	ps->data[0] = x;
	ps->sz++;
}

7.顺序表尾删(SeqListPopBack)

变量sz代表有效数据的个数,那么只要sz减一,就代表最后一个数据被删除了。

//顺序表尾删
void SeqListPopBack(SeqList* ps)
{
	assert(ps);
	assert(ps->sz != 0);

	ps->sz--;
}

8.顺序表头删(SeqListPopFront)

头删数据,要将数据从后向前挪到,覆盖掉第一个数据,sz要减一。

//顺序表头删
void SeqListPopFront(SeqList* ps)
{
	assert(ps);
	assert(ps->sz != 0);

	for (int i = 0; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}

9.顺序表查找(SeqListFind)

遍历一遍动态开辟的数组,如果找到了就放回下标,没有就放回-1。

//顺序表查找
int SeqListFind(SeqList* ps, SLDataType x)
{
	assert(ps);

	for (int i = 0; i < ps->sz; i++)
	{
		if (ps->data[i] == x)
		{
			return i;
		}
	}

	return -1;
}

10.在pos位置前插入元素(SeqListInsert)

要先检查空间容量是否充足和要插入的位置是否合法(要在顺序表的有效数据内),再将pos下标后的数据向后挪到,将数据放入data[pos]处,sz加一。
这个函数思路简单,但要注意下面两点:

  • 如果pos == 0,不就是要在顺序表第一个元素前插入元素,不就是顺序表的头插。
  • 如果pos == sz,我们知道sz还表示下一个数据要放入的位置,那么我在下一个数据要放入的位置前插入元素,不就是顺序表的尾插。

理解这点后,我们以后的头插,尾插都可以用该函数复用。方便我们手撕顺序表

//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->sz);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	int end = ps->sz;
	while (end > pos)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	ps->data[pos] = x;
	ps->sz++;
}

11.删除pos位置的值(SeqListErase)

删除pos位置处的数据,先检查pos的合法性(要属于[0,sz-1]),要将数据从后向前挪到数据,sz减一。
这个函数思路简单,但要注意下面两点:

  • 如果pos == 0,不就是要删除第一个数据,不就是头删。
  • 如果pos == sz - 1,不就是要删除最后一个数据,不就是尾删。

所以对于尾删,头删函数而言,我们也可以使用该函数复用。

//删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->sz);

	for (int i = pos; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}

三、代码实现

头删,头插,尾删,尾插我都复用了SeqListInsert和SeqListErase。
SeqList.h 文件存放有关函数的声明以及结构体的声明
SeqList.c 文件存放函数的定义

//SeqList.h 文件

#pragma once

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

#define SIZE 4

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* data;
	int sz;
	int capacity;
}SeqList;



//初始化顺序表
void SeqListInit(SeqList* ps);

//销毁顺序表
void SeqListDestroty(SeqList* ps);

//打印顺序表
void SeqListPrint(SeqList* ps);

//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDateType x);

//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDateType x);

//顺序表尾删
void SeqListPopBack(SeqList* ps);

//顺序表头删
void SeqListPopFront(SeqList* ps);

//顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);

//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDateType x);

//删除pos位置的值
void SeqListErase(SeqList* ps, int pos);

//检查容量
void SeqListCheckCapacity(SeqList* ps);
//SeqList.c 文件

#include "SeqList.h"


//初始化顺序表
void SeqListInit(SeqList* ps)
{
	ps->data = (SLDataType*)malloc(sizeof(SLDataType) * SIZE);
	if (ps->data == NULL)
	{
		perror("malloc");
		exit(-1);
	}

	ps->sz = 0;
	ps->capacity = SIZE;
}

//检查容量
void SeqListCheckCapacity(SeqList* ps)
{
	SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * ps->capacity * 2);
	if (tmp == NULL)
	{
		perror("realloc");
		exit(-1);
	}

	ps->data = tmp;
	ps->capacity *= 2;
}



//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
	/*assert(ps);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	ps->data[ps->sz] = x;
	ps->sz++;*/

	SeqListInsert(ps, ps->sz, x);
}


//打印顺序表
void SeqListPrint(SeqList* ps)
{
	assert(ps);

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

}


//销毁顺序表
void SeqListDestroty(SeqList* ps)
{
	assert(ps);

	//free(ps);
	free(ps->data);
	ps->data = NULL;
	ps->sz = 0;
	ps->capacity = 0;
}


//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDataType x)
{
	/*assert(ps);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	int end = ps->sz;
	while (end > 0)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	ps->data[0] = x;
	ps->sz++;*/

	SeqListInsert(ps, 0, x);
}


//顺序表尾删
void SeqListPopBack(SeqList* ps)
{
	/*assert(ps);
	assert(ps->sz != 0);

	ps->sz--;*/

	SeqListErase(ps, ps->sz - 1);
}

//顺序表头删
void SeqListPopFront(SeqList* ps)
{
	/*assert(ps);
	assert(ps->sz != 0);

	for (int i = 0; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;*/

	SeqListErase(ps, 0);
}


//顺序表查找
int SeqListFind(SeqList* ps, SLDataType x)
{
	assert(ps);

	for (int i = 0; i < ps->sz; i++)
	{
		if (ps->data[i] == x)
		{
			return i;
		}
	}

	return -1;
}


//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->sz);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	int end = ps->sz;
	while (end > pos)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	ps->data[pos] = x;
	ps->sz++;
}


//删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->sz);

	for (int i = pos; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}

总结

以上就是顺序表的实现。谢谢支持!!!

在这里插入图片描述

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

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

相关文章

Excel 两列数据中相同的数据进行同行显示

一、要求 假设您有两个列&#xff0c;分别是A列和B列&#xff0c;需要在C列中找出A列对应的B列的值。 二、方案 方法1&#xff1a;寻常思路 凸显重复项对A列单独进行筛选–按颜色进行排序&#xff0c;然后升序对B列重复上述操作即可 方法2&#xff1a;两个公式 VLOOKUP 纵向查找…

Python计算统计分析MSE 、RMSE、MAE、R2

1、平均绝对误差 (MAE)Mean Absolute Error&#xff0c;是绝对误差的平均值&#xff0c;能更好地反映预测值误差的实际情况。范围[0,∞)&#xff0c;当预测值与真实值完全吻合时等于0&#xff0c;即完美模型&#xff1b;误差越大&#xff0c;该值越大。 2、均方误差 MSE(mean…

VBA技术资料MF34:检查Excel自动筛选是否打开

【分享成果&#xff0c;随喜正能量】聪明人&#xff0c;抬人不抬杠&#xff1b;傻子&#xff0c;抬杠不抬人。聪明人&#xff0c;把别人抬得很高&#xff0c;别人高兴、舒服了&#xff0c;看你顺眼了&#xff0c;自然就愿意帮你&#xff01;而傻人呢&#xff1f;不分青红皂白&a…

【FAQ】关于无法判断和区分用户与地图交互手势类型的解决办法

一&#xff0e; 问题描述 当用户通过缩放手势、平移手势、倾斜手势和旋转手势与地图交互&#xff0c;控制地图移动改变其可见区域时&#xff0c;华为地图SDK没有提供直接获取用户手势类型的API。 二&#xff0e; 解决方案 华为地图SDK的地图相机有提供CameraPosition类&…

Day_71-76 BP 神经网络

目录 一. 基础概念理解 1. 一点个人理解 2. 神经网络 二. bp神经网络的局部概念 1. 神经元 2. 激活函数 三. bp神经网络的过程 1. 算法流程图 2. 神经网络基础架构 2.1 正向传播过程 2.2 反向传播过程&#xff08;算法核心&#xff09; 四. 基本bp神经网络的代码实现 1. 抽象…

1300*B. T-primes

解析&#xff1a; 有且只有三个因数&#xff0c;当且仅当&#xff0c;完全平方数并且sqrt&#xff08;n&#xff09;为素数 #include<bits/stdc.h> using namespace std; typedef long long ll; const int N1e55; ll t,n; bool prime(ll x){if(x<2) return 0;for(int…

Idea 结合docker-compose 发布项目

Idea 结合docker-compose 发布项目 这里写目录标题 Idea 结合docker-compose 发布项目Docker 开启远程访问功能 添加相应端口配置IDEA 链接Docker配置项目 docker-compose.yml本地还需要安装 dockerwin11 安装本地Docker 可能存在问题 Linux内核不是最新 Docker 开启远程访问功…

使用langchain与你自己的数据对话(二):向量存储与嵌入

之前我以前完成了“使用langchain与你自己的数据对话(一)&#xff1a;文档加载与切割”这篇博客&#xff0c;没有阅读的朋友可以先阅读一下&#xff0c;今天我们来继续讲解deepleaning.AI的在线课程“LangChain: Chat with Your Data”的第三门课&#xff1a;向量存储与嵌入。 …

spring-authorization-server (1.1.1)自定义认证

前言 注意&#xff1a;我本地没有生成公钥和私钥&#xff0c;所以每次启动项目jwkSource都会重新生成&#xff0c;导致之前认证的token都会失效&#xff0c;具体如何生成私钥和公钥以及怎么配置到授权服务器中&#xff0c;网上有很多方法自行实现即可 之前有个项目用的0.0.3的…

4、Linux驱动开发:设备-设备号设备号注册

目录 &#x1f345;点击这里查看所有博文 随着自己工作的进行&#xff0c;接触到的技术栈也越来越多。给我一个很直观的感受就是&#xff0c;某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了&#xff0c;只有经常会用到的东西才有可能真正记…

医学案例|ROC曲线

一、案例介绍 研究者想要进行“糖化血蛋白”的研究&#xff0c;对糖尿病患者和非糖尿病患者各100名检测糖化血红蛋白&#xff08;HbAlc&#xff09;含量&#xff0c;希望可以研究糖化血蛋白对患有糖尿病的情况是否有诊断价值&#xff0c;如果有最佳的诊断界值是多少。 二、问…

Android Banner - ViewPager

现在来给viewpager实现的banenr加上自动轮播 自动轮播的原理&#xff0c;使用handler的延迟消息来实现。 自动轮播实现如下内容 开始轮播&停止轮播 可配置轮播时长、轮播方向 通过自定义属性来配置轮播时长&#xff0c;方向 感知生命周期&#xff0c;可见时开始轮播&…

Activity 生命周期

在Android开发中&#xff0c;Activity是应用程序的主要组件之一&#xff0c;它代表应用程序中的一个屏幕或界面。当用户与应用程序进行交互时&#xff0c;Activity会根据用户的操作而启动、暂停、恢复或停止等&#xff0c;这些状态变化被称为Activity的生命周期。 Activity的生…

springboot创建并配置环境(二) - 配置基础环境

文章目录 一、介绍二、配置系统属性和环境变量三、配置自定义属性命令行参数四、作为应用配置信息 一、介绍 在上一篇文章&#xff1a;springboot创建并配置环境(一) - 创建环境中我们探讨了springboot是如何根据当前应用程序类型去创建对应的环境实例的。接下来探讨如何去配置…

亚马逊云科技联合霞光社发布《2013~2023中国企业全球化发展报告》

中国企业正处于全球聚光灯下。当企业全球化成为时代发展下的必然趋势&#xff0c;出海也从“可选项”变为“必选项”。中国急速扩大的经济规模&#xff0c;不断升级的研发和制造能力&#xff0c;都在推动中国企业不断拓宽在全球各行业的疆域。 过去十年&#xff0c;是中国企业…

管理后台低代码PaaS平台源码:点击鼠标,就能编程

低代码平台源码10大核心功能:1建模引擎 、2 移动引擎 、3,流程引擎 5.报表引擎、6安全引擎、 7 API引擎 、8.应用集成引擎、 9.代码引擎、 10.公式引擎。 一、低代码开发特色 1.低代码开发&#xff1a;管理后台提供了一系列易于使用的低代码开发工具&#xff0c;使企业可以快速…

TSINGSEE青犀视频安防监控视频平台EasyCVR新增密码复杂度提示

智能视频监控平台TSINGSEE青犀视频EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTM…

getInputStream has already been called for this request 问题记录

问题背景 HttpServletRequest.getReader() HttpServletRequest.getInputStream() 不能在过滤器中读取一次二进制流&#xff08;字符流&#xff09;&#xff0c;又在另外一个Servlet中读取一次&#xff0c;即一个InputSteam(BufferedReader)对象在被读取完成后&#xff0c;将无…

安全第一天

1. 编码 1.1 ASCLL编码 ASCII 是基于拉丁字母的一套电脑编码系统&#xff0c;主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准&#xff0c;并等同于国际标准ISO/IEC 646。 1.2 URL编码 URL&#xff1a;&#xff08;统一资源定位器、定位地址&#xff0c;俗称网页…

Ubuntu 曝Linux漏洞,近 40% 用户受影响

Bleeping Computer 网站披露&#xff0c;Wiz 研究人员 s.Tzadik 和 s.Tamari 发现 Ubuntu 内核中存在两个 Linux 漏洞 CVE-2023-32629 和 CVE-2023-2640&#xff0c;没有特权的本地用户可能利用其在设备上获得更高权限&#xff0c;影响大约 40% 的 Ubuntu 用户。 Ubuntu 是目前…