在数组、链接的两种结构下关于增加、删除元素的操作。
数组
增加操作
增加位置
- 在中间的index处插入某个元素
-
- 需要将index之后的元素整体往后移,需要将size++
-
- 插入元素
- 在末尾插入元素
-
- 将size++,复制给最后一个值
以下是对数组各种操作的时间复杂度
操作 | 时间复杂度 |
---|---|
prepend | O(1) |
append | O(1) |
lookup | O(1) |
insert | O(n) |
delete | O(n) |
ps: 正常情况下数组的prepend操作的时间复杂度时O(n),但是可以进行特殊优化到O(1),采用的方式是申请稍大一些的内存空间,然后在数组最开始预留一部分空间,然后prepend的操作则是把头下标前移一个位置即可。
删除操作
删除目标元素,将target index后的元素整体往前移,对于已经删除的目标元素可触发垃圾回收机制,也可手动回收
数组的增加和删除操作在最坏的情况下需要移动n个元素,进行n次操作,时间复杂度是O(n)
链表
增加操作
若要在index 处插入元素,则需要将index-1(记做a)的next指针指向需要添加的元素,需要添加的元素的next指针指向a+1,时间复杂度是O(1)。
删除操作
将目标元素的前一个元素的next 指针指向目标元素的下一个元素,时间复杂度为O(1)
链表的每个元素必须用class 来定义,也就是node,里面有两个成员变量,一个是value ,一个是next 指针,指向下一个元素。
头指针为head ,尾指针为tail ,对于最后一个元素的指针指向空,如果是循环链表,则最后一个元素的指针指向第一个元素。
链表的优点:
进行元素的删除、增加操作时不需要大量挪动元素(群移操作以及复制元素),时间复杂度比较低
链表的缺点
访问元素比较麻烦。访问头结点或者尾结点比较方便,时间复杂度时O(1),但是如果要访问链表的中间元素,则需要一个结点一个结点往后找,时间复杂度就是线性阶O(n)
以下是链表操作的时间复杂度
操作 | 时间复杂度 |
---|---|
prepend | O(1) |
append | O(1) |
lookup | O(n) |
insert | O(1) |
delete | O(1) |
跳表(skip list)
特点
跳表只能用于元素有序的情况。跳表对标的是平衡树和二分查找,是一种插入/删除/搜索都是O(log n)的数据结构。
优势
原理简单、容易实现、方便扩展、效率更高。应用于redis
缺点
维护成本比较高。
如何提高查找效率,降低时间复杂度-》升维思想+空间换时间
-
添加第一级索引
以上添加第一级索引之后每次多走两步,那么怎么将提效更大化呢?增加第二级索引 -
增加第二级索引
以此类推,逐级增加索引
跳表查询的时间复杂度
n/2,n/4,n/8、第k级索引结点的个数是n/(2k)。假设索引有n级,最高级的索引有2个结点。n/(2h)=2,从而,h=log2(n)-1。故时间复杂度O(log n);空间复杂度是O(n)。