中国建设银行官方网站 认证网站运营和seo的区别
news/
2025/9/24 17:41:40/
文章来源:
中国建设银行官方网站 认证,网站运营和seo的区别,WordPress恶意扫描,河北省建设局网站大家想必都知道#xff0c;数组和链表的搜索操作的时间复杂度都是O(N)的#xff0c;在数据量大的时候是非常耗时的。对于数组来说#xff0c;我们可以先排序#xff0c;然后使用二分搜索#xff0c;就能够将时间复杂度降低到O(logN)#xff0c;但是有序数组的插入是一个O…大家想必都知道数组和链表的搜索操作的时间复杂度都是O(N)的在数据量大的时候是非常耗时的。对于数组来说我们可以先排序然后使用二分搜索就能够将时间复杂度降低到O(logN)但是有序数组的插入是一个O(N)级别的操作。而链表的插入性能相对优秀却不能使用二分搜索快速查询。那么是否有一种数据结构即能够像链表一样快速插入数据又支持类似于二分搜索这样的查询算法呢答案是肯定的。William Pugh教授在1990发表的论文《Skip Lists: A Probabilistic Alternative to Balanced Trees》中提出的跳表就是这样一种有趣的数据结构。 跳表的结构 跳表的核心思想是通过建立索引层来缩短链表的搜索路径以达到快速搜索的目的。 假设我们从链表中的每两个节点中提取出一个建立一级索引然后再从每两个一级索引中提取一个建立二级索引以此类推就可以得到如下图所示的结构其中绿色节点表示索引。 在William Pugh的论文中使用了数组加链表的组合来实现跳表就如上图所示每一列索引具有相同的key使用一个数组来表示。还可以使用纯链表的形式来实现跳表我觉得这种方式更有助于理解跳表的原理如下图所示。 跳表的搜索 跳表的搜索需要从高层索引开始向下逐层搜索每一层的搜索方式和普通链表是一样的当后继节点的关键字大于搜索关键字时结束本层的搜索进入下一层继续搜索。下图展示了跳表搜索关键字 22 的过程其中红色部分就是搜索的路径。 从上图可以很直观的看出跳表的搜索和二分搜索是一样的其时间复杂度也是O(logN)的我们不妨简单证明一下。 假设跳表中有N个数据节点关键字每m个低级索引或数据节点中提取出一个作为高级索引那么 一级索引的数量 二级索引的数量 三级索引的数量 以此类推第i级索引的数量 最高级索引的数量 所以索引的最大层级 每一层的搜索次数 所以跳表的搜索次数 因为m是一个常量因此跳表的搜索时间复杂度是O(logN)的 跳表的多层索引结构使它的搜索方式非常灵活且强大 比如我们可能有这样的需求如果key不存在我们需要知道这个key邻近的nearKey是什么这用跳表很容易实现 搜索比key小且最接近key的关键字lowerKey如上图所示后继节点大于等于key时直接返回当前节点即可搜索比key大且最接近key的关键字higherKey如上图所示后继节点大于key时直接返回后继节点即可跳表还可以很容易的搜索一个关键字区间[fromKey, toKey]这点和B树很类似先搜索fromKey然后向后遍历链表取出所有小于等于toKey的数据即可 跳表的插入 到现在为止本文描述的都是理想状态下的跳表事实上我们不会严格的为跳表的每m个低级索引建立高级索引因为这样做复杂而且低效。所以William Pugh在他的论文中采用一种随机算法来为每个新增的节点随机建立索引下面是我用Java实现的版本。 int randomLevel(int m, int maxLevel) {ThreadLocalRandom r ThreadLocalRandom.current();int level 1;while (r.nextInt(m) 0 level maxLevel)level;return level;
}
复制代码通过这种随机算法生成第i级索引的概率为 所以能够保证每一层索引的数量都接近于 这正好符合我们前面提到的索引层的性质。 Doug Lea大佬在Java的ConcurrentSkipListMap中使用了另外一种更加炫酷的随机算法的实现方式使用随机数末尾连续为1的位数作为索引的等级显然这种方式生成第i级索引的概率为 代码如下所示。 int rn ThreadLocalRandom.current().nextInt();
// 只有最高位和最低位都为0时才建立索引相当于为4个node建立一个索引
if ((rn 0x80000001) 0) {int level 1;// 建立索引的等级等于rn末尾连续为1的位数while (((rn 1) 1) ! 0)level;
}
复制代码通过随机函数生成一个随机的索引等级之后创建一个新的索引列并将每一层的新索引链接到它的前驱索引的后面如果生成的随机等级大于当前跳表的最大索引等级需要添加一层新的索引。如下图所示其中红色虚线箭头表示重新建立的链接。 跳表的删除 跳表的删除操作比较简单先查询删除的关键字如果在索引层匹配到了关键字就向下删除所有的索引和数据节点如果没有匹配到索引只需要删除数据节点即可。其中有一点需要注意的是在删除索引后需要检测一下如果当前层的HEAD索引的后继索引为NIL则表示这一层已经没有索引了需要删除这个索引层。如下图所示红色箭头表示重新建立的链接。 跳表的实现 跳表的实现相对AVL树、红黑树等平衡二叉树来说简单了很多William Pugh的论文《Skip Lists: A Probabilistic Alternative to Balanced Trees》中提供了使用数组加链表实现跳表的伪代码我写了一个Java版本的纯链表实现的跳表并上传到了我的GitHub上有兴趣的朋友可以看一下。如果你需要在开发中使用跳表的话java.util.concurrent.ConcurrentSkipListMap是一个强大的实现而且它还是线程安全的。 转载于:https://juejin.im/post/5cdc38236fb9a0322d04ac7b
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/916032.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!