初级数据结构(一)——顺序表

文中代码源文件已上传:数据结构源码

1、顺序表的特点

1.1、数组

        现实中数据记录一般都记录在表格中,如进货单、菜单等,它们的最大特点就是有序。表述中可以用第一项、第二项、第 n 项来描述表格中某个数据或者某串数据。在 C 语言中,数组的特点恰好匹配此功能。

        由于数组在内存中的储存方式就如同列表依序排布,对数组可以用 arr[n] 或者 *(arr+n) 来迅速获得第 n-1 项数据。再加上而且数组是 C 语言的原生类型,创建数组极其便利,作为有序数据的载体着实是不二之选。

1.2、结构

        顺序表为了方便使用,除了用数组作为数据载体外,一般还包含记录数组空间大小和开辟空间大小的两个变量。常以结构体将这三个变量作为成员变量进行囊括。主要有两种创建方式:

        柔性数组顺序表( Sequence table with flexible array ):

#include <stdlib.h>//重定义数据类型
typedef int DATA;//创建并重定义结构体类型
typedef struct SeqTab
{int size;           //数据长度int capacity;       //数据空间大小DATA arr[];         //数据载体柔性数组
}SeqTab;int main()
{//开辟结构体空间SeqTab* sqList = (SeqTab*)malloc(sizeof(SeqTab) + sizeof(DATA)*4);//初始化数据长度及空间大小sqList->size = 0;sqList->capacity = 4;return 0;
}

        数组指针顺序表( Sequence table with array pointer ):

#include <stdlib.h>//重定义数据类型
typedef int DATA;//创建并重定义结构体类型
typedef struct SeqTab
{int size;           //数据长度int capacity;       //数据空间大小DATA* arr;          //数据载体数组指针
}SeqTab;int main()
{//创建结构体变量SeqTab sqList;//开辟数据载体数组空间sqList.arr = (DATA*)malloc(sizeof(DATA)*4);//初始化数据长度及空间大小sqList.size = 0;sqList.capacity = 4;return 0;
}

2、顺序表创建

        接下来以数组指针顺序表为例进行演示。

2.1、文件结构

        seqTab.h :用于创建结构体类型及声明函数;

        sqFunction.c :用于创建顺序表初始化及增删改查的函数;

        main.c :仅创建 main 函数,用作测试。

2.2、前期工作

        在 seqTab.h 中先写入以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>//用于初始化顺序表时开辟空间
#define INIT_SIZE 4//顺序表数据类型,方便顺序表储存数据类型修改
typedef int DATATYPE;//创建顺序表结构体类型
typedef struct SeqTab
{DATATYPE* data;int size;int capacity;
}SeqTab;//---------------------函数声明---------------------
//初始化顺序表
extern void DataInit(SeqTab*);//销毁顺序表
extern void DataDestory(SeqTab*);//打印顺序表
extern void DataPrint(const SeqTab*);

         在 sqFunction.c 中包含 seqTab.h 并分别创建一个初始化顺序表和销毁顺序表的函数:

#include "seqTab.h"//初始化顺序表
void DataInit(SeqTab* sq)
{//断言确保结构体指针不为空assert(sq);//为顺序表开辟空间sq->data = (DATATYPE*)malloc(INIT_SIZE * sizeof(DATATYPE));//加入判断防止空间开辟失败if (sq->data == NULL){perror("Malloc Fail");return;}//初始化记录数据长度及开辟空间长度的变量sq->size = 0;sq->capacity = INIT_SIZE;
}//销毁顺序表
void DataDestory(SeqTab* sq)
{//断言确保结构体指针不为空assert(sq);//释放顺序表数据空间free(sq->data);//数组指针置空sq->data = NULL;//数组长度及空间尺寸全部置0sq->size = 0;sq->capacity = 0;
}//打印顺序表
void DataPrint(const SeqTab* sq)
{//断言确保结构体指针不为空assert(sq);//遍历顺序表并逐个数据打印for (int i = 0; i < sq->size; i++){printf("%d ", sq->data[i]);}printf("\n");
}

        最后在 main.c 中包含 seqTab.h,并创建一个顺序表及初始化:

