跳表(Java 实现)

public abstract class SkipListUtil {

    /**
     * 按照规则生成随机层数,层数越大,概率越低
     *
     * @return
     */
    public static int generateRandomLevel() {
        int result = SkipListConfig.MIN_LEVEL;
        Random random = new Random();
        while (random.nextInt(SkipListConfig.MAX_LEVEL) < SkipListConfig.MAX_LEVEL * SkipListConfig.P && result < SkipListConfig.MAX_LEVEL) {
            result++;
        }
        return result;
    }

    /**
     * 计算跳跃表的平均高度
     *
     * @param skipList
     * @param <T>
     * @return
     */
    public static <T> double computeAvgLevel(SkipList<T> skipList) {
        double result = 0;
        for (SkipListNode<T> skipListNode : skipList) {
            result += skipListNode.getLevels().length;
        }
        return result / skipList.length;
    }
}

public abstract class SkipListConfig {
    /**
     * 每一层节点提升为上层节点的概率,概率越大,层数越高
     */
    public static final double P = 0.5;
    public static final int MAX_LEVEL = 64;
    public static final int MIN_LEVEL = 1;
}
/**
 * 跳表节点
 */
@Data
@Accessors(chain = true)
@EqualsAndHashCode
public class SkipListNode<T> implements Comparable<SkipListNode<T>> {
    /**
     * 存储数据
     */
    private T element;

    /**
     * 排序的分值,约定0为最小分数
     */
    private double score;

    /**
     * 后退指针(指向前一个节点)
     * <p>
     * 头结点指向null
     */
    private SkipListNode<T> prev;

    /**
     * 每个节点的数组长度不一样,随机生成一个层级
     * <p>
     * 例如,层级为8,代表该节点出现在8个层级上
     * <p>
     * 值越大,出现概率越低
     */
    private SkipListLevel<T>[] levels;

    @Override
    public int compareTo(SkipListNode<T> other) {
        return Double.compare(this.score, other.score);
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class SkipListLevel<T> {
        /**
         * 同一层的下一个结点
         */
        private SkipListNode<T> next;

        /**
         * 当前结点与同层的next节点之间的距离
         */
        private int span;
    }


    public SkipListNode(int levelNum) {
        this.element = null;
        this.score = 0;
        prev = null;
        levels = new SkipListLevel[levelNum];
        for (int i = 0; i < levels.length; i++) {
            levels[i] = new SkipListLevel<>(null, 0);
        }
    }

    public SkipListNode() {
        this.element = null;
        score = 0;
        prev = null;
        levels = new SkipListLevel[SkipListUtil.generateRandomLevel()];
        for (int i = 0; i < levels.length; i++) {
            levels[i] = new SkipListLevel<>(null, 0);
        }
    }

    @Override
    public String toString() {
        return "SkipListNode{" +
                "element=" + element +
                ", score=" + score +
                ", prev=" + prev +
                ", levels=" + levels.length +
                '}';
    }
}
public class SkipList<T> implements Iterable<SkipListNode<T>> {
    /**
     * 头结点
     */
    SkipListNode<T> head;

    /**
     * 尾结点
     */
    SkipListNode<T> tail;

    /**
     * 除头结点之外的节点个数
     */
    int length;

    /**
     * 跳跃表的高度
     */
    int level;


    public SkipList() {
        // 初始化头结点
        head = new SkipListNode<T>(SkipListConfig.MAX_LEVEL);
        tail = null;
        this.length = 0;
        this.level = 1;
    }

    /**
     * 查询节点所在的位置(有序链表)
     * <p>
     * 1. 查询上层节点(每一层都是有序链表)
     * <p>
     * 2. 上层发现大于或为null,查找下一层
     *
     * @param node
     * @return
     */
    public SkipListNode<T>[] find(SkipListNode<T> node) {
        SkipListNode<T>[] update = new SkipListNode[node.getLevels().length];

        SkipListNode<T> pNode = this.head;
        SkipListNode<T> nextNode;

        // 当插入节点层数为1时,会退化,因此需要进行优化
        for (int i = node.getLevels().length - 1; i >= 0; i--) {
            while ((nextNode = pNode.getLevels()[i].getNext()) != null && nextNode.compareTo(node) < 0) {
                pNode = nextNode;
            }
            update[i] = pNode;
        }
        // 返回每一个层级插入位置的前一个节点
        return update;
    }


