当前位置: 首页 > news >正文

网站中的宣传册翻页动画怎么做怎样可以做网站站长

网站中的宣传册翻页动画怎么做,怎样可以做网站站长,淘宝网站链接怎么做要,怎么上线网站创作不易#xff0c;友友们给个三连呗#xff01; 本文为博主在DS学习阶段的第一篇博客#xff0c;所以会介绍一下数据结构#xff0c;并在最后学习对顺序表的实现#xff0c;在友友们学习数据结构之前#xff0c;一定要对三个部分的知识——指针、结构体、动态内存管理的…      创作不易友友们给个三连呗 本文为博主在DS学习阶段的第一篇博客所以会介绍一下数据结构并在最后学习对顺序表的实现在友友们学习数据结构之前一定要对三个部分的知识——指针、结构体、动态内存管理的内容有一定的了解如果友友们对这三块知识不熟悉的话可以去看看博主的文章哦 深入理解指针1 深入理解指针2 深入理解指针3 深入理解指针4 自定义类型-——结构体 动态内存管理 如果了解了这三块的知识可以更好地学习后面地内容下面步入正题 一、数据结构相关概念 什么是数据结构呢从字面意识理解就是“数据”与“结构”。 1.1 什么是数据 比如常⻅的数值1、2、3、4.....、教务系统⾥保存的用户信息姓名、性别、年龄、学历等 等、网页里肉眼可以看到的信息⽂字、图⽚、视频等等这些都是数据。 1.2 什么是结构 当我们想要使⽤⼤量使⽤同⼀类型的数据时通过⼿动定义⼤量的独⽴的变量对于程序来说可读性⾮常差我们可以借助类似数组这样的数据结构将⼤量的数据组织在⼀起结构也可以理解为组织数据的方式。举个例子假设我们要在一个大草原上找到一只叫“咩咩”的羊很困难但是在羊圈里找到1号羊就很简单因为“羊圈”这个结构有效地将羊群组织了起来。 广泛一点说我们生活中每天都充斥着各种各样的数据为了能够更方便的管理数据我们需要有一个将数据有效地组织起来的方法这时候就需要用到——数据结构。 1.3 什么是数据结构 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在⼀种或多种特定关系 的数据元素的集合。数据结构反映数据的内部构成即数据由那部分构成以什么⽅式构成以及数据元素之间呈现的结构。 在一个生意火爆的餐馆中如果不借助排队的⽅式来管理客⼾会导致客⼾就餐感受差、等餐时间⻓、餐厅营业混乱等 情况。同理程序中如果不对数据进⾏管理可能会导致数据丢失、操作数据困难、野指针等情况。 通过数据结构能够有效将数据组织和管理在⼀起。按照我们的⽅式任意对数据进⾏增删改查等操作。 1.4 数据结构能为我们做什么 1、能够存储数据如顺序表、链表等结构 2、存储的数据方便查找 3、方便我们操作数据增加、删除、修改 1.5 最基础的数据结构 最基础的数据结构数组。 有了数组为什么还要学习其他的数据结构 假定数组有10个空间已经使⽤了5个向数组中插⼊数据步骤 求数组的⻓度求数组的有效数据个数向下标为数据有效个数的位置插⼊数据注意这⾥是 否要判断数组是否满了满了还能继续插⼊吗..... 假设数据量⾮常庞⼤频繁的获取数组有效数据个数会影响程序执⾏效率。 结论最基础的数据结构能够提供的操作已经不能完全满⾜复杂算法实现。 二、顺序表相关概念 2.1 线性表 线性表linear list是n个具有相同特性的数据元素的有限序列也可以理解成具有部分相同特性的一类数据结构的集合。 线性表是⼀种在实际中⼴泛使⽤的数据结构常⻅的线性表顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的 线性表在物理上存储时通常以数组和链式结构的形式存储。 案例蔬菜分为绿叶类、⽠类、菌菇类。 2.2 如何理解数据结构中逻辑结构和物理结构 逻辑结构对数据之间关系的描述 物理结构数据存储在磁盘中的方式 2.3 顺序表的分类 对于咖喱饭来说他的底层是米饭通过增加了咖喱升级成了咖喱饭。 对于顺序表来说顺序表的底层结构是数组即通过对数组的封装实现了常用的增删改查等接口将数组升级为了所谓的顺序表。 ps接口就是规定程序做什么但是又不在其中实现。友友们暂时理解成功能就行。 顺序表由于底层数组的不同定长数组和动态数组又区分了静态顺序表和动态顺序表 注顺序表的物理结构也是线性的因为底层是数组有连续存放的特点 2.3.1 静态顺序表 概念使用定长数组存储元素 #define N 1000 //定义一个宏方便根据需要修改定长数组的大小这样就不用改动后面的内容 typedef int SLDataType; //因为顺序表根据需要可能需要存储不同的数据类型所以将其进行重命名 //如果想改成char和float可以直接在这里修改不需要去改动后面的内容 typedef struct Seqlist {SLDataType a[N];//定长数组可以通过修改#define定义的N来改变数组大小int size; //定长数组开辟了N个空间但不代表里面有N个有效数个数所以需要size来记录有效数个数。 }SL;//将名字修改得简短一点 1、为什么不直接用a[1000]还要定义一个宏来表示 为了方便代码的修改如果在代码写一半的时候我们发现开辟的数组大小需要进行调整那么只需要修改#define定义的N就行了如果是直接写1000一旦需要修改所有程序中出现的a[1000]就得一个个修改 2、为什么需要给int重命名为SLDataType 因为我们希望我们的顺序表是灵活的在当前数据表我们需要存储的是int类型的数据但如果在后期我们希望能够有存储char、float、double的顺序表只需要将typedef int SLDataType中的int进行修改就行如果没有这条重命名那么当我希望用这个顺序表存储其他类型元素时就休要修改大量的代码 3、为什么需要size有效数个数 因为我们虽然开辟了这么多空间但是并不代表这么多空间都存储着有效的数据所以我们需要用一个size来记录该数组存储的有效数据个数。 2.3.2 静态顺序表的劣势 如果使用静态顺序表存储数据那么在准备该项目的一开始就得将数组长度定下来但是很多时候我们需要存储数据的多少是在程序运行的时候才能得知的比如我开发了一个app但是一开始并不知道会有多少人来使用就可能造成以下问题 1、给定的数组长度如果不够那么会导致后续的数据保存失败造成数据丢失。 假如我们开发了一个app我们需要一开始就预估数组的大小假设我们预估100但是有200个人来注册那么当前100人注册完成后从101个人开始由于数组容量不够数据不能有效保存这就会造成数据丢失这在企业中会是一个非常严重的事故并且会让别人知道你是一个容易出事故的员工。 2、给定的数组长度如果太大就会造成空间浪费 我们考虑到我们的app可能会很火爆所以我们预先设置了10000的大小但一运行发现不到100个人注册如果你团队的其他人也不注重这个那么就会造成一个小业务却占用巨大内存空间的问题这不仅会造成硬件上的浪费还会让别人知道你是一个对内存的管理能力极差的员工。 2.3.3 动态顺序表 通过分析静态顺序表的劣势我们发现该方法特别容易出问题所以我们就需要动态顺序表因为动态顺序表的底层是动态数组他和定长数组的区别就是长度并不是在一开始就确定的这使得程序员可以在程序运行过程中更灵活地去管理内存根据需求去开辟空间尽可能减少了空间浪费。 typedef int SLDataType; //因为顺序表根据需要可能需要存储不同的数据类型所以将其进行重命名 //如果想改成char和float可以直接在这里修改不需要去改动后面的内容 typedef struct Seqlist {SLDataType*a;//动态数组一开始不确定大小程序员可以根据过程中的需求去合理开辟int capacity;//空间容量假设我们扩容了用其记录扩容后动态数组的大小。int size;//开辟了相应的空间但需要size来记录有效数个数。 }SL;//将名字修改得简短一点 跟静态顺序表相比除了底层的数组不同我们还需要一个capacity因为动态数组的创建并不像定长数组一样可以一开始就知道数组的容量所以当我们为该动态数组动态开辟内存时就需要使用capacity去记录该动态数组的容量。 三、顺序表的实现 我们知道了静态顺序表可能存在的问题所以我们一般使用的是动态顺序表下面介绍的也是动态顺序表的实现。 3.1 初始化和销毁 1、初始化 void SLInit(SL* ps) //为什么要传址 //1.如果是传值形参是实参的临时‘值’拷贝如果我们创建 // 的ps未初始化那么是没有办法进行值传递的 //2.即使我们初始化了将值传过去了由于形参是实参的 // 临时拷贝因此并不会改变实际ps的值 {ps-a NULL;ps-size ps-capacity 0; } 为什么这里的参数要用指针形式 1如果是传值形参是实参的临时‘值’拷贝如果我们创建的ps未初始化那么是没有办法进行值传递的 2即使我们初始化了将值传过去了由于形参是实参的临时拷贝因此并不会改变实际ps的值 综上由于我们需要去改变ps的实际内容就必须传地址所以需要用指针类型去接收在后续的其他函数中也是如此 2、销毁 //必须要确保有动态内存的开辟才能将其释放所以释放前一定要判断是否为空 void SLDestory(SL* ps) {assert(ps);if (ps-a)free(ps-a);//释放不代表不存在ps-a NULL;ps-size 0;ps-capacity 0; } 1为什么销毁前还需要判断ps是否为空 如果传入的是NULL就没有必要销毁也就是说free其实跟realloc是配对的如果没有对顺序表的动态数组开辟过空间那么自然也没有必要free。 2ps-a已经被释放了为什么还要赋给NULL有必要吗 非常有必要因为这段空间被释放并不代表不存在只不过是失去了这段空间的使用权限指针的值并没有改变我们无法直接通过指针自身来进行判断空间是否已经被释放将指针置空有助于判断一个指针所指向的空间已经被释放因为写大量代码之后可能会忘记掉ps-a已经被释放一旦误用造成程序崩溃而如果ps-a是一个空指针那么编译器会通过报错来提醒你。 3.2 扩容的原则 1一次扩一个元素大小的空间 插入一个元素不会造成空间的浪费但是这样就需要不断地进行扩容我们知道realloc本质也是个函数每次调用都需要开辟函数栈帧不断地调用会导致程序运行的效率低下。 2一次扩容固定大小的空间比如10、100、1000 这个扩容的固定大小我们难以合理的把握如果小了会造成频繁扩容产生的效率底下如果大了就会造成空间浪费。 3成倍数的扩容1.5倍、2倍 这是一种定式1.5倍或者2倍数的增长相比其他方法更能节省空间至于为什么这个博主暂时还没有办法深入解释但如果问为什么是1.5倍或2倍而不是3倍或4倍可以说就是因为倍数过大会导致数据插入越来越多扩容大小就越来越大。总之一定要记住这个定式所以我们后面的数据结构扩容基本都是扩大1.5或者2倍。 3.3 扩容的方式 因为使用动态开辟扩容由于数组是开辟的是连续的内存当我们直接扩大时如果后面的空间尚未被分配那么就可以直接扩大但是如果该空间已经被分配了那么如果强行占用就会造成别的数据丢失所以有以下两者情况 情况1要扩展内存就直接原有内存之后直接追加空间原来空间的数据不发⽣变化。 情况2原有空间之后没有⾜够多的空间时扩展的⽅法是在堆空间上另找⼀个合适大小的连续空间然后将旧空间里原有数据拷贝在新空间上然后释放旧空间最好返回新空间的地址。 3.4 扩容和打印 1、扩容 因为在后续的操作中比如尾插、头插、指定位置插入每加入一个数据有可能会导致空间不足所以我们先来实现这样的一个扩容函数。 void SLCheckCapacity(SL* ps) {if (ps-capacity ps-size)//判断是否需要扩容{int newcapacity ps-capacity 0 ? 4 : 2 * ps-capacity;//如果capacity为0则赋给他4的初始值如果不为零就乘两倍SLDataType* temp (SLDataType*)realloc(ps-a, newcapacity * sizeof(SLDataType));//注意第二个参数的单位是字节所以newcapacity要乘以sizeof(SLDataType)。//realloc可以调整动态开辟内存的大小比calloc和malloc更灵活一点if (temp NULL)//relloc可能开辟失败 失败则退出程序{perror(realloc);exit(1);//退出程序}//if不成立则开辟成功ps-a temp;//记录开辟空间的首地址ps-capacity newcapacity;//记录新的容量大小} } 1int newcapacity ps-capacity 0 ? 4 : 2 * ps-capacity的含义是什么 因为我们在对顺序表初始化的时候给capacity赋给的是0如果是0无论乘以多少倍容量都不会变所以我们这边应用了一个三目表达式用newcapacity来接收结果如果capacity为0那我就先赋给他一个初始值4如果他不为0则按照原计划乘2倍最后再将newcapacity的值赋给ps-capacity。 2为什么使用realloc malloc和calloc的作用是申请一段连续的空间然后calloc还多了一个初始化的功能但是realloc可以调整动态开辟空间的大小因为我们未来很可能需要多次扩容显然realloc更加灵活但是也有两个易错点1、realloc的第二个参数传递的是调整后的空间大小他的单位是字节所以newcapacity要乘以sizeof(SLDataType)才行。2、realloc也有可能会开辟失败所以一定不要直接用我们顺序表里的动态数组去接收返回的地址因为原来的数组中可能已经存在一些数据了如果动态开辟空间失败还会造成原来数据的丢失所以一定要先用一个相同类型的指针去接收开辟空间的地址并进行判断确保不为NULL了才能安全地传给我们顺序表里地动态数组。 3exit1和return1的区别是什么 使用场景 return 用于从函数返回。在 main 函数中return 也会结束程序。 exit() 是一个标准库函数可以在程序中的任何地方被调用来终止程序。结束方式 return 只会结束当前的函数且如果是在子函数中使用程序其余部分还会继续执行。 exit() 则会立即结束整个程序的执行且不会返回到调用者。清理操作       当在 main 函数中使用return结束程序时这与调用 exit() 是相等的因为他们都会执行一些清理操作。这包括执行所有 atexit 设置的终止函数刷新所有的buffered I/O关闭所有打开的文件等。        但是在子程序非main函数中return 不会执行这些操作而 exit() 仍会执行。终止状态传递       return 在 main 函数中的用法和 exit() 都可以向操作系统传递终止状态。在 main 中 return 0; 或者 exit(0); 表示程序正常结束。        在其他函数中return 我们可以返回一个值来表示函数结果而 exit() 不仅会结束程序而且不返回任何 总的来说就是return 1温柔一点exit1会暴力一点在这里用哪个都是可以的平时还是要结合实际情况来使用。 2、打印 该函数没有太大的意义单纯就是为了让我们在实现顺序表的过程中对每一个封装的函数进行验证这样我们可以及时找到错误并改正如果等到全部代码写完了再去判断对错此时调试的难度就很大了所以写这个函数目的就是为了验证 void SLPrint(SL* ps) {for (int i 0; i ps-size; i){printf(%d , ps-a[i]);} 需要注意的是其实对于打印函数来说我们并不需要对里面的数据有任何操作只是单纯的展示所以这里使用值传递也是可以的但是为了保证接口一致性这样就是方便用户和我们在使用该顺序表时不需要去考虑什么时候是值传递什么时候是地址传递。 3.5 尾插和头插 1、尾插 有两者情况一种时空间足够直接插入一种是空间不够需要扩容后才能插入。 void SLPushBack(SL* ps, SLDataType x) {//assert粗暴的判断方式assert(ps);//温柔的判断方式//if (ps)//return 1;SLCheckCapacity(ps);//判断是否需要扩容//空间足够直接插入ps-a[ps-size] x;ps-size;//插入数据后有效个数加1 }为什么需要判断ps是否为空 因为我们封装这个函数是为了实现顺序表的尾插如果传入的是一个空指针那么后续操作就会出问题其实这也是为了避免该函数被滥用不能是你想传什么就传什么后面的很多函数接口都要考虑这个情况!! 注只要是插入数据一定不要忘记最后要size 2、头插 可以通过图发现头插需要将所有数据往后挪一位挪动的时候要注意挪动的顺序如果是从前往后挪那么0一旦覆盖原来1的位置1的数据就丢失了所以必须从后往前挪 void SLPushFront(SL* ps, SLDataType x) {assert(ps);//判断传入的是否是空指针SLCheckCapacity(ps);//判断是否需要扩容//空间足够 从后往前挪for (int i ps-size; i 0; i--){ps-a[i] ps-a[i - 1];//边界判断ps-a[1]ps-a[0]}ps-a[0] x;ps-size; } for循环边界的判断找循环的最后一次去验证就行比如说int i ps-size; i 0;我们通过观察最后一次循环ps-a[1]ps-a[0]恰好是我们想要的结果所有数据都后挪完成了说明此时for循环的边界没有问题如果不是我们想要的结果再及时去调整for循环的边界条件。 3.6 尾删和头删 1、尾删 有两者情况有数据的情况就删除最后一个元素如果没有数据就不执行 void SLPopBack(SL* ps) {assert(ps);//判断传入的是否是空指针assert(ps-size);//确保里面有元素否则不执行//ps-a[ps-size - 1] 0;没必要ps-size--; } 为什么ps-a[ps-size - 1] 0没必要因为无论这里是否有值只要size--了那么他就不是有效的元素了即使后面又插入了新元素插入的新元素都是直接覆盖掉原数据所以没必要特意地去赋值0 2、头删 通过上图我们可以发现删除了首元素之后要将后面的元素依次往前挪如果是从后往前挪那么3一旦覆盖2就找不到2了所以必须从前往后挪 void SLPopFront(SL* ps) {assert(ps);//判断传入的是否是空指针assert(ps-size);//确保里面有元素否则不执行 //从前往后挪for (int i 0; i ps-size - 1; i){ps-a[i] ps-a[i 1];//边界判断ps-a[size-2] ps-a[size-1]}ps-size--; } 3.7 指定位置之前插入和指定位置删除 指定位置的插入以及删除我们都需要传入一个指定的位置pos。 1、指定位置之前插入 由图可知插入之前要先将插入位置后面的元素往后挪一位然后再插入如果从前往后挪2会覆盖3就找不到3了所以要从后往前挪 void SLInsert(SL* ps, int pos, SLDataType x) {assert(ps);//判断传入的是否是空指针assert(pos 0 pos ps-size);//确保不要瞎传一个pos的值进来SLCheckCapacity(ps);//判断是否需要扩容//pos之后的元素从后往前挪for (int i ps-size; i pos; i--){ps-a[i] ps-a[i - 1];//边界判断ps-a[pos1] ps-a[pos]}ps-a[pos] x;ps-size; } 为什么要有assert(pos 0 pos ps-size) 因为我们封装这个函数是希望在指定的位置去插入一个数据但是如果你传入的这个位置并不是目前数组的有效位置那么即使你插入进去了该数据也不会被访问到所以这个操作也是为了避免函数被滥用。 2、指定位置删除 由图可知指定位置删除之后要把后面的元素往前挪要从前往后挪 void SLErase(SL* ps, int pos) {assert(ps);//判断传入的是否是空指针assert(pos 0 pos ps-size);//确保不要瞎传一个pos的值进来assert(ps-size);//确保里面有元素否则不执行for (int i pos; i ps-size-1; i){ps-a[i] ps-a[i1];//边界判断:ps-a[i-2] ps-a[i-1];}ps-size--; }3.8 查找 指定位置之前和指定位置删除都需要传入一个pos指定的位置那么如果我们是想要在下标为几的位置操作那么直接传该下标就好了但是如果我们是想要根据该下标的内容去找到该下标比如说我希望删除该顺序表中的3那么就需要我们去遍历数组找到这个3的下标再传给指定位置删除的接口来实现 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;//找不到返回一个无效的下标 } 3.9 总结 1、我们多次用到assert的意义是什么 我们利用assert本质上是为了避免函数被滥用比如说涉及到对顺序表内部的数据进行增删等操作我们需要通过assertps来确保传入的不是一个NULL指针涉及到对数据进行删除我们需要用assertps-size来确保顺序表内部有元素可以被删除的避免了对空顺序表的操作。在对指定位置进行操作时我们需要通过assertpos 0 pos ps-size来避免传入的是无效位置因为这样插入的数据是不会被访问到的。综上我们发现assert能够及时发现我们代码中可能存在的误操作其实我们思考的基点是从传入的参数开始的也就是说作为一个程序员我们思考封装该函数需要什么参数的时候也要思考这个参数有没有可能会传入一个导致程序崩溃的参数所以我们必须思考这个问题然后用assert来预防这些问题不论是误用还是被他人滥用会立即停止程序并指出错误而不会出现程序崩溃的问题 2、for循环的边界判断 当我们使用for循环的时候无法判断边界的时候一定不要慌张可以先预估一个大概的值然后通过推测最后一次循环带来的结果是否和我们想要的结果一样如果不一样及时地进行调整一定可以找到正确的边界值。 3、数据结构的一些思考 无论是顺序表还是链表我们在操作写代码的时候其实可以通过画图去理解不要光凭想象好记性不如烂笔头画图可以很好地帮助理解我们应该怎么去对数据结构进行操作以及前期学习的指针也是如此遇到任何的指针运算题一定要画图 4、顺序表的通用性 这次我们是利用顺序表存储int类型的数据那如果下次我们想要存储char类型、float类型、double类型也是可以的这也是为什么我们前期需要对int重命名的原因想修改存放的类型直接在那里改一下就可以了同时我们应该思考我们设置的上述所有接口是否都可以无缝衔接其实都是可以的可以仔细看看上面所有接口比如将int换成float是否通用打印函数是不可以的因为这个函数本身的存在意义就是为了方便我们当每次封装完一个接口的时候可以通过main函数去调用并使用打印函数打印出来本身就是一个展示的作用目的是为了我们测试我们的代码是否正确。查找函数也是不可以的因为查找函数我们实现的是通过下标对应int类型元素去找到下标但以后我们可能还会根据不同的情况去寻找下标比如在通讯录中可能就是根据名字去找下标 综上希望友友们可以利用这个打印函数每写完一个功能的函数就自己去调用检测一下如果有问题就自己去调试相比直接抄会有很大收获的下面我会把所有代码都写出来方便友友们复制同时要注意代码虽然是对的但是并不意味着一定要这样写只是参考如果可以优化的话友友们可以进行发挥 四、顺序表实现的所有代码 seqlist.h #pragma once #includestdio.h #includeassert.h #includestdlib.htypedef int SLDataType; //因为顺序表根据需要可能需要存储不同的数据类型所以将其进行重命名 //如果想改成char和float可以直接在这里修改不需要去改动后面的内容 typedef struct Seqlist {SLDataType*a;//动态数组一开始不确定大小程序员可以根据过程中的需求去合理开辟int capacity;//空间容量假设我们扩容了用其记录扩容后动态数组的大小。int size;//开辟了相应的空间但需要size来记录有效数个数。 }SL;//将名字修改得简短一点void SLInit(SL* ps);//初始化 void SLDestory(SL* ps);//销毁 void SLPrint(SL* ps);//打印 void SLCheckCapacity(SL* ps);//扩容 void SLPushBack(SL* ps, SLDataType x);//尾插 void SLPushFront(SL* ps, SLDataType x);//头插 void SLPopBack(SL* ps);//尾删 void SLPopFront(SL* ps);//头删 void SLInsert(SL* ps, int pos, SLDataType x);//指定位置之前插入 void SLErase(SL* ps, int pos);//指定位置删除 int SLFind(SL* ps, SLDataType x);//查找指定数据的位置 seqlist.c #includeseqlist.h void SLInit(SL* ps) {//为什么要传址 //1.如果是传值形参是实参的临时‘值’拷贝如果我们创建 // 的ps未初始化那么是没有办法进行值传递的 //2.即使我们初始化了将值传过去了由于形参是实参的 // 临时拷贝因此并不会改变实际ps的值ps-a NULL;ps-size ps-capacity 0; }//必须要确保有动态内存的开辟才能将其释放所以释放前一定要判断是否为空 void SLDestory(SL* ps) {if (ps-a)free(ps-a);//释放不代表不存在ps-a NULL;ps-size 0;ps-capacity 0; }void SLCheckCapacity(SL* ps) {if (ps-capacity ps-size)//判断是否需要扩容{int newcapacity ps-capacity 0 ? 4 : 2 * ps-capacity;//如果capacity为0则赋给他4的初始值如果不为零就乘两倍SLDataType* temp (SLDataType*)realloc(ps-a, newcapacity * sizeof(SLDataType));//注意第二个参数的单位是字节所以newcapacity要乘以sizeof(SLDataType)。//realloc可以调整动态开辟内存的大小比calloc和malloc更灵活一点if (temp NULL)//relloc可能开辟失败 失败则退出程序{perror(realloc fail);exit(1);//退出程序}//if不成立则开辟成功ps-a temp;//记录开辟空间的首地址ps-capacity newcapacity;//记录新的容量大小} }void SLPrint(SL* ps) {for (int i 0; i ps-size; i){printf(%d , ps-a[i]);} }void SLPushBack(SL* ps, SLDataType x) {//assert粗暴的判断方式assert(ps);//温柔的判断方式//if (ps)//return 1;SLCheckCapacity(ps);//判断是否需要扩容//空间足够直接插入ps-a[ps-size] x;ps-size;//插入数据后有效个数加1 }void SLPushFront(SL* ps, SLDataType x) {assert(ps);//判断传入的是否是空指针SLCheckCapacity(ps);//判断是否需要扩容//空间足够 数据往后挪一位for (int i ps-size; i 0; i--){ps-a[i] ps-a[i - 1];//边界判断ps-a[1]ps-a[0]}ps-a[0] x;ps-size; }void SLPopBack(SL* ps) {assert(ps);assert(ps-size);//确保里面有元素否则不执行//ps-a[ps-size - 1] 0;没必要ps-size--; }void SLPopFront(SL* ps) {assert(ps);//判断传入的是否是空指针assert(ps-size);//确保里面有元素否则不执行for (int i 0; i ps-size - 1; i){ps-a[i] ps-a[i 1];//边界判断ps-a[size-2] ps-a[size-1]}ps-size--; }void SLInsert(SL* ps, int pos, SLDataType x) {assert(ps);//判断传入的是否是空指针assert(pos 0 pos ps-size);//确保不要瞎传一个pos的值进来SLCheckCapacity(ps);//判断是否需要扩容//pos之后的元素从后往前挪for (int i ps-size; i pos; i--){ps-a[i] ps-a[i - 1];//边界判断ps-a[pos1] ps-a[pos]}ps-a[pos] x;ps-size; }void SLErase(SL* ps, int pos) {assert(ps);//判断传入的是否是空指针assert(pos 0 pos ps-size);//确保不要瞎传一个pos的值进来assert(ps-size);//确保里面有元素否则不执行for (int i pos; i ps-size-1; i){ps-a[i] ps-a[i1];//边界判断:ps-a[i-2] ps-a[i-1];}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;//找不到返回一个无效的下标 } 注意除了查找函数和打印函数需要根据内容的不同修改其他函数基本上都可以通用
http://www.w-s-a.com/news/127483/

