赞
踩
勤时当勉励 岁月不待人
C/C++ 游戏开发
Hello,米娜桑们,这里是君兮_,今天正式开始开新坑啦!在接下来的这一个月来我会逐步带大家了解初阶数据结构的知识,如果是你主修的是计算机专业数据结构的重要性不言而喻,哪怕在以后你工作面试时,它也是面试官们最喜欢考察的内容之一,如果你想对这部分内容有一个系统又深刻的认识,那么不要错过这个专栏的内容哦!!我会努力用通俗易懂的话来带大家入门的!
好了,废话不多说,开始今天的学习吧!
ps:顺序表中难以理解的点应该就是malloc以及realloc的使用了,这是有关C语言的动态内存管理的知识,我们主要目的是介绍顺序表的因此不做缀叙,如果你感兴趣之后我也会更新有关博客并且把链接贴在这里哒!
我们知道,顺序表是最基础的线性表,那么什么是线性表呢?
// 静态顺序表
#define N 1000
typedef int SLDataType;
struct SeqList
{
SLDataType a[N];
int size;
};
// 动态顺序表
typedef int SLDataType;//重命名数据类型,方便以后直接修改
typedef struct SeqList
{
SLDataType* a;//指向动态开辟的数组
int size; // 存储有效数据个数
int capacity; // 容量空间大小
}SL;
顾名思义,动态顺序表使用动态开辟的数组储存,这样更方便我们实时根据数据的多少调整数组的大小。。
typedef double SLDataType;
接下来我们来具体实现一下动态顺序表的各种功能以及使用方法
我们确定了顺序表内的基本内容,我们得把顺序表先初始化一下,不然连空间都还没开辟咋使用呢?
//初始化顺序表
void SLInit(SL* ps)
{
ps->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);//申请四个字节的空间,如果不够再进行增容
if (ps->a == NULL)
{
perror("malloc failed");
exit (-1);
}
ps->size = 0;
ps->capacity = 4;
}
我们初始化了一个顺序表,但是我们并不知道我们申请的空间是否够用,如果不够用,我们就得扩容一下。因此我们这里的逻辑应该是先判断容量是否够用,够用就不用做多余的操作,如果不够用,就申请扩容
//检查空间,如果顺序表满了,就进行增容操作 void SLCheckCapacity(SL* ps) { assert(ps);//断言防止传入ps为空 //判断一下是否空间满了,如果满了就把容量增加到原来的2倍 if (ps->size == ps->capacity)//有效数据是否占满所有空间 { SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * (sizeof(SLDataType)));//利用realloc扩容 if (tmp == NULL) { perror("realloc failed"); exit(-1); } ps->a = tmp; ps->capacity *= 2; } }
void SLDestroy(SL* ps)
{
free(ps->a);//释放malloc申请的空间并且将a指向NULL
ps->a = NULL;
ps->capacity = ps->size = 0;
}
在销毁并释放内存的同时,我们也需要把size和capacity初始化一下。
void SLPrint(SL* ps)
{
int i =0;
for (i = 0; i < ps->size; i++)
printf("%d ", ps->a[i]);//把有效数据通过循环都打印一下
printf("\n");
}
**所谓尾插就是从顺序表的末尾插入数据,而尾删就是把最后一个数据给删除
**//顺序表尾插
void SLPushBack(SL* ps, SLDataType x)
{
assert(ps);
SLCheckCapacity(ps);//先判断以下顺序表是否已满,未满才能插入数据
ps->a[ps->size] = x;//把数组a中size位置的数据赋值为x,size位置即最后一位
ps->size++;//插入数据成功,有效数据+1
}
//顺序表尾删
void SLPopBack(SL* ps)
{
assert(ps);
温柔的检查
//if (ps->size == 0)
// return;
//暴力检查
assert(ps->size > 0);
ps->a[ps->size - 1] = 0;//把最后一个数据抹掉
ps->size--;//有效数据-1
}
与尾插和尾删类似,顺序表的头插与头删就是在开头进行插入与删除数据操作
/顺序表的头插 void SLPushFront(SL* ps, SLDataType x) { assert(ps); SLCheckCapacity(ps);//判断容量是否已满 //挪动数据 int End = ps->size - 1; while (End >= 0) { ps->a[End + 1] = ps->a[End]; End--; } ps->a[0] = x; ps->size++; }
//顺序表的头删
void SLPopFront(SL* ps)
{
assert(ps);
int begin = 0;
while (begin < ps->size-1)
{
ps->a[begin] = ps->a[begin + 1];
begin++;
}
ps->size--;
}
//在顺序表中pos位置插入 void SLInsert(SL* ps, int pos, SLDataType x) { assert(ps); SLCheckCapacity(ps);//检查容量空间大小 assert(pos >= 0 && pos <= ps->size);//判断pos的合法化,避免插入到非法坐标中 int end = ps->size - 1; while (end >= pos)//把pos位置后的数据都朝后挪动一位,给插入的数据腾位置 { ps->a[end + 1] = ps->a[end]; end--; } ps->a[pos] = x;//插入数据 ps->size++;//有效数字+1 }
这里与头插类似,只不过我们需要挪动的数据变成了pos位置后的数据,它们都需要朝后挪动一位
//在顺序表中删除pos位置的值
void SLErase(SL* ps, int pos)
{
assert(ps);
assert(pos >= 0 && pos <= ps->size);
int begin = pos;
while (begin < ps->size-1)
{
ps->a[begin] = ps->a[begin + 1];//pos后的数据都朝前挪动一位
begin++;
}
ps->size--;//有效数据-1
}
与头删类似,pos后面的数据都要朝前挪动一位来填补删除pos位置上数据的空缺
//查找顺序表中是否有某个数,如果有就返回该数的下标 int SLFind(SL* ps, SLDataType x) { assert(ps); for (int i = 0; i < ps->size; i++) { if (ps->a[i] == x) { return i; } } return -1; }
void SLModify(SL* ps, int pos, SLDataType x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);//判断要修改数据的坐标是否合法
ps->a[pos] = x;//修改数据
}
int main() { SL s1; SLInit(&s1); SLPushBack(&s1, 1); SLInsert(&s1, 1, 50); SLPushFront(&s1, 20); SLPrint(&s1); int ret=SLFind(&s1, 50); if(ret!=-1) printf("找到了,下标是%d\n", ret); SLErase(&s1, 0); SLPopBack(&s1); SLPrint(&s1); SLModify(&s1, 0, 666); SLPrint(&s1); return 0; }
新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!
**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。