    /**
     * 插入节点
     * <p>
     * 1. 查询插入位置
     * <p>
     * 2. 调整跳跃表高度
     * <p>
     * 3. 插入节点
     * <p>
     * 4. 调整prev指针
     *
     * @param node 待插入节点
     */
    public void add(SkipListNode<T> node) {
        if (this.length++ == 0) {
            this.tail = node;
            SkipListNode.SkipListLevel<T>[] headLevels = this.head.getLevels();
            for (int i = 0; i < node.getLevels().length; i++) {
                headLevels[i].setNext(node);
            }
            return;
        }

        SkipListNode.SkipListLevel<T>[] levels = node.getLevels();
        // 更新跳表的最大层数
        this.level = Math.max(this.level, levels.length);
        // 查询前置节点
        SkipListNode<T>[] preNodes = find(node);

        for (int i = 0; i < levels.length; i++) {
            SkipListNode.SkipListLevel<T> preNodeLevel = preNodes[i].getLevels()[i];
            SkipListNode<T> nextNode = preNodeLevel.getNext();

            // 当前插入节点连接下一个结点
            levels[i].setNext(nextNode);
            // nextNode连接当前结点
            nextNode.setPrev(node);
            // 前置节点连接当前插入节点
            preNodeLevel.setNext(node);
        }

        // 如果当前结点插入在尾结点之后,那么当前插入的节点就是新的尾结点
        SkipListNode<T> preNode = preNodes[0];
        if (preNode == tail) {
            tail = node;
        }
        node.setPrev(preNode);


    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        for (SkipListNode<T> skipListNode : this) {
            builder.append(skipListNode.toString()).append("->");
        }

        return builder.toString();
    }

    /**
     * 自定义迭代器
     */
    private class SkipListIterator implements Iterator<SkipListNode<T>> {
        SkipListNode<T> prevNode;
        int cursor;

        public SkipListIterator() {
            this.prevNode = tail;
            this.cursor = length - 1;
        }

        @Override
        public boolean hasNext() {
            return cursor >= 0;
        }

        @Override
        public SkipListNode<T> next() {
            SkipListNode<T> result = prevNode;
            prevNode = prevNode.getPrev();
            cursor--;
            return result;
        }
    }

