目录
1>>闲话
感谢大家对小编文章的喜欢,小编会继续加油的,今天来分享空间复杂度和线性表里的顺序表部分内容,今天内容难度有点高,希望大家刚接触的坚持一下!
2>>空间复杂度
空间复杂度是对一个算法在运行过程中需要的额外临时开辟的空间。空间复杂度和时间复杂度一样,都是使用大O渐进表示法,
(不知道的参考上一篇文献:链接博主回归!数据结构篇启动-CSDN博客)
因为主要看重时间复杂度,所以空间就不过多介绍了,这边附上一题练习题,一起来看看这题的空间复杂度是多少吧:
这里调用了n次,创建了n个函数栈帧空间,所以空间复杂度为O(N)。
3>>顺序表!!(有点难度)
刚学大家肯定和我有一样的疑问?这是个啥?其实顺序表是线性表的一种 ,线性表分为顺序表、链表、栈、队列、字符串 等等。线性表表示逻辑上是线性结构,物理结构不一定线性 ,我们通常学的数组就是物理结构连续的,也就是线性的,逻辑结构线性就表示我们想象的它是线性的一条线。
接下来让我们来学习顺序表:顺序表是物理地址也是连续的一段线性结构,一般用数组存储表示。那大家又有疑问哩,顺序表和数组有啥区别?顺序表是数组的升级改造版本,实现了增删改查的操作。
顺序表又分为静态顺序表和动态顺序表。
3.1>>静态顺序表
静态顺序表不怎么常用,因为不实用,内存固定,要么设置太大造成空间浪费,要么设置太小造成空间不够,所以我们直接来学习动态。
3.2>>动态顺序表
3.2.1>>初始化动态顺序表
实现动态顺序表需要三个文件:顺序表头文件、顺序表源文件、测试文件
这边先附上代码(这里实现了动态顺序表的尾插功能),大家先看(不懂没事,后面一句句介绍):
seqlist.h(顺序表头文件,可以自己取名,这边方便看就取直译英文)
cs
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int datetype;//不知道具体类型,可以一下子改
typedef struct seqlist {
datetype* arr;//(顺序表数组实现增、删、改、查)动态顺序表
int size;//有效数据
int capacity;//容量(包含有效和浪费的数据)
}SL;//将struct seqlist 重命名为typedef
void SLset(SL* ps);//初始化声明
void SLpushback(SL* ps, datetype x);//尾插
seqlist.c(顺序表源文件)
cs
#include"seqlist.h"
void SLset(SL* ps) {
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
void SLpushback(SL* ps, datetype x) {//x是插入数据
//情况2:空间不够进行扩容
assert(ps != NULL);
if (ps->capacity == ps->size) {
//空间不足,扩容
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
datetype* tmp = (datetype*)realloc(ps->arr, newcapacity * sizeof(datetype));
if (tmp == NULL) {
perror("realloc fail!");
exit(1);
}
ps->arr = tmp;
ps->capacity = newcapacity;
}
ps->arr[ps->size++] = x;//情况1:空间够直接加
}
test.c(测试源文件)
cs
#include"seqlist.h"
void SLtest()
{
SL sl;
SLset(&sl);//初始化
SLpushback(&sl, 1);
}
int main()
{
SLtest();
return 0;
}
这边看不懂正常,难度上来了,前期看不懂是小问题滴,现在容许我一句句介绍叭。
首先 :要实现动态顺序表,最基础的部分就是结构体的创建:
typedef是重命名的意思,第一句表示吧int重命名为datetype,因为如果是char型的话只需要更改这里就好。其他的我已经在注释解释啦~大家康康。还有第二句的typedef是将struct seqlist重命名为SL。
其次,创建完顺序表那么就要初始化里面的值,在顺序表头文件进行声明
这里使用结构体指针接收,这样在函数内才能修改到顺序表SL里面的每一项值。接着在顺序表源文件里包含头文件:
创建一个无返回值函数 SLset,通过ps指针接受结构体指针,这样才能修改里面的值,然后将arr设置为空,这样自行拓展方便,接着将有效数和容量设置为0.
接着在测试文件进行操作:
写一个测试函数SLtest,当然在main里直接写也可以(这边考虑文件较大时不好看所以拿一个函数来写里面),创建结构体变量sl,将sl取地址传到初始化函数进行初始化!一定注意传的是地址!
好了至此初始化顺序表结束!
3.2.2>>实现尾插
尾插顾名思义就是在顺序表尾部进行插入数值,那么就要考虑到两种情况,空间够与不够:
现在头文件声明尾插函数SLpushback,需要有一个结构体指针接收,还要一个传进行来要插入尾部的值。
接着在顺序表源文件实现尾插代码:
情况1:空间够,数组【有效数值】就是需要插入的尾部空间,如:
arr={1,2,3,空},空表示多余空间,那么空下标是3,有效数值有3个,所以数组【有效数值】就是需要插入的尾部空间。
情况2:空间不够,那么就要另外开辟空间,我们一般将原有空间乘2,那什么时候进行扩容呢?再举例子说明,arr={1,2,3},此时有效三个,容量也是3个,那么size等于capacity时进行扩容!
也就是这行代码,还需要判断原本容量是否为0:
这里用三目操作符,如果为0那么就为4,否则就扩大两倍存放到新容量(newcapacity)
接下来就要使用realloc对arr进行扩容,要先判断内存是否有空间,没空间返回值是NULL,所以这里为了防止arr得到一个空值,那么就要不嫌麻烦再创建一个同类型指针接受地址。
这里还需要乘上sizeof(datetype),因为realloc扩容的是字节数,所以要乘上这个类型一个占多少字节
接着为空打印错误信息:
如果不为空那么往下走,让原来的arr接受新的tmp大小,然后容量变为新容量。
这里传一个值
就可以实现最终代码啦,大家可以自己写写调试看看
那么至此!尾插结束!
4>>结语
总结:这篇讲述了空间复杂度和线性表里的顺序表,主要讲述了动态顺序表的尾插概念! 呼~结束了,对于刚接触的我觉得还是有点难度的,不过通过这篇博客加深了印象,不至于一头雾水,也希望这篇博客能帮助到同样一头雾水的你们,感谢观看,期待与你,下篇相见!谢谢大家!