动态顺序表的C语言实现:

正文开始@Assassin

目录:

  • 动态顺序表的C语言实现:
    • ==什么是顺序表?==
    • 1. 定义顺序表结构体:
    • 2. 初始化顺序表:
    • 3. 销毁顺序表:
    • 4. 打印顺序表:
    • 5. 判断容量+扩容:
    • 6. 头插数据:
    • 7. 尾插数据:
    • 8. 指定下标位置插入数据:
    • 9. 删除数据:
    • 10. 尾删数据:
    • 11. 指定下标位置删除数据:
    • 12. 查找数据:
    • 13. 修改数据:
    • 14. 源代码:
      • 1. SeqList.h:
      • 2. SeqList.cpp:
      • 3. test.cpp:
    • 15. 测试:
    • see you next blog~~

什么是顺序表?

顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素,使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,采用顺序存储结构的线性表通常称为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。

简言之,顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。可以类比vector,简单理解为可以动态增长的数组~~

顺序表一般可以分为:

  • 1.静态顺序表(直接定义数组):存储数据的空间是固定的;

    • 导致的问题:开小了不够用,开大了浪费空间,现实中不实用
  • 2.动态顺序表(用指针接收malloc动态开辟):存储数据的空间是可以动态增长的,可以更好的适应于现实中的使用

1. 定义顺序表结构体:

首先,我们要创建一个顺序表类型,该顺序表类型包括了顺序表的起始位置、记录顺序表内已有元素个数的计数器(size),以及记录当前顺序表的容量的变量(capacity)。

typedef int SLDataType;//定义一个类型,以便更好的适应每一种数据的存储,这里以存放整型数据为例typedef struct SeqList
{SLDataType* a;//声明了一个指向顺序表的指针int size;//记录当前顺序表内元素个数int capacity;//记录当前顺序表的最大容量
}SeqList;//C语言中直接使用Seqlist类型

2. 初始化顺序表:

我们需要一个初始化函数,对顺序表进行初始化。这里多说两句自己的一些理解:有些小伙伴会对结构体直接赋值为0来进行初始化,这种操作虽然编译器不给error,但也会报warning,我们应该注意这一点,因为本身struct中的指针类型也不能简单的以0来初始化,实在不想用接口的话,那我建议你用NULL来初始化指针~~当然我们要有意识地去写工程化的代码,每个独立的功能习惯地去用函数封装起来,我们调用接口实现功能。

//初始化顺序表
void SeqListInit(SeqList* ps)
{assert(ps);//断言ps->a = NULL;//刚开始时顺序表为空,顺序表指针为NULLps->size = 0;//起始时元素个数为0ps->capacity = 0;//容量为0/* 或者一开始就开辟空间,给定capacityps->a = (SLDateType*)malloc((sizeof(SLDateType)* 4));if (ps->a == NULL){printf("malloc fail\n");exit(-1);}ps->size = 0;ps->capacity = 4;*/
}

3. 销毁顺序表:

因为顺序表所用的内存空间是动态开辟在堆区的,所以我们在使用完后需要及时对其进行释放,避免造成内存泄漏。 一般这个操作放在return之前调用。
当然,如果想在下次运行前记住当前的一些增删查改,若需要对数据进行保存,可以使用文件操作函数将数据保存到一个文件中,下次使用顺序表的时候先读取文件数据即可。

//销毁顺序表
void SeqListDestory(SeqList* ps)
{assert(ps);//断言free(ps->a);//释放顺序表指针指向的空间ps->a = NULL;//及时置空ps->size = 0;//元素个数置0ps->capacity = 0;//容量置0
}

4. 打印顺序表:

打印函数没啥好说的,直接遍历一遍size个数组中的元素即可。

