数据结构之跳表实现

增加了向前指针的链表叫作跳表。跳表全称叫做跳跃表,简称跳表。跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。-----来自百度百科

它的效率和红黑树以及 AVL 树不相上下,但实现起来比前面两个要简单得多、
跳表具有非常优秀的查找、插入、删除性能,并且是天然的动态数据结构。

其查询、插入、删除的时间复杂度均为O(logn)

跳表的引入
在这里插入图片描述
跳表的查找

跳表的查找需要从头开始查找;如果key小于或等于当层后面节点的key,则继续向后查找;如果key更大,则层数减1即向下查找,继续比较。最终一定会到第一层

在这里插入图片描述

/*
    * @param: [value]
    * @return: DataStructure.SkipList.SkipList.Node<V>
    * @author: Jerssy
    * @dateTime: 2021/4/9 16:56
    * @description:  查找value
    */
    private Node<V> searchNode(V value){
        Node<V> headNode=head;
        while (headNode!=null){

            
            while (headNode.next != null&&headNode.next.value.compareTo(value)<0)

                headNode = headNode.next;


            if (headNode.down==null){

                return headNode.next;
            }

            headNode=headNode.down;

        }

        return null;
    }

跳表的插入

跳表的插入首先需要确定插入的层级,层级一般使用随机函数来确定

 // 随机函数
    private int randomLevel(){
        int k = 1;

        while(random.nextInt()%2 == 0){
                k ++;
        }

        return Math.min(k, MAX_LEVEL);

    }

比如计算随机函数的值为2则1层和2层都需要插入该值,这里我们需要使用集合list保存每层插入的位置-- 从顶层开始,逐层找到每层需要插入的位置并保存位置,再插入;当然如果随机的层级数大于了当前跳表的层级数则需要更新层级数
在这里插入图片描述

 /*
     * @param: [value]
     * @return: void
     * @author: Jerssy
     * @dateTime: 2021/4/9 16:56
     * @description:插入value
     */
    private  void  insertNode( V value){

        Node<V> tempNode=head;
        List<Node<V>> insertedLeveList=new ArrayList<>();
        while (tempNode!=null){

            //将每个层级需要插入的位置保存到集合中
            if (tempNode.next==null||tempNode.next.value.compareTo(value)>0){
                insertedLeveList.add( tempNode);
                tempNode=tempNode.down;

            }
            else  {
                tempNode=tempNode.next;

            }
        }

        int level =  randomLevel();
       // 如果随机的层级数,大于head节点的层级数
        if (level > this.level) {
            Node<V> temp = null;
            Node<V> prev = head;
            // 索引的层级数
            while (this.level++ != level) {
                temp = new Node<>(null);
                temp.level=this.level;
                insertedLeveList.add(0, temp);
                temp.down = prev;
                prev = temp;
            }
            head = temp;
            //更新层级
            this.level = level;
        }

        Node<V> downNode=null; Node<V> vNode ;Node<V> newNode;
        for (int i = this.level-1;i>=this.level-level;i--) {//level的每一层都需要插入newNode
              newNode=new Node<>(value);
              vNode =insertedLeveList.get(i);
              newNode.next=vNode.next;
              newNode.level=vNode.level;
              vNode.next = newNode;
              newNode.down=downNode;
              downNode=newNode;
        }

    }

跳表的删除

删除则更简单,从跳表头部开始查询删除的位置,如果比删除值小则继续向后查找,反之向下查找删除的位置,如果找到则将当前指针断裂,当前位置的前一个指针连接后面一个即可
继续向下层寻找。因为每个层级的都需要删除
注意:
因为单链表中的删除操作需要拿到要删除结点的前驱结点,然后通过
指针操作完成删除。所以在查找要删除的结点的时候,一定要获取前驱结点。当然,如果我们用的是双向链表,就不需要考虑这个问题了。
在这里插入图片描述

 /*
     * @param: [value]
     * @return: void
     * @author: Jerssy
     * @dateTime: 2021/4/9 16:55
     * @description: 删除value
     */
    private  void  deleteNode(V value){

       if (value == null) {
           return;
       }

       Node<V> headNode=head;
       while (headNode != null) {

           //因为此跳表基于单链表,则需要找到删除的前驱进行指针的连接,如果是双链表的则直接定位到删除节点
           if (headNode.next!=null&&headNode.next.value.compareTo(value)==0){

              headNode.next=headNode.next.next;
              headNode=headNode.down;//继续向下层寻找--每个层级的都需要删除

          }
          else if (headNode.next!=null&&headNode.next.value.compareTo(value)<0) headNode=headNode.next;

          else  headNode=headNode.down;

       }

    }

跳表模拟
跳表本身就是轻量级的数据结构,直接使用单链表进行模拟,当前也可以使用数组来模拟这里不再实现

package DataStructure.SkipList;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author: Jerssy
 * @create: 2021-04-08 19:55
 * @version: V1.0
 * @slogan: 业精于勤, 荒于嬉;行成于思,毁于随。
 * @description: 跳表实现
 */
