news 2026/11/6 2:01:45

线性结构:顺序表(1)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
线性结构:顺序表(1)

一、什么是顺序表

本质:一种基本的数据结构,底层使用数组类型这种顺序存储结构所实现的一种线性表(逻辑上连续,物理内存也连续的线性存储结构)

性质:线性数据结构(除了首尾之外,其他节点有且仅有一个前驱项和后继项)

基于内存分配方式,顺序表分为两种:静态顺序表和动态顺序表(动态可扩容数组)

作用:1.存储只存在线性关系的数据;2.作为其他数据结构的底层实现(如:栈,队列,哈希表等)

二、顺序表的优缺点

优点:1.支持下标随机访问(效率是O(1));

2.对CPU高速缓存比较友好(顺序表物理地址连续,满足空间局部性,遍历时缓存命中率高,因此 CPU 缓存友好);

缺点:1.数据移动和删除会导致大量数据移动,性能比较低;

2.需要足够大一整块连续的内存空间,容易开辟失败,容易产生空间浪费;

顺序表的使用场景:适用于尾插访问多,中间插入删除少的场景

三、顺序表结构体设计及实现接口

·静态顺序表:基于栈内存固定数组实现,容量编译时固定,无法扩容

数据结构设计:

#define INIT_CAPACITY 20 typedef int DataType; typedef struct { DataType data[INIT_CAPACITY];//固定容量的数组 size_t size;//当前有效元素个数 }StaticArray;

·动态顺序表:基于堆内存动态开辟实现,支持经典二倍扩容,容量灵活可变。

数据结构设计:

typedef int DataType; typedef struct { DataType* data; // 存储管理(动态堆内存数组) size_t size; // 数据量管理(有效数据个数) size_t capacity; // 容量管理(最大存储上限) }SeqList;

具体实现接口声明:初始化,销毁,扩容(动态顺序表),增删改查,获取容量,判空,清空顺序表

//初始化 extern ErrorCode SeqListInit(SeqList* plist); //销毁 extern ErrorCode SeqListDestroy(SeqList* plist); //清空 extern ErrorCode SeqListClear(SeqList* plist); //判空判满 extern int SeqListIsEmpty(const SeqList* plist); extern int SeqListIsFull(const SeqList* plist); //扩容 extern ErrorCode SeqListRealloc(SeqList* plist); //获取数据量、容量 extern size_t SeqListGetSize(const SeqList* plist); extern size_t SeqListGetCapacity(const SeqList* plist); //头尾插入 extern ErrorCode SeqListPushFront(SeqList* plist, const DataType val); extern ErrorCode SeqListPushBack(SeqList* plist, const DataType val); //指定位置插入 extern ErrorCode SeqListInsert(SeqList* plist, int pos, const DataType val); //头尾删除 extern ErrorCode SeqListPopFront(SeqList* plist); extern ErrorCode SeqListPopBack(SeqList* plist); //按下表删除 extern ErrorCode SeqListErase(SeqList* plist, int pos); //按值删除 extern ErrorCode SeqListRemove(SeqList* plist, DataType val); extern int SeqListRemoveAll(SeqList* plist, DataType val); //修改获取 extern ErrorCode SeqListModify(SeqList* plist, int pos, const DataType val); extern ErrorCode SeqListGetAt(const SeqList* plist, int pos, DataType* val); //查找 extern int SeqListFind(SeqList* plist, const DataType val); //输出打印 extern ErrorCode SeqListPrint(const SeqList* plist);

接口实现:

ErrorCode SeqListInit(SeqList* plist) { //参数校验 if (plist==NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //申请空间并初始化 plist->data = (DataType*)malloc(sizeof(DataType) * INIT_CAPACITY); if (plist->data == NULL) { LOG("空间申请失败"); return ERR_MALLOC; } memset(plist->data, 0x00, sizeof(DataType) * INIT_CAPACITY); //初始化其他成员 plist->capacity = INIT_CAPACITY; plist->size = 0; //返回成功 return SUCCESS; } ErrorCode SeqListDestroy(SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //释放空间 free(plist->data); //初始化其他成员 plist->data = NULL; plist->capacity = plist->size = 0; //返回成功 return SUCCESS; } ErrorCode SeqListClear(SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //数据量归零 plist->size = 0; //返回成功 return SUCCESS; } int SeqListIsEmpty(const SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判空 return plist->size == 0; } int SeqListIsFull(const SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判满 return plist->size == plist->capacity; } ErrorCode SeqListRealloc(SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判满:空间满了则扩容,没满则返回 if (!SeqListIsFull(plist))return SUCCESS; //扩容:经典2倍扩容 size_t newCapacity = plist->capacity * 2; DataType* newdata = (DataType*)realloc(plist->data, newCapacity * sizeof(DataType)); if (newdata == NULL) { LOG("扩容失败"); return ERR_MALLOC; } //更新数据成员 plist->data = newdata; plist->capacity = newCapacity; //返回成功 return SUCCESS; } size_t SeqListGetSize(const SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //返回size return plist->size; } size_t SeqListGetCapacity(const SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //返回capacity return plist->capacity; } ErrorCode SeqListPushFront(SeqList* plist, const DataType val) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判满,满了则扩容 if (SeqListIsEmpty(plist))SeqListRealloc(plist); //移动数据 memmove(plist->data + 1, plist->data, plist->size * sizeof(DataType)); //头插元素 plist->data[0] = val; //size++ plist->size++; return SUCCESS; } ErrorCode SeqListPushBack(SeqList* plist, const DataType val) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判满,满了则扩容 if (SeqListIsEmpty(plist))SeqListRealloc(plist); //尾插data[size]=val plist->data[plist->size] = val; //size++ plist->size++; return SUCCESS; } ErrorCode SeqListInsert(SeqList* plist, int pos, const DataType val) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } if (pos<0 || pos>plist->capacity) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判满,满了扩容 if (SeqListIsEmpty(plist))SeqListRealloc(plist); //移动数据 memmove(plist->data + pos + 1, plist->data + pos, sizeof(DataType) * plist->size - pos); //插入数据 plist->data[pos] = val; //size++ plist->size++; //返回成功 return SUCCESS; } ErrorCode SeqListPopFront(SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判空 if (SeqListIsEmpty(plist))return ERR_EMPTY; //移动数据 memmove(plist->data, plist->data + 1, sizeof(DataType) * (plist->size - 1)); //size-- plist->size -= 1; return SUCCESS; } ErrorCode SeqListPopBack(SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判空 if (SeqListIsEmpty(plist))return ERR_EMPTY; //size-- plist->size--; return SUCCESS; } ErrorCode SeqListErase(SeqList* plist, int pos) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } if (pos<0 || pos>plist->capacity) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判空 if (SeqListIsEmpty(plist))return ERR_EMPTY; //移动数据 memmove(plist->data + pos, plist->data + pos + 1, sizeof(DataType) * (plist->size - pos - 1)); //size-- plist->size--; //返回成功 return SUCCESS; } //删除一个指定数据 ErrorCode SeqListRemove(SeqList* plist, DataType val) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判空 if (SeqListIsEmpty(plist))return ERR_EMPTY; //遍历顺序表:找到要删除的元素,删除,返回success for (int i = 0; i < plist->size; i++) { if (plist->data[i] == val) { SeqListErase(plist, i); return SUCCESS; } } //没有找到返回 return ERR_DATA_NOT_EXISTS; } //删除指定数据: 删除所有的该数据, 返回实际删除的数据数量 int SeqListRemoveAll(SeqList* plist, DataType val) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判空 if (SeqListIsEmpty(plist))return ERR_EMPTY; size_t count = 0;//统计删除的数据量 //遍历顺序表:找到要删除的元素,删除,返回success for (int i = 0; i < plist->size; i++) { if (plist->data[i] == val) { SeqListErase(plist, i); count++; } } //没有找到返回 return count; } ErrorCode SeqListModify(SeqList* plist, int pos, const DataType val) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } if (pos<0 || pos>plist->capacity) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判空 if (SeqListIsEmpty(plist))return ERR_EMPTY; //修改指定下标元素 plist->data[pos] = val; return SUCCESS; } ErrorCode SeqListGetAt(const SeqList* plist, int pos, DataType* val) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } if (pos<0 || pos>plist->capacity) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判空 if (SeqListIsEmpty(plist))return ERR_EMPTY; //获得对应下标的元素 *val = plist->data[pos]; return SUCCESS; } int SeqListFind(SeqList* plist, const DataType val) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //判空 if (SeqListIsEmpty(plist))return ERR_EMPTY; //遍历顺序表:找到对应元素的下标,并返回;没有找到返回-1 for (int i = 0; i < plist->size; i++) { if (plist->data[i] == val)return i; } return -1; } ErrorCode SeqListPrint(const SeqList* plist) { //参数校验 if (plist == NULL) { LOG("参数不合法"); return ERR_INVALID_PARAM; } //遍历顺序表输出 for (int i = 0; i < plist->size; i++) { printf("%d ", plist->data[i]); } printf("\n"); return SUCCESS; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/6 2:01:27

Python78:核心语法-面向对象基础-类与对象

类与对象定义类与创建对象类的定义定义类的语法如下&#xff1a;&#xff08;动态添加属性&#xff09;说明&#xff1a;类名的命名规范&#xff0c;遵循大驼峰命名法&#xff0c;每个单词的首字母都是大写&#xff0c;单词之间没有分隔符&#xff0c;比如&#xff1a;UserInfo…

作者头像 李华
网站建设 2026/11/6 2:01:02

7.训练相关

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/6 2:00:43

数据质量怎么判断?完整性、准确性、一致性到底有什么区别?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/6 1:59:26

QML自定义输入框:仿Agent输入条与仿wechat输入框

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/6 1:59:26

msvcr71.dll丢失怎么办?官方修复流程与单文件下载风险详解

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/11/6 1:56:25

粗糙度测试方法比对,WLI、LSCM、AFM该如何选择?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华