#include "seqTab.h"int main()
{//创建顺序表SeqTab sqList;//初始化顺序表DataInit(&sqList);return 0;
}

        至此,前期工作准备完毕,之后便是对顺序表的数据进行增删改查。

3、顺序表操作

3.1、增

        插入数据一般为头部插入数据、尾部插入数据及指定位置插入数据。插入数据时除了写入数据到数组中,还需时刻判断开辟的空间尺寸是否足以容纳已有数据。

        先将以下三个函数声明添加到 seqTab.h 中:

//指定位置插入数据
extern void DataInsert(SeqTab*, int, DATATYPE);
//头部插入数据
extern void DataPushHead(SeqTab*, DATATYPE);
//尾部插入数据
extern void DataPushTail(SeqTab*, DATATYPE);

        然后便是 DataInsert 函数。如图:

        据此可以轻松写出其代码。以下写入 sqFunction.c 中: 

void DataInsert(SeqTab* sq, int pos, DATATYPE data)
{//数据有效性判断assert(sq);if (pos < 0 || pos > sq->size){printf("Illegal Position : %d\n", pos);return;}//空间不足则创建空间if (sq->size + 1 >= sq->capacity){//申请新空间DATATYPE* ptr_newSqData = (DATATYPE*)realloc(sq->data, sizeof(DATATYPE) * (sq->capacity * 2));//空间申请结果判断if (ptr_newSqData == NULL){perror("Realloc Fail");return;}//赋予新空间地址sq->data = ptr_newSqData;//空间大小记录翻倍sq->capacity *= 2;}//数据后移直至腾出 pos 位置的空间for (int i = sq->size; i > pos; i--){sq->data[i] = sq->data[i - 1];}//写入数据*(sq->data + pos) = data;//数据长度+1sq->size++;
}

        至于头插尾插数据,只不过是上述函数 pos 位置的区别。因此:

//pos = 0 便是头插
void DataPushHead(SeqTab* sq, DATATYPE data)
{DataInsert(sq, 0, data);
}
//pos = 数据尺寸便是尾插
void DataPushTail(SeqTab* sq, DATATYPE data)
{DataInsert(sq, sq->size, data);
}

        在 main 函数里写入下列代码验证一下:

	DataInsert(&sqList, 10, 32);   //报错DataPushTail(&sqList, 10);DataPrint(&sqList);            //打印 10DataPushHead(&sqList, 20);DataPrint(&sqList);            //打印 20 10DataPushHead(&sqList, 3);DataPushTail(&sqList, 6);DataPushHead(&sqList, 8);DataPushHead(&sqList, 7);DataPushHead(&sqList, 2);DataPushTail(&sqList, 100);DataPushTail(&sqList, 432);DataPrint(&sqList);            //打印 2 7 8 3 20 10 6 10 432

        结果与预期无误。至此插入功能便已完成。

3.2、删

        正如插入数据分为头插、尾插及指定插,删除也分头删及任意位删。与插入相反,删除数据需要在数据删除结束后关注数据长度与开辟的数据空间,当空间分配过大时,对多余空间进行回收。

        同样先将以下三个函数声明添加到 seqTab.h 中:

//指定位置删除数据
extern void DataRemove(SeqTab*, int);
//删除头部数据
extern void DataPopHead(SeqTab*);
//删除尾部数据
extern void DataPopTail(SeqTab*);

         DataRemove 函数流程图如下:

        根据图中逻辑在 sqFunction.c 中写入以下:

