线性表很好理解,就是由一组能数过来的元素组成的序列,咱们具象一点可看成以下的图片
一个普通的办公工位,可以看成一个线性表,它有这些特点:
1.有序性:我们把每个工位看成每个元素,这些个工位都是有序排列的,咱给这个工位桌子上贴个编号,以后方便找到我想要的工位。(以后每个“工位”都代指“元素”)
2.一对一关系:咱们说这些工位的员工不可能每天不交流,都得认识一下自己的左邻右舍,所以说大部分员工都能和自己旁边人(左右两边)唠嗑,左边我们可以叫前一个,右边可以叫后一个,继而就有了前驱元素和后驱元素。当然了两边的工位肯定是要么没有左邻,要么没有右舍。还有一件事,这个咱们的顺序关系也就是编号不是由咱们自己决定的,这东西得根据这个整体工位也就是线性表里面每个工位关系来确定。
3.元素的唯一性和顺序
很好理解,每个位置都明确编号,都是固定的,有顺序的
4.支持基本操作
咱们通常说增删查改,其实基本操作也无非就是
访问:我要知道某个工位
插入:我要在某个地方加一个工位
删除:我要去掉某个位置的工位
查找:我要定位某个工位,或者看它存不存在
到这里特点还没完,我想补充一个事,就是咱们这个线性表分为顺序表和链表
顺序表:(实现方式为数组,数组也就可以看成一个一个台阶,台阶放下很多东西)
链表:(实现方式为指针,指针是数组的地址,也就是说它给每个台阶记上一个位置,比如用绳子打结,就像古代结绳记事,把它像链子一样连起来)
咱们稍微对比一下两者:
特性 | 顺序表(Array) | 链表(LinkedList) |
---|---|---|
内存分配 | 它的空间是给好的,就像台阶是连续有固定空间的 | 动态分配内存(就是说你可以灵活地给绳子打结任何位置都行,当然结点也不一定是挨着的,也就是节点不一定连续 |
随机访问 | (优势)支持,通过下标直接访问,时间复杂度O(1)(解释一下,意思就是你可以你要到哪个台阶直接跨上去就行,别说自己迈不开步子) | 不支持,需要从头节点遍历,时间复杂度O(n)(意思就是绳子打结你得从头开始找节点,不然会乱) |
插入和删除 | 可能需要移动大量元素以保持连续性,时间复杂度O(n)(好理解,拆一个台阶或者加一个台阶势必要影响整个阶梯) | (优势)只需修改指针,时间复杂度通常为O(1)(不考虑查找时间)(就是你可以随意添加,也可以随意删除) |
空间利用率 | (优势)较高,没有额外的指针开销(直接在台阶上放东西就行,别的东西不占空间) | 较低,每个节点需要额外的空间存储指针或引用(得要把绳子及其节点放在台阶上,占空间) |
扩容成本 | 可能需要扩容并复制旧元素,成本较高(加个台阶的开销成本大) | (优势)动态分配内存,无需整体扩容 |
大小限制 | 预先确定,可通过扩容增加但成本较高(毋庸置疑) | (优势)动态变化,大小灵活(那肯定的,给绳子打结的大小不固定) |
实现复杂度 | (优势)相对较低,无需处理复杂的指针操作 | 相对较高,需要处理指针或引用的分配和释放 |
适用场景 | 数据量不大,频繁访问元素,但插入删除操作较少的场景 | 数据量较大,插入删除操作频繁,对随机访问要求不高的场景 |