为什么要学习数据结构
数据结构的重要性,想必大家也都听说过。我们程序设计没有了数据结构,就像厨师没有了调味品,即使有再好的食材也做不出上乘的菜肴。
程序=数据结构+算法。好比说查询某人的考试成绩,成绩如何存储和表示这就是数据结构所要做的事情,而如何方便、快捷的查询这是算法的问题。
几个基本概念
学习数据结构之前,我们弄懂几个基本概念:数据、数据对象、数据元素、数据项。
把电话本看做一个数据对象,那么每一个人的相关记录就是数据元素,每天记录中的姓名、电话这些是数据项。
官方定义:
数据:是描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。
数据元素:是组成数据的、有一定意义的基本单位,在计算中通常作为整体处理。
数据项:一个数据元素可以由若干个数据项组成。
数据项是数据不可分割的最小单位。
数据对象:是性质相同的数据元素的集合,是数据的子集。
一张图解决它们之间的包含关系如下:
常用的数据结构
在我们编程过程中只要是与数据有关的就会联系到结构,最基础基础、常用的数据结构那就是线性表啦,根据我们使用的场景不同,又会以栈、队列、字符串等形式被我们使用。
线性表的顺序存储结构
今天我们主要谈论的是线性表的顺序存储结构。可以把它看做之前学过的一维数组
表中的元素排序是按我们数数的习惯,起始为1,而在c语言中数组是从0开始第一个下标的,所以在线性表中的第i个元素要存储在数组下标为i-1的位置。
线性结构的顺序存储是说是用一组连续的存储单元一次存储线性表中的各个元素,使得线性表中在逻辑上相连的元素存储在连续的物理存储单元上。通过数据元素物理存储的连续性来反映数据元素在逻辑上的相邻关系。如下图,是顺序存储结构示意图:
顺序表的特征:
-
具有相同的数据类型
-
是个有限序列
-
具有线性特征
代码实现
顺序表存储结构的定义:
typedef struct
{
int * pBase;//存储的是数组第一个元素的地址
int len;//数组所能容纳的元素的最大个数
int cnt;//当前数组有效元素的个数
}SqList;
就是自定义一种结构体类型,名字为SqList,就像定义整型变量int一样,
基本构成有存储空间基址int *PBase;表的有效长度cnt,即是表中存储数据所所占用的数组长度;表的最大长度len,就是所分配存储空间的大小。
初始化线性表:
void init_Arr(SqList * pArr,int length)
{
pArr->pBase = (int *)malloc(sizeof(int)* length);
if(pArr->pBase == NULL)
{
printf("分配失败");
exit(-1);//终止整个程序
}
pArr->len = length;
pArr->cnt = 0;
return;
}
使用malloc函数为线性表分配存储空间,如果分配失败退出执行。在使用malloc函数时,必须要有头文件<malloc.h>.
然后让线性表有效长度初始为0,因为现在表中还没有元素。
插入元素:
bool is_full(SqList *pArr)//判断表是否满是函数
{
if(pArr->cnt == pArr->len)
return true;
return false;
}
bool insert_Arr(SqList *pArr , int pos , int val)
{
if(pos<1 || pos>pArr->cnt+1)//判断插入元素的位置是否合法
return false;
else if(is_full(pArr))//判断表是否已满
return false;
else
{
for(int i=pArr->cnt-1;i>=pos-1;--i)//插入元素所在位置之后的元素分别向后移1位
pArr->pBase[i+1] = pArr->pBase[i];
pArr->pBase[pos-1] = val;
(pArr->cnt)++;//表长+1
return true;
}
}
插入元素的思路:
-
插入位子是否合法
-
从最后一个元素向前第i个元素位置,分别向后移一位
-
插入元素
-
表长加1
删除元素:
bool is_Empty(SqList * pArr)//判断表是否为空的函数
{
if(pArr->cnt == 0)//表为空时,有效长度为0
return true;
return false;
}
bool delete_Arr(SqList *pArr , int pos , int * pVal)
{
if(pos<1 || pos>pArr->cnt)//判断删除元素的位置是否合法
return false;
if(is_Empty(pArr))//判断表是否为空
return false;
*pVal = pArr->pBase[pos-1];//获取要删除元素的值
for(int i=pos;i<pArr->cnt;++i)//从要删除元素下一个位置开始,分别向前移动1位
pArr->pBase[i-1] = pArr->pBase[i];
(pArr->cnt)--;//表长-1
return true;
}
删除元素思路:
-
判断i值是否合法
-
取出删除元素
-
从删除元素位置开始知道最后,分别向前移动一位
-
表长-1
获取表中元素:
bool getelem(SqList Arr , int pos , int * pVal)
{
if(pos<1 || pos>Arr.cnt)
return false;
*pVal = Arr.pBase[pos-1];//获取元素的值
return true;
}
获取表中元素和删除操作很相似,不过在这里要把删除的功能去掉才行。获取第pos个元素实际就是下标为pos-1的元素,把值传给*Pval,即可获取该元素。
遍历输出:
void show_Arr(SqList * pArr)
{
if(is_Empty(pArr))
printf("数组为空\n");
else
{
for(int i=0;i<pArr->cnt;++i)//循环遍历输出
printf("%d ",pArr->pBase[i]);
printf("\n");
}
}
顺序表的遍历输出主要是利用for循环,遍历找出表中的每一个元素,分别让它们执行输出操作。
好啦,小伙伴们,今天的分享就到这里。有什么问题可以在微信公众号发私信给我,明天见喽!