public class SkipList<V extends Comparable<V>> {

    private  Node<V> head=new Node<>(null);

    public int level;

    public  static  final int MAX_LEVEL=16;

    ThreadLocalRandom random = ThreadLocalRandom.current();

   public SkipList(int level){
       this.level = level;
       initList();
   }

   public SkipList(){
       this(MAX_LEVEL);
   }

   /*
    * @param: []
    * @return: void
    * @author: Jerssy
    * @dateTime: 2021/4/9 16:56
    * @description: 初始化
    */
   private void initList() {
       int i = level;
       Node<V> temp = null;
       Node<V> prev = null;
       //从底部节点开始创建链表每个层级的头节点
       while (i-- != 0) {
           temp = new Node<>(null);
           temp.level= level-i;
           temp.down = prev;
           prev = temp;
       }
       head = temp;//最上层头节点
   }

   /*
    * @param: [value]
    * @return: DataStructure.SkipList.SkipList.Node<V>
    * @author: Jerssy
    * @dateTime: 2021/4/9 16:56
    * @description:  查找value
    */
    private Node<V> searchNode(V value){
        Node<V> headNode=head;
        while (headNode!=null){


            while (headNode.next != null&&headNode.next.value.compareTo(value)<0)

                headNode = headNode.next;


            if (headNode.down==null){

                return headNode.next;
            }

            headNode=headNode.down;

        }

        return null;
    }

    // 随机函数
    private int randomLevel(){
        int k = 1;

        while(random.nextInt()%2 == 0){
                k ++;
        }

        return Math.min(k, MAX_LEVEL);

    }


    /*
     * @param: [value]
     * @return: void
     * @author: Jerssy
     * @dateTime: 2021/4/9 16:56
     * @description:插入value
     */
    private  void  insertNode( V value){

        Node<V> tempNode=head;
        List<Node<V>> insertedLeveList=new ArrayList<>();
        while (tempNode!=null){

            //将每个层级需要插入的位置保存到集合中
            if (tempNode.next==null||tempNode.next.value.compareTo(value)>0){
                insertedLeveList.add( tempNode);
                tempNode=tempNode.down;

            }
            else  {
                tempNode=tempNode.next;

            }
        }

        int level =  randomLevel();
       // 如果随机的层级数,大于head节点的层级数
        if (level > this.level) {
            Node<V> temp = null;
            Node<V> prev = head;
            // 索引的层级数
            while (this.level++ != level) {
                temp = new Node<>(null);
                temp.level=this.level;
                insertedLeveList.add(0, temp);
                temp.down = prev;
                prev = temp;
            }
            head = temp;
            //更新层级
            this.level = level;
        }

        Node<V> downNode=null; Node<V> vNode ;Node<V> newNode;
        for (int i = this.level-1;i>=this.level-level;i--) {//level的每一层都需要插入newNode
              newNode=new Node<>(value);
              vNode =insertedLeveList.get(i);
              newNode.next=vNode.next;
              newNode.level=vNode.level;
              vNode.next = newNode;
              newNode.down=downNode;
              downNode=newNode;
        }

    }


    /*
     * @param: [value]
     * @return: void
     * @author: Jerssy
     * @dateTime: 2021/4/9 16:55
     * @description: 删除value
     */
    private  void  deleteNode(V value){

       if (value == null) {
           return;
       }

       Node<V> headNode=head;
       while (headNode != null) {

           //因为此跳表基于单链表,则需要找到删除的前一个进行指针的连接,如果是双链表的则直接定位到删除节点
           if (headNode.next!=null&&headNode.next.value.compareTo(value)==0){

              headNode.next=headNode.next.next;
              headNode=headNode.down;//继续向下层寻找--每个层级的都需要删除

          }
          else if (headNode.next!=null&&headNode.next.value.compareTo(value)<0) headNode=headNode.next;

          else  headNode=headNode.down;

       }

    }


    // 显示 表中的结点
    public void printNode(){
        Node<V> p = head;

        while (p.down!=null){
            p=p.down;
        }

        while(p.next!= null){
            p = p.next;
            System.out.println("打印第一层数据:"+p+ " ");
        }

    }


    static class  Node<V extends Comparable<V>>{

         V value;
         Node<V> next;
         Node<V> down;
         int level;
         public  Node(V value){

             this.value = value;

         }

        @Override
        public String toString() {
            return "Node{" +
                    "value=" + value +
                    ", level=" + level +
                    '}';
        }
    }


    public static void main(String[] args) {
        SkipList<Integer> skipList=new SkipList<>(4);
        skipList.insertNode(2);
        skipList.insertNode(4);
        skipList.insertNode(7);
        skipList.insertNode(1);
        skipList.insertNode(0);
        skipList.insertNode(12);
        skipList.insertNode(3);
        skipList.insertNode(5);
        skipList.printNode();
        System.out.println("************删除5**********");
        skipList.deleteNode(5);
        skipList.printNode();
        System.out.println("************查找2**********");
        System.out.println(skipList.searchNode(2));
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值