顺序表源码:
SeqList.h文件
//防止重复调用/包含//动态顺序表 --按需扩空间typedefintSLDataType; //为方便维护修改数据类型,重定义顺序表的数据类型typedefstructSeqList//多个数据定义为结构体,{ SLDataType*a; //想到动态开辟内存函数malloc,定义一个指针,指向动态开辟的数组intsize; //有效数据个数intcapacity; //空间容量大小,满了relloc扩容}SL;//typedef重定义voidSLPrint(SL*ps); //打印函数的声明//void SeqListInit(SL s); //全称voidSLInit(SL*ps); //定义一个顺序表voidSLDestroy(SL*ps); //释放动态开辟的内存voidSLCheckCapacity(SL*ps); //检查,扩容//尾插尾删voidSLPushBack(SL*ps, SLDataTypex); voidSLPopBack(SL*ps); //头插头删voidSLPushFront(SL*ps, SLDataTypex); voidSLPopFront(SL*ps); //在pos位置插入数据voidSLInsert(SL*ps, intpos, SLDataTypex); //删除pos位置数据,删除指定位置的数据voidSLErase(SL*ps, intpos); ////查找数据,为实现删除指定数据//int SLFind(SL* ps, SLDataType x);//查找改进,针对有重复数据intSLFind(SL*ps, SLDataTypex, intbegin);
SeqList.c文件
//引用头文件voidSLInit(SL*ps) { assert(ps); //初始化ps->a=NULL;//结构体指针用->ps->size=0; ps->capacity=0; } //打印函数voidSLPrint(SL*ps) { assert(ps); for (inti=0; i<ps->size; ++i) { printf("%d ", ps->a[i]); } printf("\n"); } voidSLDestroy(SL*ps) { //if(ps->a !=NULL)assert(ps); if (ps->a) //为真说明内存开辟成功,需要释放置空 { free(ps->a); //释放,free报错往往是越界,或者是释放的地方不对,一般free的时候才会检查越界ps->a=NULL; //置空ps->size=ps->capacity=0;//顺便修改他俩的值 } } voidSLCheckCapacity(SL*ps)//检查,扩容{ assert(ps); //插入前得开空间,判断空间是否满,否则涉及到越界问题//判断size和capacity是否相等,相等则满,或者还没开辟空间,因为开始时都初始化为0if (ps->size==ps->capacity) { intnewCapacity=ps->capacity==0?4 : ps->capacity*2;//如果是0还没开辟空间,如果不是就直接扩为2倍//ps->a = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));//扩容 ,realloc后面的参数是大小,前面的是需要扩容的空间//需要接收地址,因为relloc返回的是新开空间的地址SLDataType*tmp= (SLDataType*)realloc(ps->a, newCapacity*sizeof(SLDataType));//扩容 ,realloc后面的参数是大小,前面的是需要扩容的空间//需要用临时变量tmp接收地址,因为relloc返回的是新开空间的地址if (tmp==NULL)//判断扩容是否成功 { perror("relloc fail"); exit(-1);//异常终止程序,0代表正常终止 } ps->a=tmp; ps->capacity=newCapacity; } } //尾插O(1)voidSLPushBack(SL*ps, SLDataTypex) { /*assert(ps);SLCheckCapacity(ps);ps->a[ps->size] = x;ps->size++;*/SLInsert(ps, ps->size, x);//复用} //尾删voidSLPopBack(SL*ps) { //温柔的检查/*if (ps->size == 0){return;}*///暴力的检查(断言)assert(ps->size>0);//会直接报错,为真继续走,为假结束//ps->a[ps->size - 1] = 0;//将最后一个数据改为0,再size--,意义不大,因为print是以size为基础的,只会访问size前面的数据,再插入数据会将无效数据直接覆盖ps->size--; //SLErase(ps, ps->size - 1);//复用} //头插O(N)voidSLPushFront(SL*ps, SLDataTypex) { //assert(ps);//SLCheckCapacity(ps);////挪动数据//int end = ps->size - 1;//size-1是最后一个元素的下标//while (end >= 0)//{// ps->a[end + 1] = ps->a[end];// --end;//}//ps->a[0] = x;//ps->size++;SLInsert(ps, 0, x);//复用} //头删voidSLPopFront(SL*ps) { /*assert(ps);assert(ps->size>0);int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;*/SLErase(ps, 0);//复用} //在pos位置插入数据voidSLInsert(SL*ps, intpos, SLDataTypex) { assert(ps); assert(pos>=0); assert(pos<=ps->size);//必须是连续存储SLCheckCapacity(ps);//考虑到后面空间不够可能越界intend=ps->size-1; while (end>=pos) { ps->a[end+1] =ps->a[end]; end--; } ps->a[pos] =x; ps->size++; } //删除pos位置数据voidSLErase(SL*ps, intpos) { assert(ps); assert(pos>=0); assert(pos<ps->size); //assert(ps->size > 0);//挪动数据覆盖intbegin=pos+1; while (begin<ps->size) { ps->a[begin-1] =ps->a[begin]; begin++; } ps->size--; } ////查找//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;//}//查找改进,针对有重复数据intSLFind(SL*ps, SLDataTypex,intbegin) { assert(ps); for (inti=begin; i<ps->size; i++) { if (ps->a[i] ==x) { returni; } } return-1; }
test.c文件
在插入菜单前,main函数中调用的测试函数可以根据需要进行修改。
voidTestSeqList1() { SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1); SLPushBack(&sl, 2); SLPushBack(&sl, 3); SLPushBack(&sl, 4); SLPushBack(&sl, 5); SLPushBack(&sl, 5); SLPushBack(&sl, 5); SLPushBack(&sl, 5); SLPushBack(&sl, 5);//插入了9个数据,扩了两次容SLPrint(&sl); SLDestroy(&sl); } voidTestSeqList2() { SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1); SLPushBack(&sl, 2); SLPushBack(&sl, 3); SLPushBack(&sl, 4); SLPrint(&sl); SLPopBack(&sl); SLPrint(&sl); SLPopBack(&sl); SLPrint(&sl); SLPopBack(&sl); SLPopBack(&sl); SLPopBack(&sl); SLPopBack(&sl); //SLPopBack(&sl);//越界调试,size--会导致size出现负数,后面如果再尾插,插入到了不属于自己的空间,就是越界访问SLPrint(&sl); SLPushBack(&sl, 3); SLPushBack(&sl, 4); SLDestroy(&sl);//去掉不报错} voidTestSeqList3() { SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushFront(&sl, 1); SLPushFront(&sl, 2); SLPushFront(&sl, 3); SLPushFront(&sl, 4); SLPrint(&sl); SLPopFront(&sl); SLPopFront(&sl); SLPopFront(&sl); SLPopFront(&sl); SLPopFront(&sl);//四个数据删除五次size为空,运行正常,可能没测试到位SLPushBack(&sl, 10);//这时就出现了问题,发生了越界,free会报错SLPrint(&sl); SLDestroy(&sl); } voidTestSeqList4() { SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1); SLPushBack(&sl, 2); SLPushBack(&sl, 3); SLPushBack(&sl, 4); SLPrint(&sl); SLInsert(&sl, 2, 20);//第二个位置插入20SLPrint(&sl); SLInsert(&sl, 5, 500);//相当于尾插,需要考虑复用SLPrint(&sl); SLInsert(&sl, 0, 100);//相当于头插,需要考虑复用SLPrint(&sl); SLDestroy(&sl); } voidTestSeqList5() { SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1); SLPushBack(&sl, 2); SLPushBack(&sl, 3); SLPushBack(&sl, 4); SLPrint(&sl); SLErase(&sl, 2);//删除下标为2的值SLPrint(&sl); SLErase(&sl, 2);//删除下标为2的值SLPrint(&sl); SLErase(&sl, 0);//删除下标为2的值SLPrint(&sl); SLDestroy(&sl); } voidTestSeqList6() { SLsl;//定义顺序表的结构SLInit(&sl);//初始化,传给了SeqList.c中的函数,实参,传给形参,形参是实参的临时拷贝SLPushBack(&sl, 1); SLPushBack(&sl, 2); SLPushBack(&sl, 3); SLPushBack(&sl, 4); SLPushBack(&sl, 5); SLPushBack(&sl, 7); SLPushBack(&sl, 8); SLPushBack(&sl, 5); SLPrint(&sl); /*int pos = SLFind(&sl, 5);if (pos != -1){SLErase(&sl, pos);}SLPrint(&sl);*/intpos=SLFind(&sl, 4,0);//从0开始查找if (pos!=-1) { SLErase(&sl, pos); } SLPrint(&sl); //删除所有的5pos=SLFind(&sl, 5, 0); while (pos!=-1) { SLErase(&sl, pos); pos=SLFind(&sl, 5, pos);//从删除5的位置继续往后找 } SLPrint(&sl); SLDestroy(&sl); } //int main()//{// //TestSeqList1();// //TestSeqList2();// //TestSeqList3();// //TestSeqList4();// //TestSeqList5();// TestSeqList6();//// //int* p1 = malloc(4);// //int* p2 = realloc(p1, 20);// //int* p3 = realloc(p2, 2000);//realloc原地扩容和异地扩容的演示//// ////越界读基本不会被检查出来// //int a[10] = { 0 };// //printf("%d\n", a[10]);// //printf("%d\n", a[11]);// //// ////越界写,可能会被检查出来// ////a[10] = 0;//检查出来// //a[11] = 0;//未检查出来// ////// return 0;//}//菜单voidmenu() { printf("********************************************\n"); printf("1、尾插数据 2、尾删数据\n"); printf("3、头插数据 2、头删数据\n"); printf("5、打印数据 -1、退出\n"); printf("********************************************\n"); } intmain() { SLs;//定义顺序表SLInit(&s);//初始化intval=0; intoption=0; do { menu(); printf("请输入你的操作:>"); scanf("%d", &option); switch (option) { case1: printf("请依次输入你要尾插的数据,以-1结束"); scanf("%d", &val); while (val!=-1) { SLPushBack(&s, val); scanf("%d", &val); } break; case2: SLPopFront(&s); break; case3: break; case4: break; case5: SLPrint(&s); break; default: break; } }while (option!=-1); SLDestroy(&s); return0; }
结语:
这里本章内容就介绍完了, 希望以上内容对大家有所帮助👀,如有不足望指出🙏
前路漫漫!努力变强💪💪 吧!!