数据结构之动态顺序表(含游戏菜单)
上一篇文章我们谈了数据结构的静态顺序表,以及实现了静态顺序表,具体可以看我的上一篇文章->>>数据结构之静态顺序表.
我们可以知道,静态顺序表的缺点是: 因为使用的是定长数组,所以空间给少了不够用,给多了,就会造成空间的浪费.
由此,我们引入一个新的顺序表----动态顺序表.
目录
一.什么是动态顺序表
什么是逻辑结构和物理结构
二.动态顺序表的优缺点
三.创建项目
四.接口实现
1.定义顺序表
2.结构体初始化
3.打印数据
4.顺序表增容
5.头插数据
6.尾插数据
7.头删数据
8.尾删数据
9.查找数据、
10.某一位置插入数据
11.删除某一位置
12.修改某一位置数据
13.顺序表的元素个数
14.销毁顺序表
精华总结:
附:原码链接
一.什么是动态顺序表?
动态顺序表:使用动态开辟的数组存储,使用指针指向动态开辟的数组,可以进行扩容。可以队数组内容进行增删查改等操作。
这里顺便提一下什么是逻辑结构和物理结构
- 逻辑结构: 人为想象出来的,实际并不存在.
- 物理结构: 实际存在,可以被观察到
二.动态顺序表的优缺点
优点:空间连续,支持随机访问。
缺点:1.中间或前面部分的插入时间复杂度是O(N),
2.增容的代价比较大
三.创建项目
工程文件 | 存放的内容 |
---|---|
SeqList.h | 函数声明,宏定义 |
SeqList.c | 实现顺序表函数接口的定义 |
test.c | 测试函数接口是否能实现功能 |
四.接口实现
1.定义顺序表
为了后续我们想更改数据类型时方便,我们一般对类型进行typedef操作。
typedef int SeqlistType;//创建结构体
typedef struct Seqlist
{SeqlistType* arr; //指向动态开辟的数组SeqlistType size; //有效个数SeqlistType capacity;//容量
}SL;
2.结构体初始化
传值:因为形参是实参的一份临时拷贝,对形参的改变并不会改变实参。所以我们应该把结构体变量的地址传过去,用结构体指针接收!为了防止传过来的是空指针,我们可以用assert进行断言!
void SeqlistInit(SL* ps)
{assert(ps);ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}
3.打印数据
我们只需要遍历顺序表就能完成打印
void SeqlistPrint(SL* ps)
{assert(ps);int i = 0;for (i = 0; i < ps->size; i++){printf("%d ", ps->arr[i]);}printf("\n");
}
4.顺序表增容
我们插入数据时,应该要先检查顺序表的容量是否满了(ps->size == ps->capacity)
因为一开始我们时没有给容量的(capacity = 0),所以我们可以先给4个空间,后续不够空间了再两倍的扩容!
//检查容量
void SeqlistCheckCapacity(SL* ps)
{assert(ps);//当size == capacity时要扩容了int newcapacity = 0;if (ps->size == ps->capacity){newcapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);//如果一开始容量为0,就给4个空间//不为0就扩为原来的2倍//扩容还要重新开辟空间->reallocSeqlistType* tmp = (SeqlistType*)realloc(ps->arr, sizeof(SeqlistType) * newcapacity);//注意:要判断是否开辟成功if (tmp == NULL){printf("扩容失败\n");//exit(-1);return;}else{ps->arr = tmp;ps->capacity = newcapacity;}}
}
5.头插数据
头插数据:1.要先检查顺序表容量,不够则扩容
2.头插即为把数据放到第一个位置,那我们把数组原来的数据向后移动即可!要注意从最右边的开始移动(i = ps->size-1),否则前面的数据会把后面的数据覆盖!
3.插入数据后,标记有效数字的size+1;
//头插
void SeqlistPushFront(SL* ps, SeqlistType x)
{assert(ps);//注意先检查容量!!!!SeqlistCheckCapacity(ps);int i = 0;for (i = ps->size-1; i >=0; i--){ps->arr[i+1] = ps->arr[i];}ps->arr[0] = x;ps->size++;
}
6.尾插数据
尾插数据:1.尾插数据也要先检查容量
2.在数组的位置上插入数据即:ps->size位置
3.插入数据,szie++;
//尾插
void SeqlistPushBack(SL* ps, SeqlistType x)
{assert(ps);//注意先检查容量!!!!SeqlistCheckCapacity(ps);ps->arr[ps->size] = x;ps->size++;
}
7.头删数据
头删数据:1.把后面的数据往前面覆盖,要注意从左边开始(i=0),否则会造成数据丢失!
2.删除了数据,size--
void SeqlistPopFront(SL* ps)
{assert(ps);int i = 0;for (i = 0; i < ps->size-1; i++){ps->arr[i] = ps->arr[i+1];}ps->size--;
}
8.尾删数据
只需让有效数字-1即可,数据虽然还在数组里,但是我们以及访问不到了!
void SeqlistPopBack(SL* ps)
{assert(ps);ps->size--;
}
9.查找数据、
1查找元素是否在顺序表内,如果元素在数组中的下标.
2.如果不在,返回-1 (-1为无效坐标)
3.返回类型为int 若返回类型写成我们之前typedef的类型要注意typedef的类型是什么!
int SeqlistFind(SL* ps, SeqlistType x)
{assert(ps);//遍历查找for (int i = 0; i < ps->size; i++){if (ps->arr[i] == x)return i;}return -1; //-1为无效坐标
}
10.某一位置插入数据
函数接口实现内容:给一个下标,在该下标前位置插入数据.
1.要保证位置在数组有效范围内(ps->size-1范围内)
2.把要插入位置的数据及后面的数据向后移动,注意要从最后的数据开始移动(i=ps->size-1),否则会造成前面的数据覆盖后面的数据。
3.最后把数据插入该位置,size++
//插入
void SeqlistInsert (SL* ps, SeqlistType pos, SeqlistType x)
{assert(ps);//要保证在有效区域内插入assert(pos < ps->size);//把pos位置及其后面的数据后移 // 要从最后面开始移动//要保证容量SeqlistCheckCapacity(ps);for (int i = ps->size-1; i >=pos;i--){ps->arr[i+1] = ps->arr[i];}ps->arr[pos] = x;ps->size++;
}
11.删除某一位置
函数接口实现内容:给一个下标,删除该位置。
1.要保证要删除的位置的数组在数据范围内((ps->size-1范围内))
2.把该位置后面的数据向前移动,把要删除位置的数据覆盖即可。
3.删除掉元素->size--
//删除
void SeqlistErase(SL* ps, SeqlistType pos)
{assert(ps);assert(pos<ps->size);//把pos后面的东西前移动for (int i = pos + 1; i < ps->size; i++){ps->arr[i-1] = ps->arr[i];}ps->size--;
}
12.修改某一位置数据
函数接口实现内容:给一个下标,修改该下标对应的值
要保证该下标在数组的数据范围内(ps->size-1范围)
//更改数据
void SeqlistModify(SL* ps, SeqlistType pos, SeqlistType x)
{//要保证在有效数据范围内更改assert(pos < ps->size);ps->arr[pos] = x;
}
13.顺序表的元素个数
size标识的就是顺序表的有效数字个数
//统计顺序表元素数量
int SeqListSize(SL* ps)
{assert(ps);return ps->size;
}
14.销毁顺序表
释放掉动态开辟的数组即可,free和指针置空要同时使用!不然就可能造成野指针!
//销毁空间
void SeqlistDestory(SL* ps)
{//free和NULL要配合使用free(ps->arr);ps->arr = NULL;ps->size = ps->capacity = 0;
}
精华总结:
1. 有些童鞋理解不了size和数组下标的关系!下面请看图
size是有效数字的个数,即数组有多少个元素。数组的下标是从0开始的,所以ps->arr[ps->size]是数组最后一个元素后面的位置。数组最后一个元素下标为ps->arr[ps->size-1]
其他注意事项:
!搞清楚传值还是传址问题!
传值:形参是实参的一份临时拷贝,对形参的改变并不会改变实参
1.插入数据时要检查容量!
2.在某个下标,修改/删/插入数据,要保证该下标在数组下标的范围内(ps->size-1)
3.插入/删除数据后,size也要记得++ /-- !
4.头插头删以及在某个下标位置前插入,要搞清楚从哪边元素开始移动!
当我们将全部接口实现时,我们就可以设计成一个游戏菜单了!
效果展示:
具体游戏代码以及本文章中的所有代码都在附录!
如果感觉本篇文章对你有所帮助,请给笔者一个小小的点赞,评论和关注吧!你们的支持就是我的动力!
附:原码链接
动态顺序表代码
数据结构之动态顺序表(含游戏菜单)相关推荐
- 数据结构之静态顺序表(含游戏菜单)
目录 一.什么是顺序表? 二.静态顺序表和动态顺序表的不同点 三.什么是静态顺序表 四:函数接口实现 1.初始化结构体 2.打印数据 3.头插数据 4.尾插数据 5.头删数据 6.尾删数据 附:原码链 ...
- 数据结构C语言实现动态顺序表
动态顺序表的C语言实现: 正文开始@Assassin 目录: 动态顺序表的C语言实现: ==什么是顺序表?== 1. 定义顺序表结构体: 2. 初始化顺序表: 3. 销毁顺序表: 4. 打印顺序表: ...
- 数据结构基础之动态顺序表详解
文章目录 前言 一.动态顺序表的概念 二.顺序表的结构体 三.基本接口 1.SeqListInit(初始化数组) 2.SeqListDestory(销毁数组) 3. SeqListCheckCapac ...
- 数据结构初阶——顺序表
博客写到这里,关于C语言的相关内容就告一段落了,从这篇开始,跟我一起进入一个全新的领域吧. 前面也为大家介绍了通讯录应该怎样去实现,其实顺序表也与通讯录差不多.顺序表是一种线性表,线性表在逻辑上是线性 ...
- 数据结构第二课 | 顺序表(详解)
前言:Hello!大家好,我是@每天都要敲代码,上次我们讲了数据结构第一课时间复杂度和空间复杂度:不明白的小伙伴可以学习一遍时间复杂度和空间复杂度传送门:今天让我们开始一起学习数据结构第二课啦---- ...
- [数据结构]数据结构简介和顺序表
目录 什么是数据结构 数据结构的特性 线性表 顺序表 创建一个动态顺序表 顺序表的增删查改 尾插和尾删除 尾插 头插头删 头插 头删 任意位置的插入和删除 插入 删除 查找和打印 总结 这天,小明和小 ...
- 数据结构之——《顺序表》
数据结构之--<顺序表> 1.含义 2.分类 3.接口函数实现 4.顺序表的优缺点 1.含义 顺序表示用一段纹理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储,在数组 ...
- 【线性表】—动态顺序表的增删查改实现
小菜坤日常上传gitee代码:https://gitee.com/qi-dunyan(所有的原码都放在了我上面的gitee仓库里) 数据结构知识点存放在专栏[数据结构]后续会持续更新 ❤❤❤ 个人简介 ...
- c语言pushback用法,C语言:【动态顺序表】动态顺序表的初始化、打印、尾插PushBack、尾删PopBack...
#include #include #include #include #include typedef int DateType; typedef struct SeqList { DateType ...
最新文章
- 树莓派 Zero 与 Zero W 对比
- mysql学习二:sql语句分类
- 【jQuery】parent()和parents遍历
- python控制命令行光标位置_python实现cli命令行的进度条光标滚动显示效果
- 工程师注意了!IBM新机器人将会抢走你们饭碗
- JSONObjec的作用详解——Web网络系列学习笔记
- 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当 new 的时候, 他们的执行顺序
- 官宣!多所高校,整体搬迁!
- Python+matplotlib绘制等电位面图
- Java 创建线程的4种方式
- 大数据技术应用需注意哪些问题
- java session时间_java设置session过期时间的实现方法
- 7-2 计算Fibonacci数列的前N(N<=20)项 (10 分)
- 几种颜色单位设置(颜色设置)
- java实现doc互转docx
- 百度百科:游荡在中国的窃贼
- 声学的一些基本知识(心理声学)
- 用友u8计算机快捷键,用友U8快捷键一览表
- mc有无限火力的服务器地址,我的世界花雨庭无限火力怎么玩 花雨庭无限火力玩法教程...
- WebSocket connection to ‘ws://localhost:8080/api/handler‘ failed: Invalid frame header