数据结构:顺序表(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 4void 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 4typedef 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--;
}

总结

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

在这里插入图片描述

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

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

相关文章

K8S群集调度

目录 一、调度约束二、Pod 启动典型创建过程三、K8S的调度过程3.1 Predicate&#xff08;预选策略&#xff09; 常见的算法使用3.2 常见优先级选项3.3 指定调度节点3.3.1 nodeName指定3.3.2 nodeSelector指定3.3.3 Pod亲和性与反亲和1.节点亲和硬策略示例2.节点亲和软策略示例3…

linux -网络编程-多线程并发服务器

目录 1.三次握手和四次挥手 2 滑动窗口 3 函数封装思想 4 高并发服务器 学习目标&#xff1a; 掌握三次握手建立连接过程掌握四次握手关闭连接的过程掌握滑动窗口的概念掌握错误处理函数封装实现多进程并发服务器实现多线程并发服务器 1.三次握手和四次挥手 思考: 为什么…

【javaSE】 面向对象程序三大特性之继承

目录 为什么需要继承 继承的概念 继承的语法 注意事项 父类成员访问 子类中访问父类的成员变量 子类和父类不存在同名成员变量 子类和父类成员变量同名 访问原则 子类中访问父类的成员方法 成员方法名字不同 总结&#xff1a; 成员方法名字相同 总结&#xff1a; …

【决策树-鸢尾花分类】

决策树算法简介 决策树是一种基于树状结构的分类与回归算法。它通过对数据集进行递归分割&#xff0c;将样本划分为多个类别或者回归值。决策树算法的核心思想是通过构建树来对数据进行划分&#xff0c;从而实现对未知样本的预测。 决策树的构建过程 决策树的构建过程包括以…

数据结构:单链表的实现(C语言)

个人主页 &#xff1a; 水月梦镜花 个人专栏 &#xff1a; 《C语言》 《数据结构》 文章目录 前言一、单链表实现思路和图解1.节点的定义(SListNode)2.申请一个节点(BuySListNode)3.单链表打印(SListPrint)4.单链表尾插(SListPushBack)5.单链表的头插(SListPushFront)6.单链表的…

【目标检测】基于yolov5的水下垃圾检测(附代码和数据集,7684张图片)

写在前面: 首先感谢兄弟们的订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 路虽远,行则将至;事虽难,做则必成。只要有愚公移山的志气、滴水穿石的毅力,脚踏实地,埋头苦干,积跬步以至千里,就…

行云管家荣获CFS第十二届财经峰会 “2023产品科技创新奖”

7月26日至27日&#xff0c;CFS第十二届财经峰会暨2023可持续商业大会在京盛大召开。峰会主题为“激活高质量发展澎湃活力”&#xff0c;超1000位政商领袖、专家学者、企业及媒体代表出席了本次盛会&#xff0c;共同分享新技术新产品新趋势、研判全球新挑战与新变局下企业的机遇…

【方法】PDF可以转换成Word文档吗?如何操作?

很多人喜欢在工作中使用PDF&#xff0c;因为PDF格式可以准确地保留文档的原始格式&#xff0c;比如字体、图像、布局和颜色等。 但如果编辑文档的话&#xff0c;PDF还是没有Word文档方便。那可以将PDF转换成Word格式&#xff0c;再来编辑吗&#xff1f;如何操作呢&#xff1f;…

接口自动化测试平台

下载了大神的EasyTest项目demo修改了下<https://testerhome.com/topics/12648 原地址>。也有看另一位大神的HttpRunnerManager<https://github.com/HttpRunner/HttpRunnerManager 原地址>&#xff0c;由于水平有限&#xff0c;感觉有点复杂~~~ 【整整200集】超超超…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(13)-Fiddler请求和响应断点调试

1.简介 Fiddler有个强大的功能&#xff0c;可以修改发送到服务器的数据包&#xff0c;但是修改前需要拦截&#xff0c;即设置断点。设置断点后&#xff0c;开始拦截接下来所有网页&#xff0c;直到取消断点。这个功能可以在数据包发送之前&#xff0c;修改请求参数&#xff1b…

JVM复习(史上最全!!!)

