跳跃表

概述

跳跃表(SkipList)是链表加多级索引组成的数据结构。链表的数据结构的查询复条度是 O(N)。为了提高查询效率,可以在链表上加多级索引来实现快速查询。跳跃表不仅能提高搜索性能。也能提高插入和删除操作的性能。索引的层数也叫作跳跃表的高度

跳跃表

查找

在跳跃表的结构中会首先从顶层开始查找,当顶层不存在时向下一层查找,重复此查找过程直到跳跃到原始链表。如图所示,在 [1,3,4,10,1,20] 的链表中查找 10,首先从二级索引中查找,由于 1 和 4 都比 10 小,因此接着在一级索引查找,由于 10 大于 4 小于 11,因此接着向下查找,原始链表中 4 的下一个节点 10 便是需要查找的数据

跳跃表

插入

首先按照查找流程找到待插入元素的前驱和后继,然后按照随机算法生成一个高度值 height,最后将待插入的节点按照高度值生成一个垂直节点(这个节点的层数正好等于高度值),并将其插人跳跃表的多条链表中。如果高度值 heigh 大于插入前跳跃表的高度,那么跳跃表的高度被提升为 height,同时需要更新头节点和尾节点的指针指向。如果 height 小于或等于跳跃表的高度,那么需要更新待插入元素的前驱和后继的指针指向。在 [1,3,4.10,11,20] 的跳跃表中插入 18 的过程如图所示

跳跃表

删除

在删除节点时首先需要找到待删除的节点在每一层的前驱和后继,接着将其前驱节点的后继替换为待删除的节点的后继,删除 4 的过程如图所示

跳跃表

代码实现

import java.util.Random; import java.util.Stack;  class SkipNode<T> {      int key;     T value;     SkipNode right,down;//左右上下四个方向的指针     public SkipNode (int key,T value) {         this.key=key;         this.value=value;     }  }  public class SkipList <T> {      SkipNode headNode;//头节点,入口     int highLevel;//层数     Random random;// 用于投掷硬币     final int MAX_LEVEL = 32;//最大的层          SkipList(){         random=new Random();         headNode=new SkipNode(Integer.MIN_VALUE,null);         highLevel=0;     }          public SkipNode search(int key) {         SkipNode team=headNode;         while (team!=null) {             if(team.key==key){                 return  team;             }             else if(team.right==null) { //右侧没有了,只能下降                 team=team.down;             }             else if(team.right.key>key) { //需要下降去寻找                 team=team.down;             }             else { //右侧比较小向右                 team=team.right;             }         }         return null;     }      public void delete(int key) { //删除不需要考虑层数         SkipNode team=headNode;         while (team!=null) {             if (team.right == null) { //右侧没有了,说明这一层找到,没有只能下降                 team=team.down;             }             else if(team.right.key==key) { //找到节点,右侧即为待删除节点                 team.right=team.right.right;//删除右侧节点                 team=team.down;//向下继续查找删除             }             else if(team.right.key>key) { //右侧已经不可能了,向下                 team=team.down;             }             else { //节点还在右侧                 team=team.right;             }         }     }          public void add(SkipNode node) {              int key=node.key;         SkipNode findNode=search(key);         if(findNode!=null) { //如果存在这个key的节点                      findNode.value=node.value;             return;         }          Stack<SkipNode>stack=new Stack<SkipNode>();//存储向下的节点,这些节点可能在右侧插入节点         SkipNode team=headNode;//查找待插入的节点   找到最底层的哪个节点。         while (team!=null) {//进行查找操作             if(team.right==null) { //右侧没有了,只能下降                 stack.add(team);//将曾经向下的节点记录一下                 team=team.down;             }             else if(team.right.key>key) { //需要下降去寻找                 stack.add(team);//将曾经向下的节点记录一下                 team=team.down;             }             else { //向右                 team=team.right;             }         }          int level=1;//当前层数,从第一层添加(第一层必须添加,先添加再判断)         SkipNode downNode=null;//保持前驱节点(即down的指向,初始为null)         while (!stack.isEmpty()) {             //在该层插入node             team=stack.pop();//抛出待插入的左侧节点             SkipNode nodeTeam=new SkipNode(node.key, node.value);//节点需要重新创建             nodeTeam.down=downNode;//处理竖方向             downNode=nodeTeam;//标记新的节点下次使用             if(team.right==null) {//右侧为null 说明插入在末尾                 team.right=nodeTeam;             }             //水平方向处理             else {//右侧还有节点,插入在两者之间                 nodeTeam.right=team.right;                 team.right=nodeTeam;             }             //考虑是否需要向上             if(level>MAX_LEVEL)//已经到达最高级的节点啦                 break;             double num=random.nextDouble();//[0-1]随机数             if(num>0.5)//运气不好结束                 break;             level++;             if(level>highLevel) { //比当前最大高度要高但是依然在允许范围内 需要改变head节点                 highLevel=level;                 //需要创建一个新的节点                 SkipNode highHeadNode=new SkipNode(Integer.MIN_VALUE, null);                 highHeadNode.down=headNode;                 headNode=highHeadNode;//改变head                 stack.add(headNode);//下次抛出head             }         }     }          public void printList() {         SkipNode teamNode=headNode;         int index=1;         SkipNode last=teamNode;         while (last.down!=null){             last=last.down;         }         while (teamNode!=null) {             SkipNode enumNode=teamNode.right;             SkipNode enumLast=last.right;             System.out.printf("%-8s","head->");             while (enumLast!=null&&enumNode!=null) {                 if(enumLast.key==enumNode.key) {                     System.out.printf("%-5s",enumLast.key+"->");                     enumLast=enumLast.right;                     enumNode=enumNode.right;                 }                 else {                     enumLast=enumLast.right;                     System.out.printf("%-5s","");                 }             }             teamNode=teamNode.down;             index++;             System.out.println();         }     } } 

发表评论

相关文章