void DataRemove(SeqTab* sq, int pos)
{//数据有效性判断assert(sq);if (pos < 0 || pos > sq->size - 1){printf("Illegal Position : %d\n", pos);return;}//列表不为空则执行if (sq->size - 1 >= 0){//由 pos 位开始,之后所有数据前移 1 位for (int i = pos; i < sq->size - 1; i++){sq->data[i] = sq->data[i + 1];}//数据长度-1sq->size--;}//开辟空间过大则执行if (sq->size < sq->capacity / 2){//申请新空间DATATYPE* ptr_newSqData = (DATATYPE*)realloc(sq->data, sizeof(DATATYPE) * (sq->capacity / 2));//空间申请结果判断if (ptr_newSqData == NULL){perror("Realloc Fail");return;}//赋予新空间地址sq->data = ptr_newSqData;//空间大小记录减半sq->capacity /= 2;}
}

         至于头删尾删数据,也同样是上述函数 pos 位置的区别:

//头删 pos = 0
void DataPopHead(SeqTab* sq)
{DataRemove(sq, 0);
}
//尾删 pos = 数据长度-1
void DataPopTail(SeqTab* sq)
{DataRemove(sq, sq->size - 1);
}

        之后同样是验证,将以下代码写到之前测试代码之后:

	DataRemove(&sqList, 100);    //报错DataRemove(&sqList, 3);DataPrint(&sqList);          //打印 2 7 8 20 10 6 100 432DataPopHead(&sqList);DataPrint(&sqList);          //打印 7 8 20 10 6 100 432DataPopTail(&sqList);DataPrint(&sqList);          //打印 7 8 20 10 6 100DataPopTail(&sqList);DataPopTail(&sqList);DataPopTail(&sqList);DataPopTail(&sqList);DataPopTail(&sqList);DataPrint(&sqList);          //打印 7DataPopTail(&sqList);DataPopTail(&sqList);DataPrint(&sqList);          //因为 size = 0 ,pos = -1 , 报错

         删除数据功能完毕。

3.3、改

        改数据的功能实现起来,逻辑上毫无难度可言。以下函数声明添加到 seqTab.h 中:

//修改指定位置数据
extern void DataModify(SeqTab*, int, DATATYPE);

         在 sqFunction.c 中写入:

void DataModify(SeqTab* sq, int pos, DATATYPE data)
{//数据有效性判断assert(sq);if (pos < 0 || pos > sq->size - 1){printf("Illegal Position : %d\n", pos);return;}//修改数据sq->data[pos] = data;
}

        在 main 函数中追加以下代码验证:

	for (int i = 0; i < 10; i++){DataPushTail(&sqList, i);}DataPrint(&sqList);            //打印 0 1 2 3 4 5 6 7 8 9DataModify(&sqList, 100, 30);  //报错DataModify(&sqList, 3, 30);DataPrint(&sqList);            //打印 0 1 2 30 4 5 6 7 8 9

         完毕。

3.4、查

        查到数据返回该数据的位置,查不到返回 -1 。同样很简单。 seqTab.h 中写入声明:

//在表中查找数据
extern int DataSearch(SeqTab*, DATATYPE);

        然后是 sqFunction.c 中写入:

int DataSearch(SeqTab* sq, DATATYPE data)
{//数据有效性判断assert(sq);//遍历数组for (int i = 0; i < sq->size; i++){//如果找到数据则返回下标if (sq->data[i] == data){return i;}}//遍历完毕仍找不到数据返回 -1return -1;
}

        main 函数中验证:

	int num = 1200;int pos = DataSearch(&sqList, num);if (pos == -1){printf("The number \"%d\" is not exist!\n", num);}else{printf("The position of number \"%d\" is %d\n", num, pos);}//打印不存在num = 9;pos = DataSearch(&sqList, num);if (pos == -1){printf("The number \"%d\" is not exist!\n", num);}else{printf("The position of number \"%d\" is %d\n", num, pos);}//打印 9DataModify(&sqList, DataSearch(&sqList, 8), 11001);DataPrint(&sqList);    //打印 0 1 2 30 4 5 6 7 11001 9

        至此增删改查功能实现均已完毕。除此之外,还有排序、截断等其他一系列可以自定的操作。总之,操作顺序表就是操作数组,实现起来难度几乎为 0 。

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

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

