【顺序表】

简介: 【顺序表】

顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存

储。在数组上完成数据的增删查改。

下面我们实现动态顺序表:

1. 函数声明部分

下面是顺序表结构体的定义和一些增删查改函数的声明;

#pragma once
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    //将顺序表中的指针类型起别名
    typedef int SLDataType;
    //创建一个结构体顺序表,存放顺序表的头指针,顺序表的长度,顺序表的容量
    typedef struct SeqList
    {
      SLDataType *a;
      int size;
      int capacity;
    }SL;
    //初始化
    void SLInit(SL* psl);
    //尾插和头插
    void SLPushBack(SL* psl, SLDataType x);
    void SLPushFront(SL* psl, SLDataType x);
    //尾删和头删
    void SLPopBack(SL* psl);
    void SLPopFront(SL* psl);
    //在pos位置插入x
    void SLInsert(SL* psl, size_t pos, SLDataType x);
    //删除pos位置的元素
    void SLErase(SL* psl, size_t pos);
    //修改数据
    void SLModify(SL* psl, size_t pos ,SLDataType x);
    //查找,找到返回下标,找不到返回-1
    int SLFind(SL* psl, SLDataType x);
    //打印
    void SLPrint(SL* psl);
    //归还空间
    void SLDestroy(SL* psl);

2. 函数的实现部分

由于一些头插,尾插等函数需要判断容量的大小,所以我们将检查容量的函数放到外面;若当前长度等于容量,即满了,用realloc开辟成原来两倍的空间;

//检查容量是否已满
    void CheakCapacity(SL* psl)
    {
      assert(psl);
      if (psl->size == psl->capacity)
      {
        SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(SLDataType) * psl->capacity * 2);
        assert(tmp);
        psl->a = tmp;
        psl->capacity *= 2;
      }
    }

(1)初始化

先为顺序表开辟4个大小的空间,当前容量为4,当前长度为0;

void SLInit(SL* psl)
    {
      assert(psl);
      psl->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
      assert(psl->a);
      psl->capacity = 4;
      psl->size = 0;
    }

(2)尾插

void SLPushBack(SL* psl, SLDataType x)
    {
      assert(psl);
      CheakCapacity(psl);
      psl->a[psl->size++] = x;
    }

(3)头插

void SLPushFront(SL* psl, SLDataType x)
    {
      assert(psl);
      CheakCapacity(psl);
      int i = psl->size - 1;
      for (i = psl->size - 1; i >= 0; i--)
      {
        psl->a[i + 1] = psl->a[i];
      }
      psl->a[i+1] = x;
      psl->size++;
    }

(4)尾删

void SLPopBack(SL* psl)
    {
      assert(psl);
      assert(psl->size > 0);
      psl->size--;
    }

(5)头删

void SLPopFront(SL* psl)
    {
      assert(psl);
      assert(psl->size > 0);
      for (int i = 1; i < psl->size; i++)
      {
        psl->a[i - 1] = psl->a[i];
      }
      psl->size--;
    }

(6)在pos位置插入x

void SLInsert(SL* psl, size_t pos, SLDataType x)
    {
      assert(psl);
      assert(pos >= 0 && pos <= psl->size);
      CheakCapacity(psl);
      SLDataType right = psl->size - 1;
      SLDataType left = pos;
      while (left <= right)
      {
        psl->a[right + 1] = psl->a[right];
        right--;
      }
      psl->a[left] = x;
      psl->size++;
    }

(7)删除pos位置的元素

void SLErase(SL* psl, size_t pos)
    {
      assert(psl);
      assert(pos >= 0 && pos < psl->size);
      while (pos < psl->size - 1)
      {
        psl->a[pos] = psl->a[pos + 1];
        pos++;
      }
      psl->size--;
    }

(8)修改数据

void SLModify(SL* psl, size_t pos, SLDataType x)
    {
      assert(psl);
      psl->a[pos] = x;
    }

(9)查找

找到返回下标,找不到返回-1

int SLFind(SL* psl, SLDataType x)
    {
      assert(psl);
      for (int i = 0; i < psl->size; i++)
      {
        if (psl->a[i] == x)
        {
          return i;
        }
      }
      return -1;
    }

(10)打印

void SLPrint(SL* psl)
    {
      assert(psl);
      for (int i = 0; i < psl->size; i++)
      {
        printf("%d ", psl->a[i]);
      }
    }

(11)归还空间

void SLDestroy(SL* psl)
    {
      assert(psl);
      free(psl->a);
      psl->a = NULL;
      psl->capacity = 0;
      psl->size = 0;
    }

3. 测试部分

int main()
    {
      SL s;
      SLInit(&s);
      SLPushBack(&s, 1);
      SLPushBack(&s, 2);
      SLPushBack(&s, 3);
      SLPushFront(&s, 10);
      SLPopFront(&s);
      SLPopBack(&s);
      SLInsert(&s, 1, 10);
      SLErase(&s, 1);
      SLModify(&s, 1, 100);
      SLPrint(&s);
      printf("\n");
      int ret = SLFind(&s, 100);
      if (ret != -1)
      {
        printf("找到了,下标为:%d\n", ret);
      }
      else
      {
        printf("找不到\n");
      }
      SLDestroy(&s);
      return 0;
    }

