首页 > 其他分享 >跳跃表

跳跃表

时间:2024-09-07 15:37:58浏览次数:5  
标签:right SkipNode key team 跳跃 null 节点

概述

跳跃表(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();
        }
    }
}

标签:right,SkipNode,key,team,跳跃,null,节点
From: https://www.cnblogs.com/Yee-Q/p/18401654

相关文章

  • 【Unity踩坑记录】使用Rigidbody模拟跳跃时,刚体会突然上升
    最初的写法privatevoidFixedUpdate(){if(!isGrounded){return;}floatrawHorizontal=Input.GetAxis("Horizontal");floatrawVertical=Input.GetAxis("Vertical");Vector3localDirection=new(rawHorizon......
  • 力扣热题100_贪心算法_45_跳跃游戏
    文章目录题目链接解题思路解题代码题目链接45.跳跃游戏II给定一个长度为n的0索引整数数组nums。初始位置为nums[0]。每个元素nums[i]表示从索引i向前跳转的最大长度。换句话说,如果你在nums[i]处,你可以跳转到任意nums[i+j]处:0<=j<=nums[i]......
  • 代码随想录算法day24 | 贪心算法part02 | 122.买卖股票的最佳时机II,55. 跳跃游戏,45.跳
    122.买卖股票的最佳时机II本题解法很巧妙,本题大家可以先自己思考一下然后再看题解,会有惊喜!力扣题目链接(opensnewwindow)给定一个数组,它的第 i个元素是一支给定股票第i天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次......
  • 力扣热题100_贪心算法_55_跳跃游戏
    文章目录题目链接解题思路解题代码题目链接55.跳跃游戏给你一个非负整数数组nums,你最初位于数组的第一个下标。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标,如果可以,返回true;否则,返回false。示例1:输入:nums=[......
  • 力扣面试经典算法150题:跳跃游戏
    跳跃游戏今天的题目是力扣面试经典150题中的数组的中等难度题:跳跃游戏。题目链接:https://leetcode.cn/problems/jump-game/description/?envType=study-plan-v2&envId=top-interview-150题目描述给定一个非负整数数组nums,你最初位于数组的第一个下标,即nums[0]。数......
  • Leetcode JAVA刷刷站(55)跳跃游戏
    一、题目概述二、思路方向    在Java中,为了解决这个问题,你可以采用贪心算法的思想。贪心算法在这里的应用主要体现在,每一步都尽可能跳得远,以此来判断是否能够到达数组的最后一个下标。    算法的思路是,遍历数组nums,用一个变量farthest来记录遍历过程中能够......
  • NP2011-SW-22-VLAN跳跃攻击_VACL(VLAN-MAP)
    vlan跳跃攻击打双层标记配置端口为access端口trunk模式最好是on关闭trunknegotiation本证vlan使用不用的vlan号配置trunk链路要设置允许哪些vlan通过交换机的aclipaclmacaclvlanacl配置access-list100permitip10.1.9.00.0.0.255anymacaccess-listextende......
  • leetcode面试经典150题- 45. 跳跃游戏 II
    https://leetcode.cn/problems/jump-game-ii/description/?envType=study-plan-v2&envId=top-interview-150gopackageleetcode150import"testing"funcTestJump2(t*testing.T){nums:=[]int{5,9,3,2,1,0,2,3,3,1,0,0}res:=j......
  • 代码随想录算法训练营第二十八天 | 122.买卖股票的最佳时机II , 55. 跳跃游戏 , 45.跳跃
    目录122.买卖股票的最佳时机II 思路方法一:贪心方法二:动态规划55.跳跃游戏思路方法一:使用while循环方法二:使用for循环45.跳跃游戏II 思路方法一方法二方法一:贪心方法一方法二:贪心方法二 方法三:贪心方法三心得体会1005.K次取反后最大化的数组和思路方法......
  • 代码随想录day28 || 122 买卖最佳时机2,55 跳跃游戏,45 跳跃游戏2,1005 k次取反最大数组
    122买卖股票最佳时机2funcmaxProfit(prices[]int)int{ //思路,因为支持同一天买入卖出,所以利润最大应该是所有正利润的加总结果 varsumint fori:=1;i<len(prices);i++{ ifprices[i]-prices[i-1]>0{ sum+=prices[i]-prices[i-1] } } returns......