相关文章

开启三层交换机DHCP服务

二层交换机上不需要配置任何东西&#xff0c;只需要在pc机上开启dhcp服务&#xff0c;配置好LSW1后就可以自动获取到IP地址。 sys Enter system view, return user view with CtrlZ. [Huawei]sys sw1 [sw1]dhcp enable Info: The operation may take a few seconds. Please wai…

BUU UPLOAD COURSE 1

传一个cmd.php木马文件 访问一下这个图片地址 发现什么都没有&#xff0c;在hackbar里面连接一下我们的木马 然后看到了一些目录 然后直接查看flag就出来了 这里也可以用蚁剑去连接 直接访问地址&#xff0c;拿着地址去连接就行了。

大数据:sql,数据挖掘刷题

大数据&#xff1a;sql 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle&#xff0c;尤其sql要学&…

22款奔驰C260L升级小柏林音响 无损音质效果

奔驰新款C级号称奔驰轿车的小“S”&#xff0c;在配置方面上肯定也不能低的&#xff0c;提了一台低配的车型&#xff0c;通过后期升级加装件配置提升更高档次&#xff0c;打造独一无二的奔驰C级&#xff0c;此次来安排一套小柏林之声音响&#xff0c;效果怎么样&#xff0c;我们…

剪刀石头布游戏

csdn问答社区的一道题目&#xff0c;题目描述都像一篇论文了&#xff0c;界面设置不敢恭维&#xff0c;不过也算是可练手工程。 (笔记模板由python脚本于2023年12月05日 22:15:03创建&#xff0c;本篇笔记适合熟悉Python字典、列表、字符串的coder翻阅) 【学习的细节是欢悦的历…

[JavaScript前端开发及实例教程]计算器井字棋游戏的实现

计算器&#xff08;网页内实现效果&#xff09; HTML部分 <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>My Calculator&l…

微信小程序基础

1.小程序发展史 微信小程序之前&#xff0c;是使用weixin-sdk进行开发&#xff0c;调用视频&#xff0c;摄像头等。 微信小程序weixin up端&#xff0c;所以PC端的window这些没有&#xff0c;运行环境是IOS&#xff0c;安卓等&#xff0c;有一些特殊的调用录音功能&#xff0…

JavaScript 安全的《加/解密处理》的实战--案例(二)

前言: 在Web开发中&#xff0c;安全性一直是一个重要而复杂的议题&#xff0c;尤其是与敏感数据操作有关时。数据传输地过程中需要保证信息绝对的安全性&#xff0c;包括了诸如用户名、密码、个人信息等&#xff0c;这就需要对这类信息进行加密与解密。本案例&#xff08;二&a…

在AWS Lambda中使用FFmpeg处理m3u8视频流

大纲 1 部署有FFmpeg功能的Lambda环境1.1 部署层1.2 部署代码1.2.1 FFmpeg指令1.2.2 代码 2 配置Lambda角色权限2.1 选择角色类型2.2 设置权限2.3 保存角色2.4 绑定角色 参考文献 在直播里领域&#xff0c;我们经常需要对视频流进行处理。FFmpeg则是该领域中处理的利器。这篇文…

根文件系统的开机自启动测试

一. 简介 本文在之前制作的根文件系统可以正常运行的基础上进行的&#xff0c;继上一篇文章地址如下&#xff1a; 完善根文件系统-CSDN博客 在前面测试软件hello 运行时&#xff0c;都是等 Linux 启动进入根文件系统以后手动输入 “./hello” 命令 来完成的。 我们一般做好产…

Python计算方差

方差可以反应变量的离散程度&#xff0c;是因为它度量了数据点与均值的差异。方差是每个数据点与均值的差的平方和的平均值&#xff0c;它可以反映数据点在均值附近的分布情况。如果方差较小&#xff0c;说明数据点更加集中在均值附近&#xff0c;离散程度较小&#xff1b;如果…