相关文章:

  • 网站制作后还能更改么wordpress 近期文章 代码
  • 做一个小网站需要多少钱wordpress集成paypal
  • 加强网站建设管理 及时更新自己设计装修的app
  • 集团网站设计案例网页制作网站开发
  • 怎么优化网站的单个关键词排名惠州品牌网站建设
  • 上海跨境电商网站制作wordpress弃用react
  • phpcms网站模版下载电商网站建设属于研发费用吗
  • 动画毕业设计代做网站高校门户网站建设需要多少钱
  • 网站内链设置wordpress前台特别慢
  • 杭州模板网站建设系统江苏省建设考试网站准考证打印
  • 国家建设执业资格注册中心网站企业手机网站建设机构
  • 内容管理系统做网站怎么做英文版的网站
  • 浙江省专业网站制作网站建设网站设计及内容策划
  • 浙江门户网站建设公司做网站上哪买空间
  • 郑州网站怎么推广贵阳市网站建设
  • 规范网站建设福州外贸网站建设推广
  • 平台电商网站开发传媒公司排行
  • 在哪给人做网站怎么样制作一个网页
  • 网站更改文章标题广西新闻
  • 专业做网站路桥寺院网站建设方案
  • 网站维护与优化教程广州做网站的网络公司排名
  • 网站做贷款许可证网站改版方案模板
  • 装饰公司怎么做网站嘉兴网站制作推广
  • 深圳兼职做网站涿州网站制作
  • 能找本地人做导游的网站app模板素材下载免费
  • 网站积分的作用网站开发需要看相关书籍
  • 建设银行总行网站alexa排名与什么有关系
  • 阿里云服务器发布网站收款网站怎么建设
  • 开发东莞网站制作公司做网站优化步骤
  • 网站版权信息的正确写法如何制作网络游戏