以上代码的结果:

通过上面的实现我们可以看出,顺序表还是有缺陷的:

  1. 中间/头部的插入删除,时间复杂度为O(N)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。
    例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
目录
相关文章
|
编解码 计算机视觉
OpenCV(三十六):霍夫直线检测
OpenCV(三十六):霍夫直线检测
462 0
|
机器学习/深度学习 异构计算 AI芯片
云端开炉,线上训练,Bert-vits2-v2.2云端线上训练和推理实践(基于GoogleColab)
对于笔者这样的穷哥们来讲,GoogleColab就是黑暗中的一道光,就算有训练时长限制,也能凑合用了,要啥自行车?要饭咱也就别嫌饭馊了,本次我们基于GoogleColab在云端训练和推理Bert-vits2-v2.2项目,复刻那黑破坏神角色莉莉丝(lilith)。
云端开炉,线上训练,Bert-vits2-v2.2云端线上训练和推理实践(基于GoogleColab)
|
Oracle 关系型数据库 API
实时计算 Flink版产品使用合集之当sink到elasticsearch时,可以指定es的指定字段吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
实时计算 Flink版产品使用合集之当sink到elasticsearch时,可以指定es的指定字段吗
|
机器学习/深度学习 人工智能 自然语言处理
TsingtaoAI亮相2025青岛西海岸科技成果对接会,以具身智能实训赋能AI人才培养
3月26日青岛——由青岛市科学技术局指导、青岛西海岸新区管委联合上海技术交易所等多家机构主办的“2025青岛西海岸新区科技成果对接会”在青岛金沙滩蓝海御华酒店盛大启幕。青岛市委常委,西海岸新区工委书记、区委书记孙永红,青岛市科学技术局副局长张栋华和上海技术交易所总裁颜明峰等参加会议并致辞。TsingtaoAI受邀参会并发表主题分享,公司负责人汶生以《基于DeepSeek的具身智能实训》为题,向与会嘉宾展示了AI具身智能技术如何突破传统边界,助力AI人才从实验室走向产业一线。
332 1
|
传感器 监控 物联网
PWM在物联网中的应用
PWM(脉冲宽度调制)在物联网中广泛应用,通过控制信号的占空比来调节设备的工作状态,如LED亮度、电机速度等,实现高效、精确的控制,常用于智能家居、工业自动化等领域。
|
设计模式 数据库 C#
外观模式(Facade Pattern)
外观模式(Facade Pattern)是一种结构型设计模式,为子系统中的一组接口提供一个一致的接口。它通过一个高层接口简化子系统的复杂性,使客户端更容易使用。外观模式的核心角色包括外观(Facade)和子系统(Subsystems),主要优点是降低复杂性和松耦合,适用于简化接口、分层设计和遗留代码集成等场景。
数据结构中的 线性结构和非线性结构
这篇文章介绍了数据结构中的线性结构和非线性结构,其中线性结构包括顺序存储结构和链式存储结构,如数组、队列、链表和栈;非线性结构包括图结构、树结构、二维数组、广义表和多维数组。
|
自然语言处理 运维 开发工具
深入探讨了 NeoVim 相较于传统 Vim 的优势,包括更好的扩展性、现代化的界面和用户体验、多语言编程支持、强大的异步处理能力、更好的协作支持、持续的更新和改进、活跃的社区以及与现代开发工具的集成
本文深入探讨了 NeoVim 相较于传统 Vim 的优势,包括更好的扩展性、现代化的界面和用户体验、多语言编程支持、强大的异步处理能力、更好的协作支持、持续的更新和改进、活跃的社区以及与现代开发工具的集成。通过命令对比,展示了两者在启动、配置、模式切换、移动编辑、搜索替换、插件管理、文件操作、窗口缓冲区管理和高级功能等方面的差异。总结部分强调了 NeoVim 在多个方面的显著优势,解释了为什么越来越多的运维人员选择 NeoVim。
1433 3
多进程同步之文件锁
【10月更文挑战第16天】文件锁是一种常用的多进程同步机制,它可以用于确保多个进程在访问共享资源时的互斥性。在使用文件锁时,需要注意锁的粒度、释放、竞争和性能等问题。通过合理使用文件锁,可以提高多进程程序的正确性和性能
|
Kubernetes 安全 开发工具
Kubernetes系统安全-准入控制(admission control)
文章详细介绍了Kubernetes中的准入控制机制,包括各种准入控制器的功能、如何创建和使用LimitRange和ResourceQuota资源,以及PodSecurityPolicy和准入控制器扩展的使用方法。
235 1
Kubernetes系统安全-准入控制(admission control)

热门文章

最新文章