一、JDK、JRE、JVM的区别 JDK: 全称Java Development Kit&#xff0c;是 Java 语言的软件开发工具包&#xff0c;主要用于移动设备、嵌入式设备上的Java应用程序。JDK是整个Java开发的核心。 JRE: JRE&#xff0c;全称Java Runtime Environment&#xff0c;是指Java的运行环境&…

开放麒麟1.0发布一个月后,到底怎么样?另一款操作系统引发热议

具有里程碑意义 7月5日&#xff0c;国产首个开源桌面操作系统“开放麒麟1.0”正式发布。 标志着我国拥有了操作系统组件自主选型、操作系统独立构建的能力&#xff0c;填补了我国在这一领域的空白。 举国欢庆&#xff0c;算的上是里程碑意义了&#xff01; 发布后用着如何&a…

【业务功能篇57】Springboot + Spring Security 权限管理 【上篇】

4.权限管理模块开发 4.1 权限管理概述 4.1.1 权限管理的意义 后台管理系统中&#xff0c;通常需要控制不同的登录用户可以操作的内容。权限管理用于管理系统资源&#xff0c;分配用户菜单、资源权限&#xff0c;以及验证用户是否有访问资源权限。 4.1.2 RBAC权限设计模型 …

redis的并发安全问题:redis的事务VSLua脚本

redis为什么会发生并发安全问题&#xff1f; 在redis中&#xff0c;处理的数据都在内存中&#xff0c;数据操作效率极高&#xff0c;单线程的情况下&#xff0c;qps轻松破10w。反而在使用多线程时&#xff0c;为了保证线程安全&#xff0c;采用了一些同步机制&#xff0c;以及多…

windows中注册redis服务启动时报1067错误

注册完redis服务&#xff0c;打开计算机 服务时确实有redis服务存在&#xff0c;但是点击启动时却报1067错误&#xff0c;而命令行用redis-server.exe redis.windows.conf 命令却也可以启动 查看6379的端口也没有被占用&#xff08;netstat -ano | findstr :6379&#xff09; …

Mac 定时重启 TouchBar 脚本(缓解闪烁问题)

背景 Mac 笔记本 TouchBar 是真的脆啊&#xff0c;合盖使用一段时间就废了&#xff0c;右侧一直闪烁简直亮瞎眼 &#x1f602; 经过观察&#xff0c;总结出闪烁规律如下&#xff1a; 工作状态&#xff1a;不断操作电脑时&#xff0c;触控栏处于工作状态&#xff0c;几乎不闪…

Apipost教程?一篇文章玩转Apipost

你是否经常遇到接口开发过程中的各种问题&#xff1f;或许你曾为接口测试与调试的繁琐流程而烦恼。不要担心&#xff01;今天我将向大家介绍一款功能强大、易于上手的接口测试工具——Apipost&#xff0c;并带你深入了解如何玩转它&#xff0c;轻松实现接口测试与调试。 什么是…

1992-2021年全国及31省对外开放度测算数据含原始数据和计算过程(无缺失)

1992-2021年全国及31省对外开放度测算数据含原始数据和计算过程&#xff08;无缺失&#xff09; 1、时间&#xff1a;1992-2021年 2、范围&#xff1a;全国及31省 3、指标&#xff1a;进出口总额、国内生产总值、年均汇率 4、计算方法&#xff1a;对外开放度进出口总额/GDP…

【Linux 网络】 HTTPS协议原理 对称加密 非对称加密 数字证书

HTTPS协议 HTTPS协议和HTTP协议的区别什么是“加密” 和“解密”加密和解密的小故事 为什么要进行加密&#xff1f;臭名昭著的“运营商劫持”事件 常见加密方式对称加密非对称加密 数据摘要数字签名 HTTPS工作过程探究方案 1 &#xff1a; 只使用对称加密方案2 &#xff1a; 只…

从0到1开发go-tcp框架【2-实现Message模块、解决TCP粘包问题、实现多路由机制】

从0到1开发go-tcp框架【2-实现Message模块、解决TCP粘包问题、实现多路由机制】 1 实现\封装Message模块 zinx/ziface/imessage.go package zifacetype IMessage interface {GetMsdId() uint32GetMsgLen() uint32GetMsgData() []byteSetMsgId(uint32)SetData([]byte)SetData…