提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
数据结构——顺序表的C语言代码实现
数据结构——八种链表的C语言代码实现
数据结构——栈的C语言代码实现
数据结构——队列的C语言代码实现
数据结构——堆的C语言代码实现
使用C语言实现顺序表,重点实现动态顺序表。加强模块化实现功能的能力,了解并熟练使用realloc(),assert()等函数。
鬼话:顺序表 就是把线性表中的所有元素按照其逻辑顺序,依次储存到从指定的储存位置开始的一块 连续 的储存空间中。
人话:自我理解,特殊的数组!即将连续的数据存储在数组中,注意连续性,不可跳跃式存储。
在进行数据结构的代码实现时,最常用的接口函数便是:增、删、查、改。
增:尾插、头插、指定位置插入;
删:尾删、头删、指定位置删除;
查:遍历查找;
改:先找后改;
realloc()函数:
void* realloc (void* ptr, size_t size);
注意:
1.返回值是void*,实际使用中应合理使用强制类型转换;
2.size_t size 是字节数,即所需要开辟的空间大小,此处应和calloc()结合记忆,注意区别!
3.引用
戳此处,查看realloc函数标准形式
realloc()是C语言中最常用的扩容或缩容函数,其改变已开辟的内存空间大小的工作实质是:
在已有空间的末尾寻找空余的连续空间,若末尾的空余空间足够开辟,则便在此处进行开辟,返回的指针为原指针,即所开辟的空间的起始地址没有发生改变;若末尾的空余空间不足以开辟,则对已开辟空间所存储的内容进行拷贝,然后在内存的其它位置寻找足够大的连续空间进行开辟,而原有空间被系统释放,故此时该函数的返回值不再是原指针,即所开辟的空间的起始地址发生了改变;
但实际使用时,未避免引用过多指针,常使用以下方式进行操作:
(DataType*) ptr=(DataType*)realloc(p,sizeof(DataType)*size_t);
if(ptr!=NULL)
p=ptr;
assert()函数:
void assert (int expression);
戳此处,查看assert()函数标准形式
注意引用
条件为真,继续向下执行;
条件为假,终止程序。
#include
#include
#include
建议遵循命名规则,将动态数组命名为arr等名字,p总是带来误解,但我懒得改了。。。
typedef int SLDataType;
//便于更改所存储数据的类型
typedef struct SeqLIst
{
SLDataType* p;
int size;
int capacity;
}SL;
注意在设计接口函数时应使用传址的参数
//初始顺序表
void SeqListInit(SL* ps);
//顺序表的尾插法
void SeqListPushBack(SL* ps, SLDataType n);
//顺序表的尾删法
void SeqListPopBack(SL* ps);
//顺序表的头插法
void SeqListPushFront(SL* ps, SLDataType n);
//顺序表的头删法
void SeqListPopFront(SL* ps);
//查找顺序表中的数据位置
int Find(SL* ps,SLDataType n);
//指定位置插入
void SeqListInsert(SL* ps, int location, SLDataType n);
//指定位置删除
void SeqListDelete(SL* ps, int location);
//检测顺序表容量是否足够
void CheckCapacity(SL* ps);
//接口函数测试函数
void PrintSeqList(SL* ps);
//删除顺序表
void DestroySeqList(SL* ps);
此文件用于实现各接口函数。
#include"SeqList.h"
//初始顺序表
void SeqListInit(SL* ps)
{
(*ps).p = NULL;
ps->capacity = 0;
ps->size = 0;
}
//检测顺序表容量是否足够
void CheckCapacity(SL* ps)
{
//进行扩容,两种情况:1.没有开辟空间;2.容量用尽
if (ps->size == ps->capacity)
{
int Newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDataType* ptr = (SLDataType*)realloc(ps->p, sizeof(SLDataType) * Newcapacity);
if (ptr != NULL)
//扩容成功
ps->p = ptr;
else
{
printf("realloc fail !");
//异常退出,终止程序,使用return的话,只是退出该函数
exit(-1);
}
ps->capacity = Newcapacity;
}
}
//顺序表的尾插法
void SeqListPushBack(SL* ps, SLDataType n)
{
CheckCapacity(ps);
ps->p[ps->size] = n;
ps->size += 1;
}
void SeqListPopBack(SL* ps)
{
if(ps->size>0)
ps->size--;
}
何为暴躁?
assert(条件)条件为假,直接终止函数!
void SeqListPopBack(SL* ps)
{
assert(ps->size>0)
ps->size--;
}
//删除顺序表
void DestroySeqList(SL* ps)
{
free(ps->p);
//防止该指针成为野指针
ps->p = NULL;
ps->capacity = ps->size = 0;
}
//顺序表的头插法
void SeqListPushFront(SL* ps, SLDataType n)
{
CheckCapacity(ps);
//用前值覆盖后值,实现整体后移,必须从后向前两两操作
ps->size += 1;
int end = ps->size - 1;
while (end > 0)
{
//实现插入前的数组的整体后移
ps->p[end] = ps->p[end - 1];
end--;
}
ps->p[0] = n;
}
//顺序表的头删法
void SeqListPopFront(SL* ps)
{
assert(ps->size > 0);
//将已有数组整体前移
int head = 0;
while (head < ps->size - 1)
{
ps->p[head] = ps->p[head + 1];
head++;
}
ps->size--;
}
int Find(SL* ps, SLDataType n)
{
if (ps->size == 0)
{
printf("顺序表为空!\n");
exit(-1);
}
int tem = 0;
while (tem < ps->size)
{
if (ps->p[tem] == n)
{
return tem;
}
tem++;
}
printf("顺序表中没有该值!\n");
return -1;
}
注意判断所要插入的位置,进而合理使用已有的接口函数,该程序设计中输入的位置是从1开始的!
//指定位置插入
void SeqListInsert(SL* ps, int location,SLDataType n)
{
//因为输入的位置是从1开始数的
int L = location - 1;
//确保所要插入的位置合法
assert(L>=0&&L<=ps->size);
//确保顺序表不为空
assert(ps->size > 0);
CheckCapacity(ps);
//如果插入位置在头部
if (L == 0)
{
SeqListPushFront(ps, n);
}
//如果插入位置在尾部
else if (L == ps->size)
{
SeqListPushBack(ps, n);
}
//如果插入位置在已有数组内部
else
{
ps->size++;
int temend = ps->size - 1;
while (temend > L)
{
ps->p[temend] = ps->p[temend - 1];
temend--;
}
ps->p[L] = n;
}
}
//指定位置删除
void SeqListDelete(SL* ps, int location)
{
int L = location - 1;
//确保输入的位置合法
assert(L>=0&&L<=ps->size-1);
//确保顺序表不为空
assert(ps->size > 0);
if (L == 0)
{
SeqListPopFront(ps);
}
else if (L == ps->size - 1)
{
SeqListPopBack(ps);
}
else
{
int temend = L;
while (temend < ps->size - 1)
{
ps->p[temend] = ps->p[temend+1];
temend++;
}
ps->size -= 1;
}
}
//接口函数测试
void PrintSeqList(SL* ps)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d ", ps->p[i]);
}
}
该文件用于存放主函数,本程序只研究如何代码实现顺序表,故多为测试语句,不具有参考价值。具体使用时,可在此处代码实现菜单功能!
#include"SeqList.h"
该处无参考价值,大家随意设置
void testSeqList()
{
SL sl;
SeqListInit(&sl);
SeqListPushBack(&sl, 1);
SeqListPushBack(&sl, 2);
SeqListPushBack(&sl, 3);
SeqListPushBack(&sl, 4);
/*SeqListPopBack(&sl,5);
SeqListPushFront(&sl, 0);*/
//用来测试接口函数
PrintSeqList(&sl);
DestroySeqList(&sl);
}
void testSeqListPushFront()
{
SL sl;
SeqListInit(&sl);
SeqListPushFront(&sl, 1);
SeqListPushFront(&sl, 2);
SeqListPushFront(&sl, 3);
SeqListPushFront(&sl, 4);
SeqListPopFront(&sl);
//int ret=Find(&sl, 2);
PrintSeqList(&sl);
/* printf("\n");
printf("%d", ret);*/
SeqListDelete(&sl,3);
PrintSeqList(&sl);
}
亦无实际价值
int main()
{
//testSeqList();
testSeqListPushFront();
return 0;
}
数据结构的学习在于实际操作,大学课堂的教学偏向于理论学习,如若只是浅尝辄止地了解一些名词概念毫无作用,故特此逐一实现数据结构的C语言代码,进而鞭策自己迎难而上!
与君共勉!