顺序表详解

简介: 线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。


什么是顺序表呢?

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

顺序表分为静态顺序表和动态顺序表,我们重点讲动态的,因为实用性更大。


静态顺序表

使用定长的数组来存储数据。

//  静态
#define MAX 100
typedef int SLDateType;
typedef struct SeqList
{
  SLDateType arr[MAX];
  int size;  // 有效数据的个数
}SL;

ce848d7427844405955f02deb0051d69.png


动态顺序表

使用动态开辟的数组存储。

// 动态
typedef int SLDateType;
typedef struct SeqList
{
  SLDateType* arr;
  int size;      // 有效数据的个数
  int capacity;  // 容量空间的大小
}SeqList;

12abb88a80734148af567e6e1c82934f.png

接口实现

那么有哪些接口呢?

// 对数据的管理:增删查改 
// 顺序表的初始化
void SeqListInit(SeqList* ps);
// 顺序表销毁
void SeqListDestroy(SeqList* ps);
// 顺序表打印
void SeqListPrint(SeqList* ps);
// 顺序表尾插
void SeqListPushBack(SeqList* ps, SLDateType x);
// 顺序表头插
void SeqListPushFront(SeqList* ps, SLDateType x);
// 顺序表头删
void SeqListPopFront(SeqList* ps);
// 顺序表尾删
void SeqListPopBack(SeqList* ps);
// 顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos);

接下来我们来一一的实现这些接口。


初始化

我们这里主要讲的是动态的顺序表,我们假定刚开始给顺序表设置为4个元素,不够用我们就扩容。

//初始化
void SeqListInit(SeqList* ps)
{
//防止ps为空指针
  assert(ps);
  ps->arr = (SLDateType*)malloc(sizeof(SLDateType) * 4);
  //判断是够开辟成功
  if (ps->arr == NULL)
  {
    perror("malloc falled");
    return;
  }
  ps->size = 0;
  ps->capacity = 4;
}

打印

打印比较简单,我们只需要遍历一遍顺序表就可以了。

// 打印顺序表
void SeqListPrint(SeqList* ps)
{
  assert(ps);
  for (int i = 0; i < ps->size; i++)
  {
    printf("%d ", ps->arr[i]);
  }
  printf("\n");
}

销毁顺序表

我们需要将动态开辟的内存释放了,然后将数据和容量都置为0.

// 销毁顺序表
void SeqListDestroy(SeqList* ps)
{
  assert(ps);
  free(ps->arr);
  ps->size = 0;
  ps->capacity = 0;
}

尾删

尾删只需要将有效数据的个数减少一下就可以了,但是在这之前要判断顺序表中是否有元素,如果没有就没必要删了。

// 尾删
void SeqListPopBack(SeqList* ps)
{
  assert(ps);
  assert(ps->size);
  ps->size--;
}

尾插

尾插只要在size的位置放一个数据就可以了,也是比较简单的。


但是在插入之前我们为了防止容量不够,我们再分装一个函数来判断顺序表是否满了,如果满了我们就扩容。我们这里假设一次扩2倍,这个比较灵活,自己掌握就行。

//扩容
void SLCheckCapacity(SeqList* ps)
{
  if (ps->size == ps->capacity)
  {
    SLDateType* cur = (SLDateType*)realloc(ps->arr, ps->capacity * 2 * sizeof(SLDateType));
    if (cur == NULL)
    {
      perror("realloc");
      return;
    }
    ps->arr = cur;
    ps->capacity *= 2;
  }
}
//尾插
void SeqListPushBack(SeqList* ps, SLDateType x)
{
  assert(ps);
  SLCheckCapacity(ps);
  ps->arr[ps->size] = x;
  ps->size++;
}

头删

我们只需要将后面的数据依次往前挪动,然后将size–就可以了,这里从前往后挪,从后往前挪数据会被覆盖。

// 头插
void SeqListPushFront(SeqList* ps, SLDateType x)
{
  assert(ps);
  SLCheckCapacity(ps);
  int end = ps->size;
  while (end > 0)
  {
    ps->arr[end] = ps->arr[end - 1];
    end--;
  }
  //循环结束end==0
  ps->arr[end] = x;
  ps->size++;
}

查找

我们遍历顺序表,找到返回下标,找不到返回-1.

// 查找  找到返回下标否则返回-1
int SeqListFind(SeqList* ps, SLDateType x)
{
  assert(ps);
  for (int i = 0; i < ps->size; i++)
  {
    if (ps->arr[i] == x)
    {
      return i;
    }
  }
  return -1;
}