//打印顺序表
void SeqListPrint(SeqList* ps)
{assert(ps);//断言int i = 0;//循环打印顺序表指针指向的数据for (i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}

5. 判断容量+扩容:

我们应该意识到,每次需要增加数据的时候,首先都应该先检查顺序表内元素个数是否已达顺序表容量上限。若已达上限,那么我们就需要先对顺序表进行扩容,然后才能增加数据。扩容就要使用到realloc函数。

//检查顺序表容量是否已满,若已满,则增容
void SeqCheckCapacity(SeqList* ps)
{if (ps->size == ps->capacity)//判断已满,需要增容{//判断顺序表容量是否为0,若为0,则先开辟用于存放4个元素的空间大小,若不为0,则扩容为原来容量的两倍int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* newArr = realloc(ps->a, newcapacity*sizeof(SLDataType));if (newArr == NULL){printf("realloc fail\n");exit(-1);}//最好用同一个指针维护较为稳妥,所以我们把newArr赋值给psps->a = newArr;//开辟成功,将顺序表指针更新ps->capacity = newcapacity;//容量更新}
}

注意: 若传入realloc的指针为空指针(NULL),则realloc函数的作用相当于malloc函数。

6. 头插数据:

要想在顺序表的表头插入数据,那么就需要先将顺序表原有的数据从后往前依次向后挪动一位,最后再将数据插入表头。注意一定要依次从后面移动数据,否则会发生覆盖。

//头插
void SeqListPushFront(SeqList* ps, SLDataType x)
{assert(ps);SeqCheckCapacity(ps);//检查容量int i = 0;for (i = ps->size; i > 0; i--)//将数据从后往前依次向后挪{ps->a[i] = ps->a[i - 1];}ps->a[0] = x;ps->size++;//顺序表元素个数加一
}

注意: 挪动数据的时候应从后向前依次挪动,若从前向后挪动,会导致后一个数据被覆盖。

7. 尾插数据:

尾插相对于头插就比较简单了,直接在表尾的size插入数据即可。记得size也要相应地++

//尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{assert(ps);SeqCheckCapacity(ps);//检查容量ps->a[ps->size] = x;ps->size++;//顺序表元素个数加一
}

8. 指定下标位置插入数据:

要做到在指定下标位置插入数据,首先我们需要得到一个下标位置,然后从该下标位置开始(包括该位置),其后的数据从后往前依次向后挪动一位,最后将数据插入到该下标位置。

//指定下标位置插入
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);//检查输入下标的合法性SeqCheckCapacity(ps);//检查容量int i = 0;for (i = ps->size; i > pos; i--)//从pos下标位置开始,其后的数据从后往前依次向后挪{ps->a[i] = ps->a[i - 1];}ps->a[pos] = x;ps->size++;//顺序表元素个数加一
}

我们可以发现,头插和尾插实际上就是在下标为0的位置和下标为ps->size的位置插入数据,也就意味着我们可以统一使用该函数来实现头插和尾插。
相当于实现了代码复用,一定程度上也起到了便于管理的效果。

//头插
void SeqListPushFront(SeqList* ps, SLDataType x)
{SeqListInsert(ps, 0, x);//在下标为0的位置插入数据
}
//尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{SeqListInsert(ps, ps->size, x);//在下标为ps->size的位置插入数据
}

9. 删除数据:

删除数据,其实可以理解为:从某个位置开始,数据依次向前覆盖,相应的size做出改变。这样一来,该位置的数据就相当于删除了。

10. 尾删数据:

尾删就更简单了,直接将顺序表的元素个数减一即可。把size减一,让其遍历不到最后一个数据,也就是删除了。ps:其实,深入了解的话,操作系统层面上的删除也是如此,你不能访问了,对于OS来说就是删除了~~

//尾删
void SeqListPopBack(SeqList* ps)
{assert(ps);assert(ps->size > 0);//保证顺序表不为空ps->size--;//顺序表元素个数减一
}

11. 指定下标位置删除数据:

要删除指定下标位置的数据,我们只需要从下标位置开始,其后的数据从前向后依次覆盖即可。

//指定下标位置删除
void SeqListErase(SeqList* ps, int pos)
{assert(ps);assert(ps->size > 0);//保证顺序表不为空assert(pos >= 0 && pos < ps->size);int i = 0;for (i = pos; i < ps->size - 1; i++)//从pos下标位置开始,其后的数据从前往后依次向前覆盖{ps->a[i] = ps->a[i + 1];}ps->size--;//顺序表元素个数减一
}

同理,头删和尾删实际上也就是删除下标为0的位置和下标为ps->size - 1的位置的数据,也就意味着我们可以统一使用该函数来实现头删和尾删。

//头删
void SeqListPopFront(SeqList* ps)
{SeqListErase(ps, 0);//删除下标为0的位置的数据
}
//尾删
void SeqListPopBack(SeqList* ps)
{SeqListErase(ps, ps->size - 1);//删除下标为ps->size - 1的位置的数据
}

12. 查找数据:

查找数据也相对简单,直接遍历一次顺序表即可,若找到了目标数据,则停止遍历,并返回该数据的下标,否则返回-1。

//查找元素,若有,返回下标,否则返回-1
int SeqListFind(SeqList* ps, SLDataType x)
{assert(ps);int i = 0;for (i = 0; i < ps->size; i++)//遍历顺序表进行查找{if (ps->a[i] == x)return i;//找到该数据,返回下标}return -1;//未找到,返回-1
}

13. 修改数据:

修改数据,就直接对该位置的数据进行再次赋值即可。

//修改指定下标位置元素
void SeqListModify(SeqList* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos < ps->size);//检查输入下标的合法性ps->a[pos] = x;//修改数据
}

14. 源代码:

1. SeqList.h:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef int SLDatatype;
typedef struct SeqList
{SLDatatype *a; //存储数据空间的指针int size;      //有效数据的个数int capacity;  //容量空间大小
} SeqList;
//顺序表初始化声明
void SeqListInit(SeqList *ps);
//顺序表销毁声明
void SeqListDestory(SeqList *ps);
//检查空间,如果满了,进行空间增容
void CheckCapacity(SeqList *ps);
//顺序表打印声明
void SeqListPrint(SeqList *ps);
//顺序表尾插
void SeqListPushBack(SeqList *ps, SLDatatype x);
//顺序表头插
void SeqListPushFront(SeqList *ps, SLDatatype x);
//顺序表尾删
void SeqListPopBack(SeqList *ps);
//顺序表头删
void SeqListPopFront(SeqList *ps);
//顺序表查找
SLDatatype SeqListFind(SeqList *ps, SLDatatype x);
//顺序表在pos位置插入
void SeqListInsert(SeqList *ps, int pos, SLDatatype x);
//顺序表删除pos位置的值
void SeqListErase(SeqList *ps, int pos);

2. SeqList.cpp:

#include "SeqList.h"
void CheckCapacity(SeqList *ps)
{//空间不够,需要增容if (ps->size == ps->capacity){SLDatatype *tmp = (SLDatatype *)realloc(ps->a, sizeof(SLDatatype) * ps->capacity * 2);//如果空间不足,可能增容失败if (ps->a == NULL){printf("顺序表已满,无法插入\n");exit(-1);}ps->a = tmp;ps->capacity *= 2;}
}
//顺序表初始化;需要传址
void SeqListInit(SeqList *ps)
{ps->a = (SLDatatype *)malloc(sizeof(SLDatatype) * 4);//malloc失败if (ps->a == NULL){printf("malloc fail\n");exit(-1);}memset(ps->a, 0, sizeof(SLDatatype) * 4);ps->size = 0;ps->capacity = 4;
}
//顺序表销毁;需要传址
void SeqListDestory(SeqList *ps)
{free(ps->a);ps->a = NULL;ps->size = 0;ps->capacity = 0;
}
//顺序表打印
void SeqListPrint(SeqList *ps)
{for (int i = 0; i < ps->size; ++i){printf("%d ", ps->a[i]);}printf("\n");
}
//顺序表尾插
void SeqListPushBack(SeqList *ps, SLDatatype x)
{assert(ps);CheckCapacity(ps);//空间够了,直接把插入的数据放到a[size]位置处ps->a[ps->size] = x;ps->size++;
}
//顺序表头插
void SeqListPushFront(SeqList *ps, SLDatatype x)
{assert(ps);CheckCapacity(ps);//从最后一个数的位置开始一个一个往后移int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];--end;}//x赋值给头位置ps->a[0] = x;ps->size++;
}
//顺序表尾删
void SeqListPopBack(SeqList *ps)
{assert(ps);//若无此步骤size为0时再size--为-1assert(ps->size > 0);ps->size--;
}
//顺序表头删
void SeqListPopFront(SeqList *ps)
{assert(ps);assert(ps->size > 0);int begin = 1;//从第二个数的位置开始往前移while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];++begin;}ps->size--;
}
//顺序表查找,可以查找一个数在不在数组里,并返回其下标,配合其他接口使用
SLDatatype SeqListFind(SeqList *ps, SLDatatype x)
{assert(ps);for (int i = 0; i < ps->size; ++i){if (ps->a[i] == x){return i;}}return -1;
}
//顺序表在pos位置插入
void SeqListInsert(SeqList *ps, int pos, SLDatatype x)
{assert(ps);assert(pos >= 0 && pos < ps->size);CheckCapacity(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(SeqList *ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);while (pos < ps->size - 1){ps->a[pos] = ps->a[pos + 1];++pos;}ps->size--;
}

3. test.cpp:

#include "SeqList.h"
int main()
{SeqList Sl;//测试顺序表初始化SeqListInit(&Sl);//测试顺序表尾插SeqListPushBack(&Sl, 1);SeqListPushBack(&Sl, 2);SeqListPushBack(&Sl, 3);SeqListPushBack(&Sl, 4);SeqListPushBack(&Sl, 5);SeqListPrint(&Sl);//测试顺序表头插SeqListPushFront(&Sl, 0);SeqListPrint(&Sl);//测试顺序表尾删SeqListPopBack(&Sl);SeqListPopBack(&Sl);SeqListPrint(&Sl);//测试顺序表头删SeqListPopFront(&Sl);SeqListPrint(&Sl);SeqListFind(&Sl, 1);SeqListPrint(&Sl);//测试顺序表在pos位置插入SeqListInsert(&Sl, 1, 20);SeqListPrint(&Sl);//测试顺序表删除pos位置的值SeqListErase(&Sl, 0);SeqListPrint(&Sl);//测试顺序表查找int pos = SeqListFind(&Sl, 3);if (pos != -1){printf("找到了\n");}//查找配合删除删掉指定的数int pos1 = SeqListFind(&Sl, 2);if (pos1 != -1){SeqListErase(&Sl, pos1);}SeqListPrint(&Sl);//顺序表销毁SeqListDestory(&Sl);return 0;
}

15. 测试:

see you next blog~~

数据结构C语言实现动态顺序表相关推荐

  1. 【动态顺序表】 c语言的动态顺序表

    动态顺序表: 容量不够时 自动增容(静态顺序表的改进) 动态顺序表的结构: typedef int DataType; typedef struct SeqList { DataType* _arra ...

  2. C语言实现动态顺序表

    1.用于存放声明的头文件 #pragma once //避免重复引入头文件,作用于预编译指令几乎相同#define _CRT_SECURE_NO_WARNINGS 1 #include <std ...

  3. 【初识数据结构】c语言实现动态顺序表(已配图)

    前言  大家好啊,这里是幸麟 一名普通的大学牲

  4. 数据结构之动态顺序表(含游戏菜单)

    上一篇文章我们谈了数据结构的静态顺序表,以及实现了静态顺序表,具体可以看我的上一篇文章->>>数据结构之静态顺序表. 我们可以知道,静态顺序表的缺点是:  因为使用的是定长数组,所以 ...

  5. c语言pushback用法,C语言:【动态顺序表】动态顺序表的初始化、打印、尾插PushBack、尾删PopBack...

    #include #include #include #include #include typedef int DateType; typedef struct SeqList { DateType ...

  6. 数据结构基础之动态顺序表详解

    文章目录 前言 一.动态顺序表的概念 二.顺序表的结构体 三.基本接口 1.SeqListInit(初始化数组) 2.SeqListDestory(销毁数组) 3. SeqListCheckCapac ...

  7. c语言实现顺序表源程序,C语言实现静态顺序表的实例详解

    C语言实现静态顺序表的实例详解 线性表 定义一张顺序表也就是在内存中开辟一段连续的存储空间,并给它一个名字进行标识.只有定义了一个顺序表,才能利用该顺序表存放数据元素,也才能对该顺序表进行各种操作. ...

  8. 【线性表】—动态顺序表的增删查改实现

    小菜坤日常上传gitee代码:https://gitee.com/qi-dunyan(所有的原码都放在了我上面的gitee仓库里) 数据结构知识点存放在专栏[数据结构]后续会持续更新 ❤❤❤ 个人简介 ...

  9. c语言顺序表有效元素长度,用C语言描述的顺序表类型

    2.2.1 顺序表 用C语言描述的顺序表类型如下所示: // 存储结构 const int MAXLISTSIZE=80; // 预设的存储空间最大容量 typedef struct { ElemTy ...

最新文章

  1. 【转】Flex Application 初始化顺序
  2. 基于jquery的一个javascript前端框架实现
  3. windows 环境怎样恢复 (oracle 11g grid) ocr voting 损坏的集群
  4. 将CLASS文件打包成可运行的jar文件
  5. MySQL卸载5.重新安装 8.0.20教程(windows 64位)
  6. 计算机 学校教一半 自学一半,一半初中生无缘普高,上职业学校怎么样?
  7. mysql tcp优化_mysql 优化
  8. Java中找出s字符串的回文_给定一个字符串 s,找到 s 中最长的回文子串。
  9. 微信小程序云开发教程-微信小程序的API入门-API的类型和语法结构
  10. MySQL 数据库重装失败最后一步无法启动server的解决办法
  11. java2实用教程第六版习题答案
  12. linux 更新软件命令 失败,(2015.1.13 更新)联合DSDT和SSDT进行反编译——减少DSDT和SSDT错误的尝试...
  13. teechart的addarray_TeeChart绘图控件 - 之三 - 提高绘图的效率
  14. Error installing to Instantiated: name=AttachmentStore state=Described
  15. 简述XSS攻击及其防范措施
  16. 互联网短信网关接口协议
  17. 网络波动造成服务器文件系統损坏,和平精英网络波动异常 与服务器失去连接解决方法...
  18. SWUST OJ954: 单链表的链接
  19. 电商分销APP开发功能模块
  20. 训练集、验证集、测试集划分

热门文章

  1. 漂亮大气!小米武汉总部正式开园:从签约到建成使用仅用时两年
  2. 华为Mate 30 Pro相机要上天了:主摄或达8100万像素
  3. 后置“浴霸”六摄!疑似索尼全新旗舰Xperia 2曝光
  4. 李想当年是被赶出汽车之家?真相了...
  5. couldn't find libweibosdkcore.so
  6. Python 提交表单数的一点简单介绍How to submit a web form
  7. python如何获取javascript动态产生的数据
  8. 求解集合A与B的差集
  9. 大学mysql期末试题_四川大学数据库系统期末试题2014-2015.doc
  10. c++友元模板单例模式