9️⃣中间插入:SLInsert
void SLInsert(SL* psl, int pos, SLDatatype x);
//中间插入:首先要看容量,调用检查容量的函数,接着挪动 void SLInsert(SL* psl,int pos,SLDatatype x) { assert(psl);//应对可能传过来的NULL指针,而且好处是直接告诉你哪个文件的哪一行出问题 //assert(0 <= pos && pos <= psl->size);//说明这个位置可以是顺序表的头和尾 SLCheckCapacity(psl); int end = psl->size - 1; while (end >= pos) { psl->a[end + 1] = psl->a[end]; --end; } psl->a[pos] = x; psl->size++; }
图解:
假设没有assert断言pos的范围,开一组测试看看效果:记住越界是不一定报错的!
void TestSeqList5() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); SLInsert(&s, 2, 30); SLPrint(&s); SLInsert(&s, 20, 30);//在不属于顺序表的地方,插入一个元素,越界但不一定报错! //SLPrint(&s); SLInsert(&s, -20, 30);//负数下标 //SLPrint(&s); }
加了assert(0 <= pos && pos <= psl->size)之后:
这里说一下,头插和尾插都可以调用SLInsert函数,提高代码的复用性
尾插:
void SLPushBack(SL* psl, SLDatatype x) { assert(psl); //psl->a[psl->size] = x; //psl->size++; //SLCheckCapacity(psl); //psl->a[psl->size++] = x; SLInsert(psl, psl->size, x); }
头插:
void SLPushFront(SL* psl, SLDatatype x) { assert(psl); //SLCheckCapacity(psl); 挪动数据 //int end = psl->size - 1; //while (end >= 0) //{ // psl->a[end + 1] = psl->a[end]; // --end; //} //psl->a[0] = x; //psl->size++; SLInsert(psl, 0, x); }
🔟中间删除:SLErase
void SLErase(SL* psl,int pos);
void SLErase(SL* psl, int pos)//从中间删除元素,也可以是首或者尾 { assert(psl);//应对可能传过来的NULL指针,而且好处是直接告诉你哪个文件的哪一行出问题 assert(0 <= pos && pos < psl->size);//说明这个位置可以是顺序表的头和尾 //assert(psl->size>0);//这句代码也可以不加,因为 int start = pos + 1; while (start < psl->size) { psl->a[start - 1] = psl->a[start]; ++start; } psl->size--; }
图解:
再次调用这组测试,这次是为了测试从中间删除:
void TestSeqList5() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); SLInsert(&s, 2, 30);//中间插入 SLPrint(&s); //SLInsert(&s, 20, 30); //SLPrint(&s); //SLInsert(&s, -20, 30); //SLPrint(&s); SLErase(&s, 3);//删除中间下标为3的元素,把元素3删除了 SLPrint(&s); SLPopFront(&s); SLPrint(&s); SLPopBack(&s); SLPrint(&s); SLDestroy(&s); }
执行:这里第三行把3干掉了
调用SLErase(函数
尾删:
void SLPopBack(SL* psl) { assert(psl); // 暴力检查 //assert(psl->size > 0); 温柔的检查 if (psl->size == 0) return; psl->a[psl->size - 1] = 0; //psl->size--; SLErase(psl, psl->size-1); }
头删:
void SLPopFront(SL* psl) { assert(psl); // 暴力检查 //assert(psl->size > 0); ///*int start = 0; //while (start < psl->size-1) //{ // psl->a[start] = psl->a[start + 1]; // start++; //}*/ //int start = 1; //while (start < psl->size) //{ // psl->a[start-1] = psl->a[start]; // start++; //} //psl->size--; SLErase(psl, 0); }
1️⃣1️⃣查找:SLFind
int SLFind(SL* psl, SLDatatype x);//找到返回下标,没有找到返回-1
返回的-1也可以用其它负数,但是一般都是用-1。
int SLFind(SL* psl, SLDatatype x)//查找 { assert(psl);//应对可能传过来的NULL指针,而且好处是直接告诉你哪个文件的哪一行出问题 for (int i = 0; i < psl->size; i++) { if (psl->a[i] == x) { return i;//返回要查找的元素的下标 } } return -1;//走完一遍了还没找到就返回-1,因为下标不可能是负数 }
测试一组查找的代码:
void TestSeqList6() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 6);//返回这个的下标,不会返回下面那个6的下标 SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); int pos = SLFind(&s, 6); if (pos != -1) { SLErase(&s, pos); } SLPrint(&s); SLDestroy(&s); }
找到了就返回该元素的下标,然后从中间删除它,注意这里有两个6,只返回第一个6的下标,因为第一个6是先放进去的
执行:
1️⃣2️⃣修改:SLModify
void SLModify(SL* psl, int pos, SLDatatype x);
void SLModify(SL* psl, int pos, SLDatatype x) { assert(psl);//应对可能传过来的NULL指针,而且好处是直接告诉你哪个文件的哪一行出问题 assert(0 <= pos && pos < psl->size); psl->a[pos] = x; }
调用修改的代码:
void TestSeqList7()//用于测试修改 { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 6); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); int pos = SLFind(&s, 6); if (pos != -1) { SLModify(&s, pos, 10);//4下标的6已经改成10了 } SLPrint(&s); SLDestroy(&s); }
这里再测试一下assert断言的好处:应对可能传过来的NULL指针,而且好处是直接告诉你哪个文件的哪一行出问题
void TestSeqList8() { SL* s = NULL; SLPushBack(s, 1); SLPushBack(s, 2); SLPushBack(s, 3); SLPrint(s); SLDestroy(s); }
三.整体实现代码
SeqLish.h
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<assert.h> //静态的顺序表 //#define N 10000 //typedef int SLDatatype; //struct SeqList //{ // SLDatatype a[N]; // int size; //}; //动态顺序表 typedef int SLDatatype;//这个位置换成double会导致问题,可能会导致全元素都是0 typedef struct SeqList { SLDatatype* a; int size; //存储的有效数据的个数 int capacity;//容量 }SL;//类型名重定义 void SLInit(SL* psl); void SLDestroy(SL* psl); void SLPrint(SL*psl);// 顺序表打印 void SLPushBack(SL* psl, SLDatatype x);//尾插 void SLPushFront(SL* psl, SLDatatype x);//头插 void SLPopBack(SL* psl);//尾删 void SLPopFront(SL* psl);//头删 void SLInsert(SL* psl, int pos, SLDatatype x); void SLErase(SL* psl,int pos); //找到返回下标,没有找到返回-1 int SLFind(SL* psl, SLDatatype x); void SLModify(SL* psl, int pos, SLDatatype x);
SeqList.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"SeqList.h" //顺序表的要求就是连续存储 void SLInit(SL* psl) { psl->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4);//malloc扩容,因为malloc类型是->void* malloc (size_t size);所以需要强制转换 //打印错误信息? if (psl->a == NULL) { perror("malloc fail"); return; } psl->capacity = 4;//使用结构体指针指向访问对象的成员,当前容量 psl->size = 0;//当前有效信息个数 } void SLDestroy(SL* psl)//销毁不是整没了,而是还给操作系统了 { free(psl->a); psl->a = NULL; psl->size = 0; psl->capacity = 0; } void SLPrint(SL* psl) { for (int i = 0; i < psl->size; i++) { printf("%d ", psl->a[i]); } printf("\n"); } //? void SLCheckCapacity(SL* psl) { if (psl->size == psl->capacity)//有效信息的个数等于当前容量 { SLDatatype* tmp =(SLDatatype*)realloc(psl->a, sizeof(SLDatatype) * psl->capacity * 2); if (tmp == NULL)//申请空间过大可能会申请失败 { perror("realloc fail"); return; } psl->a = tmp;//原地扩容用的是原来的地址,异地扩容用的是新的 psl->capacity *= 2;//当前容量*2 } } //尾插法 void SLPushBack(SL* psl, SLDatatype x) { assert(psl); SLCheckCapacity(psl); psl->a[psl->size++] = x;//检查当前容量,不够则扩容 } //头插法必须从后往前挪动数据,不能从往前往后挪动 void SLPushFront(SL* psl, SLDatatype x) { assert(psl); SLCheckCapacity(psl); //挪动数据 int end = psl->size-1; while (end >= 0) { psl->a[end + 1] = psl->a[end]; --end; } psl->a[0] = x; psl->size++; } //尾删 void SLPopBack(SL* psl) { assert(psl); //暴力检查 //assert(psl->size > 0); //温柔检查 if (psl->size == 0) { printf("顺序表为空,删除失败\n"); return;//不报错任何问题,直接回答主函数。 } //psl->a[psl->size - 1] = 0;这句话不好,就是说把最后一个位置变成0 psl->size--; } void SLPopFront(SL* psl)//从后往前 { assert(psl); //暴力检查 assert(psl->size > 0); //温柔检查 if (psl->size == 0) return; int start = 0; while (start < psl->size - 1) { psl->a[start] = psl->a[start + 1]; start++; } /*int start = 1; while (start < psl->size) { psl->a[start - 1] = psl->a[start]; start++; }*/ psl->size--; } //中间插入:首先要看容量,调用检查容量的函数,接着挪动 void SLInsert(SL* psl,int pos,SLDatatype x) { assert(psl); assert(0 <= pos && pos <= psl->size); SLCheckCapacity(psl); int end = psl->size - 1; while (end >= pos) { psl->a[end + 1] = psl->a[end]; --end; } psl->a[pos] = x; psl->size++; } void SLErase(SL* psl, int pos)//从中间删除元素,也可以是首或者尾 { assert(psl); assert(0 <= pos && pos < psl->size); //assert(psl->size>0); int start = pos + 1; while (start < psl->size) { psl->a[start - 1] = psl->a[start]; ++start; } psl->size--; } int SLFind(SL* psl, SLDatatype x)//查找 { assert(psl); for (int i = 0; i < psl->size; i++) { if (psl->a[i] == x) { return i; } } return -1;//走完一遍了还没找到就返回-1,因为下标不可能是负数。 } void SLModify(SL* psl, int pos, SLDatatype x) { assert(psl); assert(0 <= pos && pos < psl->size); psl->a[pos] = x; }
Test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"SeqList.h" void TestSeqList1() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushFront(&s,5); SLPrint(&s); SLDestroy(&s); } void TestSeqList2() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLDestroy(&s); } void TestSeqList3()//测试尾部删除的越界问题,以及打印值问题 { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushFront(&s, 5); SLPushFront(&s, 6); SLPrint(&s); SLPopBack(&s); SLPopBack(&s); SLPrint(&s); SLPopBack(&s); SLPopBack(&s); SLPrint(&s); SLPopBack(&s); SLPopBack(&s); SLPopBack(&s); SLPrint(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPrint(&s); SLDestroy(&s); } void TestSeqList4() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPrint(&s); SLPopFront(&s); SLPopFront(&s); SLPrint(&s); SLPopFront(&s); SLPopFront(&s); SLPrint(&s); //SLPopFront(&s); //SLPopFront(&s); //SLPrint(&s); SLDestroy(&s); } void TestSeqList5() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); SLInsert(&s, 2, 30); SLPrint(&s); //SLInsert(&s, 20, 30); //SLPrint(&s); //SLInsert(&s, -20, 30); //SLPrint(&s); SLErase(&s, 3); SLPrint(&s); SLPopFront(&s); SLPrint(&s); SLPopBack(&s); SLPrint(&s); SLDestroy(&s); } void TestSeqList6() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 6); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); int pos = SLFind(&s, 6); if (pos != -1) { SLErase(&s, pos); } SLPrint(&s); SLDestroy(&s); } void TestSeqList7() { SL s; SLInit(&s); SLPushBack(&s, 1); SLPushBack(&s, 2); SLPushBack(&s, 3); SLPushBack(&s, 4); SLPushBack(&s, 6); SLPushBack(&s, 5); SLPushBack(&s, 6); SLPrint(&s); int pos = SLFind(&s, 6); if (pos != -1) { SLModify(&s, pos, 10); } SLPrint(&s); SLDestroy(&s); } void TestSeqList8() { SL* s = NULL; SLPushBack(s, 1); SLPushBack(s, 2); SLPushBack(s, 3); SLPrint(s); SLDestroy(s); } void menu() { printf("***************************************\n"); printf("1、尾插数据 2、尾删数据\n"); printf("3、头插数据 4、头删数据\n"); printf("5、打印数据 -1、退出\n"); printf("***************************************\n"); } int main() { //TestSeqList1(); TestSeqList2(); //TestSeqList3(); //TestSeqList5(); //TestSeqList8(); return 0; }
欢迎大佬指正,非常感谢您的支持!