在下标pos的位置插入数据

我们只需要将pos位置到最后的数据依次往后挪动,然后将arr[pos]改为x,size++即可。但是我们依然要判断是否满容。

// 在pos下标位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x)
{
  assert(ps);
  //判断pos是否合法
  assert(pos >= 0 && pos <= ps->size);
  SLCheckCapacity(ps);
  int end = ps->size;
  while (end > pos)
  {
    ps->arr[end] = ps->arr[end - 1];
    end--;
  }
  ps->arr[pos] = x;
  ps->size++;
}

删除pos位置的数据

这个就比较简单了,我们只需要将pos后面的数据依次往前挪,覆盖pos,size–,即可。

// 删除pos下标的数据
void SeqListErase(SeqList* ps, int pos)
{
  assert(ps);
  //判断pos是否合法
  assert(pos >= 0 && pos < ps->size);
  int begin = pos + 1;
  while (begin < ps->size)
  {
    ps->arr[begin - 1] = ps->arr[begin];
    begin++;
  }
  ps->size--;
}

修改pos位置的元素为x

这个直接将arr[pos]改为x就行啦,这里就不给大家实现了。


今天的分享就到这里,感谢大家的关注和支持。

相关文章
|
机器学习/深度学习 人工智能 自然语言处理
第10章 经典智能算法——10.1 粒子群算法的MATLAB实现(1)
第10章 经典智能算法——10.1 粒子群算法的MATLAB实现(1)
|
JavaScript 前端开发
el-upload上传文件
el-upload上传文件
1224 0
|
6月前
|
运维 分布式计算 监控
Dataphin深度评测:企业级数据中台的智能实践利器
Dataphin是一款以全链路治理、智能提效和高兼容性为核心的企业级数据中台工具,特别适用于中大型企业的复杂数据场景。其流批一体能力、资源监控工具及行业化模板库可显著提升数据治理水平并降低运维成本。通过周期补数据功能,历史数据修复效率提升约60%;智能建模功能使建模时间缩短50%。尽管在数据源支持(如SAP HANA、DB2)和用户体验上仍有改进空间,但其强大的功能使其成为构建企业级数据中台的优选工具,尤其适合零售、金融等行业需要高效数据治理与实时分析的企业。
|
7月前
|
JSON API 数据格式
关键词搜索爱回收商品列表API接口(爱回收API系列)
爱回收作为二手电子产品交易平台,提供丰富的商品资源。其API接口允许开发者通过关键词搜索商品列表,获取商品名称、类别、品牌、预估回收价格等信息,支持分页展示和自定义每页数量。接口采用HTTP GET请求,响应格式为JSON。以下是Python示例代码,展示如何使用该接口进行搜索。
|
消息中间件 人工智能 Cloud Native
社区胜于代码,我们在阿帕奇软件基金会亚洲大会聊了聊开源中间件的未来
阿帕奇基金会亚洲大会顺利召开,阿里云消息技术负责人林清山在主论坛做了《阿里云中间件持续进化:从分布式应用架构向云原生 AI 原生应用架构全面升级》的演讲,从云厂商的视角分享了贡献开源、推动社区发展的过程,希望通过 AI 开发框架+AI 观测能力+AI 网关 + 事件驱动,一站式助力大模型应用落地。
417 98
社区胜于代码,我们在阿帕奇软件基金会亚洲大会聊了聊开源中间件的未来
|
10月前
|
存储 安全 关系型数据库
权限组件是怎么设计的
【10月更文挑战第26天】在实际设计过程中,还需要根据具体的业务需求和技术架构进行灵活调整和优化。
|
缓存 运维 关系型数据库
PolarDB产品使用问题之如何进行PolarDBX的本地部署
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
Java Maven
intellij idea如何查看项目maven依赖关系图
这篇文章介绍了如何在IntelliJ IDEA中查看项目的Maven依赖关系图,包括使用Maven工具栏和相关操作来展示和查看依赖细节。
|
前端开发 Java
springboot项目中外卖用户下单业务功能之需求分析+数据模型+功能开发(详细步骤)
springboot项目中外卖用户下单业务功能之需求分析+数据模型+功能开发(详细步骤)
247 0
|
存储 缓存 物联网
新EDPB指南:不只是Cookie
保障中国企业符合《个人信息保护法》合规,方案包括梳理基线、发现敏感信息、简化评估工作流、快速响应权利请求、满足告知同意要求,以及有效保护敏感数据。用九智汇整合自动化工具和规则引擎,确保高效风险评估、合规证据链建立,进一步保障数据安全。
217 1