实验一顺序表的基本操作的实现(必做,设计性实验)
- 实验目的
熟悉将算法转换成程序代码的过程,了解顺序表的逻辑结构特性,熟练掌握顺序表存储结构的C语言描述方法。熟练掌握顺序表的基本操作:查找、插入、删除、合并等,掌握顺序表的随机存取特性。
- 实验内容(选其中之一书写实验报告)
(1)在非递减有序的顺序表中插入一个元素x,保持顺序表有序性。
(2)顺序表元素的逆置
(3)两个(有序或无序)顺序表的合并
要求用静态分配的一维数组和动态分配的一维数组来完成实验题目。分析静态分配的一维数组和动态分配的一维数组在顺序表基本操作实现上的共同点和区别。
对顺序表插入的算法,要求用两种方法实现:其一:自己编写实现函数;其二:调用顺序表基本操作ListInsert(SqList &L,int i,ElemType x),比较使用自己编写的插入函数和调用顺序表基本操作的函数两种实现方法之间的优缺点。对所编写的算法进行时间复杂度分析。
- 问题描述
(说明你选做的题目及要求)
题目:顺序表元素的逆置
题目要求:分别使用静态分配的一维数组和动态分配的一维数组来完成有序顺序表的合并和无序顺序表的合并。并分析静态分配的一维数组和动态分配的一维数组在顺序表基本操作实现上的共同点和区别。
- 数据结构定义
(说明你算法中用到的数据结构、数据类型的定义)
数据结构:用到的数据结构是线性表,选择的存储结构是顺序存储结构
数据类型:*elem,length,listsize整型变量分别存储空间基地址,长度,当前分配存储容量,线性表类型名定义为Sqlist
typedef struct
{
int *elem; //存储空间的基地址
int length; //当前长度
int listsize; //当前分配的存储容量
}Sqlist;
- 算法思想及算法设计
(先文字说明算法的思想,然后给出类C语言算法)
(1)算法的思想
①顺序表的逆置就是将表中元素逆序,首先创建一个顺序表并输入元素个数length,也就是表的长度,并对顺序表中的元素进行初始化;②然后将第i个元素与第length-i-1个元素互换,先将第length-1-i个元素(后者)元素赋值给中间变量temp,再将第i个元素(前者元素)赋值给后者元素,再将temp赋值给前者元素,完成前者后者元素的互换,通过for循环语句循环length/2次完成整个表中元素的逆序;③最后将逆置过的顺序表输出。
(2)类C语言算法
Status TransList(Sqlist *l) {
InitList(&l); scanf(&length); //构造顺序表并确定其长度
CreatList(&l,length); PrintList(&l); //初始化顺序表并遍历输出
for(i=0;i<(l->length)/2;i++){ //将顺序表逆置
l->elem[i]<->l->elem[l->length-1-i];
}
PrintList(&l); //将逆置后的线性表遍历输出
}
- 实验代码
(即C语言程序)
详见电子版
- 算法测试结果
(说明测试数据,粘贴实验结果图)
(1)动态分配的一维数组:
分别输入奇数个和偶数个数据,{1 2 3}和{1 2 3 4
(2)静态分配的一维数据
- 分析与总结
(1)算法复杂度分析及优、缺点分析
(说明你编写算法的复杂度,算法的优点和缺点有哪些)
①动态存储的一维数组:
InitList(Sqlist *l)算法时间复杂度为O(1)
PrintList(Sqlist *l), CreatList(Sqlist *l,int length), TransList(Sqlist *l)算法时间复杂度为O(n)
优点:动态存储的一维数组,可以动态地增加或缩小数组的大小,从而根据实际需要占用内存空间。相对于静态数组,只需在必要时才会重新分配内存,避免了空间浪费和数据被丢失的风险,动态开辟空间,使用相对灵活。
缺点:但如果不小心预估了错误的数组大小,或者出现了多次扩容和收缩操作,可能导致频繁地重新分配和复制内存,这会带来额外的时间开销和性能问题。
②静态存储的一维数组
InitList(Sqlist *l)算法时间复杂度为O(1)
PrintList(Sqlist *l),CreatList(Sqlist *l,int length), TransList(Sqlist *l)算法时间复杂度为O(n)
优点:静态存储的一维数组创建空间时为静态开辟,不用malloc函数,代码相对简单(一点点),不存在内存泄露问题。
缺点:但静态顺序表的数据存储的空间大小在一开始初始化的时候就定好了,后面运行后不能随意增加或缩小,当你不清楚所需存储数据多少的时候,如果给太大就会浪费、太小又不能够存储完。
(2)实验总结
(说明你怎么解决实验中遇到的问题,有什么收获)
问题:如何提高逆置算法的效率并且需要尽量少的额外的辅助空间
解决办法:在对顺序表进行逆置操作时,最初的思路是将顺序表的元素从最后一个元素开始向前遍历并依次赋值给另一个顺序表的第一个元素开始往后的元素,直到第一个顺序表的元素全部赋给第二个顺序表,这样第二个顺序表就是第一个顺序表的逆置,但这样的方法需要较多的辅助空间,循环次数也比较多。后对算法改进,借助辅助变量temp让顺序表的第i个元素与第length-i-1个元素互换,通过for循环语句循环length/2次完成整个表中元素的逆置,改进后不仅需要的辅助空间少了,循环次数也大大减少,效率更高了。
收获:
①理解数组的静态分配和动态分配:静态分配的数组是在编译时确定大小,并且存储空间在程序运行时分配的;而动态分配的数组是在运行时根据需要动态分配内存空间。
②掌握数组元素的逆置算法:通过实践,了解如何使用一维数组的索引进行元素逆置操作。这是一种常见的数组操作,对后续算法的设计和分析具有重要意义。
③提高对指针的理解和应用能力:动态分配数组需要使用指针来管理内存空间的分配和释放。通过本次实验,可以巩固和加深对指针的理解,并学会正确地使用指针进行动态数组的相关操作。
④加深对顺序表概念的理解:顺序表是一种线性表的实现方式,它的特点是元素在物理地址上连续存储。通过逆置实验,可以更好地理解顺序表的概念,并体会顺序表在实际应用中的优势和局限性。
⑤培养解决问题的思维能力:在实验中,可能会遇到一些问题和困难,需要进行思考和解决。通过自主探索和实践,可以培养解决问题的能力和思维方式,提高学习和工作中的自主性和创造性。
⑥强化编程技巧和调试能力:实验过程中可能会遇到一些编程错误或逻辑问题,需要不断调试和改进代码。通过实践,可以提高编程技巧和调试能力,增加对程序运行过程的理解和把握。
总之,通过对顺序表元素的逆序操作,更加了解了线性表的存储结构和数据类型,明白了静态和动态存储的一维数组的区别和优缺点,懂得了如何定义顺序表,更加熟练的掌握了顺序表的构造、初始化、遍历的操作,对表内元素进行基本的操作有了更加深刻的理解,培养解决问题的能力,并强化编程技巧和调试能力。这些收获将对日后的学习和工作有着积极的影响。