这是我参与「第四届青训营 」笔记创作活动的第[6]天
跳表
- 假如有一个单链表,如果是想要查找某个数据,那么只能从头遍历到尾,因为链表不支持随机访问,查找的效率就很低,时间复杂度也是为O(n)。
- 如果是想要提高查找的效率,那么可以在建立一个一级索引
-
1 -->> 4 -->> 7 -->> 9 -->> 13 -->> 16 -->> 19 -->> 23 | | | | | | | | | | | | | | | | 1 -> 3 -> 4 -> 5 -> 7 -> 8 -> 9 -> 10 -> 13 -> 14 -> 16 -> 17 -> 19 -> 21 -> 23 -> 24 -> 25 - 当查找5的时候,从索引层出发,如果当下一个节点的索引的值大于查找的值时候,那么可以去下一层查找,直到找到值。
- 当查找21的时候,只需要遍历8个节点,原来需要遍历14个节点。遍历的节点个数减少了,那么查找的效率也高了起来。
-
- 可以建立一个一级索引,那么肯定是可以建立一个二级的索引,当建立了一个二级索引时:
-
1 ---->>>> 7 ---->>>> 13 ---->>>> 19 | | | | | | | | 1 -->> 4 -->> 7 -->> 9 -->> 13 -->> 16 -->> 19 -->> 23 | | | | | | | | | | | | | | | | 1 -> 3 -> 4 -> 5 -> 7 -> 8 -> 9 -> 10 -> 13 -> 14 -> 16 -> 17 -> 19 -> 21 -> 23 -> 24 -> 25 - 再次查找21的时候,需要遍历5个节点,而一级索引需要8个节点,单链表的形式而需要14个节点,如果数据量更大,那么查找的效率会快很多,提升也是很明显的。
-
跳表的时间复杂度 & 空间复杂度
- 时间复杂度
- 假如链表中有n个节点,那么一级索引的节点个个数为n/2,二级索引的节点个数为n/4,三级所以的节点个数为n/8,那么第m级索引的节点个数为/( )。
- 假如最高级的索引有2个节点,那么可以得到/( )=2,从而求得m=n-1,包含了原始链表这一层的话,整个跳表的高度就是n层。
- 在每一层都需要遍历k个节点,那么查找一个数据的时间复杂度为O(m*)。
- 需要查找一个数据x时,在第k级索引中,遍历到了y节点之后,发现x大于y,小于后面的节点z,所以需要下降到第k-1级索引,在第k-1级索引中,y和z之间只有3个节点,所以每一级都最多遍历3个节点。
- 那么就为O(3*),所以跳表查询任意数据的时间复杂度就是O()。这个时间和二分查找一样,基于单链表实现了二分查找。
- 从单链表的增加O(n) 删除O(n) 修改O(n) 查找O(n)的时间复杂度 ==>> 到跳表的增加O() 删除O() 修改O() 查找O()的时间复杂度
- 空间复杂度
- 链表中的n个节点,一级索引的节点个数为n/2,二级索引的节点个数为n/4,三级索引的节点个数为n/8。
- 那么就是n/2 + n/4 + n/8.... + 8 + 4 + 2=n-2,所以跳表的空间复杂度是O(n)。
维护跳表
- 当一直在跳表两个节点中执行插入操作时,跳表还会退化成单链表,那么需要维护索引与原始链表大小之间的平衡。
- 当链表中的节点多了,索引节点就增加一些,避免退化成单链表