当前位置: 首页 > news >正文

(数据结构)顺序表实现-增删查改

1.线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

2.顺序表

2.1概念及结构

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

顺序表就是数组,但是在数组的基础上,它还要数据是连续存储的,不能跳跃间隔。

#pragma once
#define N 100
typedef int SLDataType;//静态顺序表
typedef struct SeqList
{SLDataType arr[N];int size;//表示数组中存了多少个数据
}SL;//接口函数
//静态特点:满了就不让插入,很难确定给多少空间void SeqListInit(SL* ps);
//尾插
void SeqListPushBack(SL* ps, SLDataType x);
//尾删
void SeqListPopBack(SL* ps);
//头插
void SeqListPushFront(SL* ps, SLDataType x);
//头删
void SeqListPopFront(SL* ps);

静态顺序表不够灵活,我们接下来要学习的是动态顺序表;

学习动态顺序表前先说一个我犯过的错误,希望你们可以避一下

所以要传的是地址

顺序表一般可以分为:

1.静态顺序表:使用定长数组存储元素

2.动态顺序表:使用动态开辟的数组存储

3.顺序表的实现

3.1尾插:在顺序表末尾插入数据

实现步骤:

1.检查空间是否足够,不足需要继续开辟空间

1.1如果容量为0先分配一个初始容量,后面容量不够可以进行2倍扩容

1.2通过realloc开辟空间,将这个空间的地址赋值给一个定义的指针变量

1.3如果这个指针变量为NULL,即空间开辟失败进行相应的保护

1.4令顺序表的空间地址等于定义的指针变量,同时将新的容量赋值给原容量

2.空间足够

2.1将数据直接插入当前顺序表尾部

2.2++当前的有效数据个数

void SeqListPushBack(SL* ps, SLDataType x)
{//当空间为0或空间不够时,要开辟空间if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp=(SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (tmp == NULL){perror(realloc);exit(-1);//不可以写return -1;因为return没有终止掉程序}ps->a = tmp;ps->capacity = newcapacity;}//空间充足,直接插入数据即可ps->a[ps->size] = x;ps->size++;
}

如果对动态内存管理的函数不太了解可以看看我这一篇文章:

理清C语言中动态内存管理相关函数-CSDN博客

3.2尾删

直接减小size就行

void SeqListPopBack(SL* ps)
{//两种方式都可以/*if (ps->size > 0){ps->size--;}*/assert(ps->size > 0);ps->size--;
}

3.3头插

和尾插一样,先判断空间是否充足

为了方便我直接将扩容的功能封装成一个函数

void SeqListCheckcapacity(SL* ps)
{//当空间为0或空间不够时,要开辟空间if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (tmp == NULL){perror(realloc);exit(-1);//不可以写return -1;因为return没有终止掉程序}ps->a = tmp;ps->capacity = newcapacity;}
}

头插数据最简单的方法就是把现在数组的数据都往后挪一位,再把要插入的数据放在顺序表头部

void SeqListPushFront(SL* ps, SLDataType x)
{SeqListCheckcapacity(ps);//挪动数据int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];end--;}ps->a[0] = x;ps->size++;
}

3.4头删

从第二个数据开始往前挪,覆盖第一个数据,然后size-1

void SeqListPopFront(SL* ps)
{assert(ps->size > 0);int start = 0;while (start < ps->size-1){ps->a[start] = ps->a[start + 1];start++;}ps->size--;
}

3.5搜寻数据

遍历一遍顺序表即可

//找到了返回x位置的下标,没有找到返回-1
int SeqListFind(SL* ps, SLDataType x)
{int j = -1;for (int i = 0; i < ps->size; i++){if (ps->a[i] == x){j = i;}}return j;
}

3.6在指定位置插入数据

和头插的逻辑一样,也是将数据往后挪