uniapp微信小程序分包,小程序分包

前言&#xff0c;都知道我是一个后端开发、所以今天来写一下uniapp。 起因是美工给我的切图太大&#xff0c;微信小程序不让了&#xff0c;在网上找了一大堆分包的文章&#xff0c;我心思我照着写的啊&#xff0c;怎么就一直报错呢&#xff1f; 错误原因 tabBar的页面被我放在分…

【从零开始学习JVM | 第一篇】快速了解JVM

前言&#xff1a; 在探索现代软件开发的丰富生态系统时&#xff0c;我们不可避免地会遇到一个强大而神秘的存在——Java虚拟机&#xff08;JVM&#xff09;。作为Java语言最核心的组成之一&#xff0c;JVM已经超越了其最初的设计目标&#xff0c;成为一个多语言的运行平台&…

WPS Office JS宏实现批量处理Word中的标题和正文的样式

该篇讲解下word文档中的标题和正文批量修改样式&#xff0c;如下图&#xff1a; 前面一篇已讲解了WPS Office宏编辑器操作方法&#xff0c;这里不细讲了&#xff0c;如有不清楚可以查看该篇&#xff1a;https://blog.csdn.net/jiciqiang/article/details/134653657?spm1001.20…

Install4J安装界面中如何使用脚本找到依赖程序XShell的安装位置

前言 写了一个工具, 使用Install4j打包, 但因为需要用到XShell, 所以希望在安装界面能够提前让用户配置好XShell的安装位置, 所以对Install4j的安装界面需要自定义, 后期在程序中直接过去安装位置就可以正常使用. 调研 和git-bash不一样, 安装版的XShell没有在注册表里存储安…

Ubuntu系统下使用apt-get安装Redis

记录一下Ubuntu20.04 64位系统下使用apt-get安装Redis 首先检查一下系统是否安装过redis whereis redismywmyw-K84HR:~$ whereis redis redis: mywmyw-K84HR:~$ 更新软件包 sudo apt-get update -y安装redis sudo apt-get install redis-server -ymywmyw-K84HR:~$ sudo apt…

Java常见CodeReview及编码规范

鉴于自己的开发经验,以及常见容易产生bug及性能问题的点做个记录. 1.数据库 如果开发人员的经验不足,Java通过ORM(Mybatis)对数据库的操作的性能问题比较隐蔽.因为不压测或者异常case没发生的时候一般发现不了问题.特别是异常case发生的时候. 除配置表以外的sql都要经过expl…

Learning Memory-guided Normality for Anomaly Detection 论文阅读

Learning Memory-guided Normality for Anomaly Detection 摘要1.介绍2.相关工作3.方法3.1网络架构3.1.1 Encoder and decoder3.1.2 Memory 3.2. Training loss3.3. Abnormality score 4.实验5.总结总结&代码复现&#xff1a; 文章信息&#xff1a; 发表于&#xff1a;cvpr…

消息中间件之间的区别

一.单机吞吐量 ActiveMQ&#xff1a;万级&#xff0c;吞吐量比RocketMQ和Kafka要低了一个数量级 RabbitMQ&#xff1a;万级&#xff0c;吞吐量比RocketMQ和Kafka要低了一个数量级 RocketMQ&#xff1a;10万级&#xff0c;RocketMQ也是可以支撑高吞吐的一种MQ Kafka&#xff…

Python的requests库实现HTTPS

嘿&#xff0c;Python程序员们&#xff01;今天我们要来点刺激的——使用Python的requests库实现HTTPS请求&#xff01;是的&#xff0c;你没有听错&#xff0c;我们要一起迈入HTTPS的神秘世界&#xff01; 首先&#xff0c;我们来了解一下HTTPS是什么。HTTPS是HTTP Secure的缩…