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

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

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,一经查实,立即删除!

相关文章

pytorch学习3-torchvisin和Dataloader的使用

系列文章目录 pytorch学习1-数据加载以及Tensorboard可视化工具pytorch学习2-Transforms主要方法使用pytorch学习3-torchvisin和Dataloader的使用pytorch学习4-简易卷积实现pytorch学习5-最大池化层的使用pytorch学习6-非线性变换&#xff08;ReLU和sigmoid&#xff09;pytorc…

开启三层交换机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…

Fabric.js 实战开发使用介绍

原生canvas用的多的有哪些槽点就不用我多说了&#xff1b;fabric 作为一个canvas库&#xff0c;提供了非常高效、直观的API操作&#xff0c;使我们对涉及canvas相关的功能开发效率大幅提升~~~~ 简单记录下自己的心得&#xff1b;以下是对比canvas来说的优势&#xff1a; 1.简…

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要学&…

【HDFS运维】HDFS回收箱机制:原理、配置、配置可能导致的问题分析

文章目录 一. HDFS回收箱机制逻辑1. 基本逻辑2. 举例说明 二. 配置测试1. 配置2. 回收箱相关命令 三. 其他问题讨论1. api不会走trash机制2. 因为设置了Trash configuration导致nn无法响应 一. HDFS回收箱机制逻辑 1. 基本逻辑 If trash configuration is enabled, files remo…

Quartus II 13.1入门使用方法

Quartus II是由Altera Corporation&#xff08;现为英特尔旗下的Intel Programmable Solutions Group&#xff09;发布的一款综合性的FPGA设计软件。Quartus II提供了从设计输入和综合到优化、验证和仿真的全套解决方案。下面是一个关于Quartus II 13.1版本入门级使用方法的简要…

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

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

鸿蒙(HarmonyOS)应用开发——构建更加丰富的页面(题目答案)

判断题 1.State修饰的属性不允许在本地进行初始化。 错误(False) 解析&#xff1a; State isExpanded: boolean false;2.CustomDialog装饰器用于装饰自定义弹窗组件&#xff0c;使得弹窗可以自定义内容及样式。 正确(True) 3.将Video组件的controls属性设置为false时&…

剪刀石头布游戏

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…

Centos 搭建Git私有服务器

要在CentOS上搭建Git私有服务器&#xff0c;您可以按照以下步骤进行操作&#xff1a; 安装和配置Git服务器软件&#xff1a; 确保您的CentOS系统已经安装了Git软件包。您可以使用yum命令安装Git&#xff1a;sudo yum install git。如果您想使用企业级的Git服务器&#xff0c;可…

如何有效预防内存泄漏?

1.前言 最近部门不同产品接连出现内存泄漏导致的网上问题&#xff0c;具体表现为单板在现网运行数月以后&#xff0c;因为内存耗尽而导致单板复位现象。 一方面&#xff0c;内存泄漏问题属于低级错误&#xff0c;此类问题遗漏到现网&#xff0c;影响很坏&#xff1b;另一方面…

微信小程序基础

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

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

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

java google.zxing解析二维码工具类

文章目录 pom代码解析用例生成二维码用例 pom <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.0</version> </dependency>代码 import com.google.zxing.*; import com.google…

通俗理解Jenkins是什么?

目录 通俗理解 Jenkins是什么&#xff1f; 通俗理解 假设你有一个软件项目&#xff0c;多个开发者在一起写代码。每当有人提交新的代码时&#xff0c;你想要自动地构建、测试这些代码&#xff0c;确保它们没有引入问题。 Jenkins就像一个聪明的助手&#xff0c;会在有人提交…

【数据仓库-10】-- 数据仓库、数据湖和湖仓一体对比

目录 1 数据仓库与数据库的对比 2 数据湖与数据仓库的对比 3 数据仓库、数据湖和湖仓一体

检查 `/var` 是否有自己的独立分区

要检查 /var 是否有自己的独立分区&#xff0c;您可以使用以下方法&#xff1a; 1. 使用 df 命令 df 命令&#xff08;磁盘文件系统&#xff09;可以用来报告文件系统的磁盘空间使用情况。要查看 /var 的情况&#xff0c;请运行&#xff1a; df -h /var这个命令会显示 /var …

在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则是该领域中处理的利器。这篇文…