void SeqListInsert(SL* ps, int pos, SLDataType x)
{assert(pos >= 0 || pos <= ps->size);SeqListCheckcapacity(ps);//空间充足int end = ps->size-1;while (end >=pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;}

3.7删除指定位置的数据

//删除pos位置的数据
void SeqListErase(SL* ps, int pos)
{SeqListCheckcapacity(ps);int start = pos;while (start < ps->size - 1){ps->a[start] = ps->a[start + 1];start++;}ps->size--;
}

3.9销毁顺序表

void SeqListDestory(SL* ps)
{free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
}

完整的工程:

main.c

#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"void TestList1();int main()
{TestList1();return 0;
}void TestList1()
{SL plist;SeqListInit(&plist);SeqListPushBack(&plist, 1);SeqListPushBack(&plist, 2);SeqListPushBack(&plist, 3);SeqListPushBack(&plist, 4);SeqListPushBack(&plist, 5);//        ListPushFront(plist, 0);SeqListPrint(&plist);}

SeqList.h

#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 SeqListInit(SL* ps);
//尾插
void SeqListPushBack(SL* ps, SLDataType x);
//尾删
void SeqListPopBack(SL* ps);
//头插
void SeqListPushFront(SL* ps, SLDataType x);
//头删
void SeqListPopFront(SL* ps);
//找到了返回x位置的下标,没有找到返回-1
int SeqListFind(SL* ps, SLDataType x);
//指定pos下标位置插入
void SeqListInsert(SL* ps, int pos, SLDataType x);
//删除pos位置的数据
void SeqListErase(SL* ps, int pos);//打印顺序表
void SeqListPrint(SL* ps);
//销毁顺序表
void SeqListDestory(SL* ps);
//查看顺序表空余的容量
void SeqListCheckcapacity(SL* ps);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS
#include "SeqList.h"//初始化
void SeqListInit(SL* ps)
{ps->a = NULL;ps->size = ps->capacity = 0;
}void SeqListDestory(SL* ps)
{free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
}void SeqListPrint(SL* ps)
{for (int i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}void SeqListCheckcapacity(SL* ps)
{//当空间为0或空间不够时,要开辟空间if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (tmp == NULL){//perror(realloc);exit(-1);//不可以写return -1;因为return没有终止掉程序}ps->a = tmp;ps->capacity = newcapacity;}
}//尾插:在顺序表末尾插入数据
void SeqListPushBack(SL* ps, SLDataType x)
{//当空间为0或空间不够时,要开辟空间if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (tmp == NULL){//perror(realloc);exit(-1);//不可以写return -1;因为return没有终止掉程序}ps->a = tmp;ps->capacity = newcapacity;}//空间充足,直接插入数据即可ps->a[ps->size] = x;ps->size++;
}//尾删
void SeqListPopBack(SL* ps)
{//两种方式都可以/*if (ps->size > 0){ps->size--;}*/assert(ps->size > 0);ps->size--;
}//头插
void SeqListPushFront(SL* ps, SLDataType x)
{SeqListCheckcapacity(ps);//挪动数据int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];end--;}ps->a[0] = x;ps->size++;
}
//头删
void SeqListPopFront(SL* ps)
{assert(ps->size > 0);int start = 0;while (start < ps->size - 1){ps->a[start] = ps->a[start + 1];start++;}ps->size--;
}//找到了返回x位置的下标,没有找到返回-1
int SeqListFind(SL* ps, SLDataType x)
{int j = -1;for (int i = 0; i < ps->size; i++){if (ps->a[i] == x){j = i;}}return j;
}//指定pos下标位置插入
void SeqListInsert(SL* ps, int pos, SLDataType x)
{assert(pos >= 0 || pos <= ps->size);SeqListCheckcapacity(ps);//空间充足int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;}//删除pos位置的数据
void SeqListErase(SL* ps, int pos)
{SeqListCheckcapacity(ps);int start = pos;while (start < ps->size - 1){ps->a[start] = ps->a[start + 1];start++;}ps->size--;
}

上一篇:

算法的时间复杂度和空间复杂度_算法复杂度 计算复杂度和存储复杂度-CSDN博客

下一篇:

(数据结构)链表-CSDN博客

http://www.dtcms.com/a/320382.html

相关文章:

  • java中override和overload的区别
  • 敏捷总结-上
  • 如果获取Docker镜像
  • Flink与Kafka核心源码详解-目录
  • 中国北极圈战略部署
  • 有密钥保护的物流跟踪、图书馆管理ISO15693标签ICODE SLIX2读写C#源码
  • 跨学科视域下的深层语义分析与人类底层逻辑一致性探索
  • 计数组合学7.15(Schur 函数的经典定义 )
  • 多模态融合(Multimodal Fusion)
  • 神策埋点是什么
  • C语言:单链表学习
  • 城市道路场景下漏检率↓76%:陌讯多模态融合算法在井盖缺失识别中的实践
  • Nestjs框架: 管道机制(Pipe)从校验到转换的全流程解析
  • ROS Launch 文件中的替换参数详解
  • 1.电动汽车动力电池系统技术介绍与分类
  • 在线文档自动化工具有什么
  • 周志华院士西瓜书实战(三)聚类+邻居+PCA+特征选择+半监督学习
  • 【Canvas与徽章】北极星蓝盘玻璃光徽章
  • NumPy库向量的常见运算
  • C++面试9——多继承陷阱与适用场景
  • 【新闻资讯】Anthropic CEO 达里奥·阿莫迪万字访谈:在技术加速与风险防控间的坚守
  • vLLM:彻底改变大型语言模型推理延迟和吞吐量
  • RabbitMQ面试精讲 Day 14:Federation插件与数据同步
  • YOLOv8面试知识
  • Linux系统编程--基础开发工具
  • 容器之王--Docker的部署及基本操作演练
  • 前端学习 7:EDA 工具
  • Springboot 使用 JPA 分页查询
  • 前端开发工具大全
  • 车辆特征与车牌识别准确率↑29%:陌讯多模态融合算法实战解析