《数据结构》第2章线性表的学习总结
《数据结构》第2章-线性表
我刚刚开始第二章学习时候,对线性表的了解特别模糊,只是对数组(线性表的推广,它的数据元素是一个线性表)比较熟悉,所以就开始对这一章内容的学习和探索。通过老师由浅及深的引导,总算在学习中清楚了许多。
其中包括两大内容:线性表的顺序表示和实现、线性表的链式表示和实现。
一、顺序表
顺序表≠数组,数组只是其中一部分,在这里老师谈到栈和堆,我感兴趣就记了下来,作为备忘。
一般定义一个数组是在main函数里面,是一个局部变量,局部变量在物理空间上被分配到栈中,而栈空间小(1M-2M),以最大计算 2M = 2*1024*1024bytes
int类型为4个字节,这样数组最多也就50万个数据左右,如果数组申请空间太大,就会出现栈溢出,程序崩溃。
那如果真需要开一个超大数组,如何解决这个情况呢?
这时就要使用“堆”的空间了,对空间比栈大得多,一个100万个数据的数组都可以做到,我们有 2个方法,一是定义为全局变量,二是动态申请数组空间
#include<iostream> using namespace std; int main() { int *a; a=new int[所需数组长度]; ... delete a; return 0; }
这两种分配物理内存都在“堆”,所以可以开超大数组。(相关博客链接:https://blog.csdn.net/github_30605157/article/details/57084216)
顺序表能够实现随机存取,在取值的时间复杂度都是O(1),查找(时间耗费在比较上)、插入删除(时间耗费在移动元素)是O(n)。
二、链式表(线性链表/单链表)
我觉得链式表的学习比顺序表难,主要就是在各个指针的指向,它的每个结点包含有下个结点的指针域,一个链表一般都有头指针、头结点、首元结点,这三个开始我不太明白其作用,很容易混淆,后来观察几个例题,画一下图,才慢慢理清思路。
从链式表基本操作开始,我就感觉怎么这么抽象,实际操作起来好像不是很简单,它的存储结构是链式的,通过指针把表串起来,不跟顺序结构一样是一片连续的区域,逻辑很清晰。所以有时候容易短路,不知道那行代码的意思。
单链表的取值、查找、插入、删除的时间复杂度都是O(n),但在插入删除方面优势明显比顺序表大,只需要将指针指向调整一下,不需要移动元素,就能实现。
在“单链表的创建和遍历”那道题中,自己着手进行实际操作,开始程序报错许多,然后一步步进行修改,直到答案正确,这个过程让我理解更深一步。
另一道题是实践1_求集合交集
给定两个整数集合(每个集合中没有重复元素),集合元素个数<=100000,求两集合交集,并按非降序输出。
我的第一个版本是用for循环,里面再来一个for循环,在dev上面运行,没有错误,感觉这题还行,但PTA提交之后没通过最后一个测试点100000个数据时,运行超时了,问了老师,原来我那个程序时间复杂度是O(100000*100000),这样肯定超时啊,这么大的数量级。
所以还需优化程序的算法,改为O(100000+100000),好算法的重要性就在这里了。
第一次尝试了if语句,试图一个对应一个比较,因为还要循环比较,我就想到goto结构,经过一番验证,goto语句确实破坏了结构化程序设计,程序运行是很不稳定,有时候错,有时对,正式宣告第一次尝试失败。主要实现部分如下:
loop:if(i<m&&j<n) { if(a[i]<b[j]) { i++;goto loop; } else if(a[i]>b[j]) { j++;goto loop; } else if(a[i]==b[i]) { c[x++]=a[i]; t++; i++; j++;goto loop; } }
第二次用了while循环,解决了循环问题,内部再用if进行比较,好像可以了,但在运行时,我尝试几个样例,还是输出有点问题,之后开始寻找错误,发现是在if那里有问题,修改之后再次测试,终于输出都无误了,提交正确,总算成功了。
while(i<m&&j<n) { if(a[i]<b[j]) { i++; } else if(a[i]>b[j]) { j++; } else { c[t]=a[i]; t++; i++;j++; } }
对一些问题的解决,我还需学习更多方法,理论上的东西还是要通过实践才能够吸收,不对之处,老师、同学多多指教哦!
在错误中寻找答案,学的东西会更多,我觉得现在对这些知识只是简单的理解,也就是刚刚入门,还需以后多加学习,多打代码,收获才更多。