    @Override
    public Iterator<SkipListNode<T>> iterator() {
        return new SkipListIterator();
    }
}

测试代码

public class MainDemo {
    public static void main(String[] args) {
        SkipList<String> skipList = new SkipList<>();

        SkipListNode<String> skipListNodeD = new SkipListNode<>(4);
        skipListNodeD.setElement("4");
        skipListNodeD.setScore(4);
        skipList.add(skipListNodeD);

        SkipListNode<String> skipListNodeA = new SkipListNode<>(1);
        skipListNodeA.setElement("2");
        skipListNodeA.setScore(2);
        skipList.add(skipListNodeA);


        SkipListNode<String> skipListNodeB = new SkipListNode<>(1);
        skipListNodeB.setElement("1");
        skipListNodeB.setScore(1);
        skipList.add(skipListNodeB);

        SkipListNode<String> skipListNodeC = new SkipListNode<>(1);
        skipListNodeC.setElement("3");
        skipListNodeC.setScore(3);
        skipList.add(skipListNodeC);



        System.out.println(skipList);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/589273.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙学习1概况

鸿蒙学习1相关概念 前言相关概念Stage 模型1. AbilityStage2. UIAbility组件和ExtensionAbility组3. WindowStage4. Context 事件传递UIAbility组件与UI的数据同步UIAbility组件间交互&#xff08;设备内&#xff09; 进程模型线程模型 前言 有时间多看官网&#xff0c;官网的…

ctfshow web78 获取flag(用老版的火狐浏览器)

题&#xff1a; 第一种&#xff1a;利用input伪协议 ,获取到flag ?filephp://input POST data <?php system(tac ls) ?> 第二种&#xff1a;利用flter协议,获取到flag https://21d9e58a-c0fd-47ea-a9c4-d875100f2fdb.challenge.ctf.show/?filephp://filter/readcon…

如何彻底删除python

点击菜单栏中的“开始”&#xff0c;打开“运行”。 在运行上输入“cmd”&#xff0c;点击“确定”&#xff0c;接着输入“python --version”&#xff0c;得到一个程序的版本。 然后到这个网上下载对应的程序的版本&#xff0c;接着点击这个版本软件&#xff0c;点击这个卸载。…

java入门-日期类

日期类 Date类 Date类表示特定的时间&#xff0c;可以精确到毫秒。 获取Date对象 Date date new Date(); 构造方法 /*** Allocates a <code>Date</code> object and initializes it so that* it represents the time at which it was allocated, measured to…

WebStorm2024版 将项目上传到gitee

目录 一、准备 WebStorm gitee 二、上传代码到Gitee 三、过程中遇到的问题 报错&#xff1a;You may want to first integrate the remote changes (e.g., git pull ...) before pushing again. 报错&#xff1a;fatal: refusing to merge unrelated histories 报错&a…

Linux深入学习内核 - 中断与异常(下)

软中断&#xff0c;Tasklet和Work Queue 由内核执行的几个任务之间有一些不是紧急的&#xff0c;他们可以被延缓一段时间&#xff01;把可延迟的中断从中断处理程序中抽出来&#xff0c;有利于使得内核保持较短的响应时间&#xff0c;所以我们现在使用以下面的这些结构&#x…

【linux】进程间通信(匿名管道)

对于本篇文章我们采取三段论&#xff1a;是什么 为什么 怎么办。 目录 进程间为什么要通信&#xff1f;进程间如何通信&#xff1f;进程间怎么通信&#xff1f;匿名管道&#xff1a;匿名管道原理&#xff1a;代码示例&#xff1a;匿名管道的情况与特征&#xff1a; 进程间为什…

双指针(C++)

文章目录 1、移动零2、复写零3、快乐数4、盛最多水的容器5、有效三角形的个数6、和为s的两个数7、三数之和8、四数之和 需要理解的是&#xff0c;双指针并非只有指针&#xff0c;双指针的意思是两个位置。比如对于数组来说&#xff0c;两个下标也是双指针。当然&#xff0c;也可…

二叉树中的最大路径和 - LeetCode 热题 50

大家好&#xff01;我是曾续缘&#x1f638; 今天是《LeetCode 热题 100》系列 发车第 50 天 二叉树第 15 题 ❤️点赞 &#x1f44d; 收藏 ⭐再看&#xff0c;养成习惯 二叉树中的最大路径和 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一…

冯喜运:5.2黄金触底反弹今日还会跌吗?原油最新行情分析策略

【黄金消息面分析】&#xff1a;周三(5月1日)&#xff0c;受美联储主席鲍威尔讲话影响&#xff0c;现货黄金价格暴涨近33美元&#xff1b;周四亚市早盘&#xff0c;现货黄金守住涨幅&#xff0c;目前交投于2323.69美元/盎司。此外&#xff0c;美联储主席鲍威尔(Jerome Powell)未…

RoNID:通过生成可靠标签与聚类友好型表征来实现新意图的发现

论文地址&#xff1a;https://arxiv.org/abs/2404.08977 原文地址&#xff1a;intents-are-not-going-away-ronid-is-a-new-intent-discovery-framework 2024 年 4 月 26 日 Robust New Intent Discovery&#xff08;RoNID&#xff09;框架致力于在开放域场景中识别已知意图并合…

树莓派控制步进电机(上):硬件连接

目录 说明 硬件连接 DM542的连接方法 树莓派的连接方法 参考文献 说明 最近需要测试树莓派控制步进电机的功能&#xff0c;在查阅网上资料的基础上做了一些整理和测试&#xff0c;特别记录在此。这里我们使用的是树莓派4B开发板&#xff0c;步进电机为6线两相步进电机&am…

探索APP分发的含义和小猪APP分发平台的优势(小猪APP分发平台)

一、APP分发的基本含义 APP分发指的是将开发完成的APP通过特定渠道推广给用户的过程。这个过程涵盖探索APP分发的含义和小猪APP分发平台的优势了从提交、审核到发布的全过程探索APP分发的含义和小猪APP分发平台的优势&#xff0c;目的是让APP更好地触达潜在用户探索APP分发的含…

AI时代程序员必备的22个网站,你了解多少?

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

2024-05-02 商业分析-杭州小万科技-商业模式分析

摘要: 对杭州小万科技的商业模式进行分析,以对其做出客观的评估。 杭州小万科技的资料: 杭州小万科技有限公司 - 企知道 (qizhidao.com) 杭州小万科技有限公司网站备案查询 - 天眼查 (tianyancha.com) 杭州小万科技有限公司 - 爱企查 (baidu.com) ​ 2023年年报:

高中数学:三角函数公式汇总及推导

一、定义 常用三角函数值 参考&#xff1a; 三角函数定义 二、基本三角函数及相互关系 sinx cosx tanx cscx secx cotx 函数间相互关系 参考&#xff1a; cosx、sinx、tanx的函数图像与性质 secx、cscx、cotx函数图像及相关关系 三、诱导公式 口诀&#xff1a;奇变…

【Python文字识别】基于HyperLPR3实现车牌检测和识别(Python版本快速部署)

闲来无事&#xff0c;想复现一下网上的基于YOLO v5的单目测距算法。然后就突然想在这个场景下搞一下车牌识别&#xff0c;于是就有了这篇文章。今天就给大家分享基于HyperLPR3实现车牌检测和识别。 原创作者&#xff1a;RS迷途小书童 博客地址&#xff1a;https://blog.csdn.ne…

商务谈判模拟口才训练方案(3篇)

商务谈判模拟口才训练方案&#xff08;3篇&#xff09; 商务谈判模拟口才训练方案&#xff08;一&#xff09; 一、训练目标 本训练方案旨在提高参与者在商务谈判中的口才表达能力&#xff0c;包括清晰表达、有效倾听、应对挑战和构建信任等能力。 二、训练内容 基础口才训练…

android天气实战

页面绘制 问题1、下拉框需要背景为透明 我懒得写全部省份就写了5个所以不需要往下 图标准备 iconfont-阿里巴巴矢量图标库几坤年没来这了好怀念啊&#xff0c;图标库选择下雨的图标等 准备网络请求 0、API接口准备 api免费七日天气接口API 未来一周天气预报api (tianqiap…

智慧能源数据监控平台

随着科技的飞速发展&#xff0c;能源管理已逐渐从传统的粗放型向精细化、智能化转变。在这个转型过程中&#xff0c;HiWoo Cloud平台的智慧能源数据监控平台以其独特的技术优势和创新理念&#xff0c;正引领着能源管理的新潮流。 一、智慧能源数据监控平台的概念 智慧能源数据…
最新文章