惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
MongoDB | Blog
MongoDB | Blog
U
Unit 42
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
L
LINUX DO - 最新话题
博客园_首页
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Privacy & Cybersecurity Law Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
K
Kaspersky official blog
C
Cisco Blogs
博客园 - 【当耐特】
阮一峰的网络日志
阮一峰的网络日志
I
Intezer
罗磊的独立博客
MyScale Blog
MyScale Blog
Last Week in AI
Last Week in AI
A
About on SuperTechFans
G
GRAHAM CLULEY
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
D
DataBreaches.Net
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
I
InfoQ
T
The Exploit Database - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
Project Zero
Project Zero

风萧古道 - 勤学苦练,年复一年

游戏服务器开发经验(五)应对复杂需求 沉浸式体验东汉末年生活 - 《真三国无双 起源》玩后感 怒其不争!致2025年HLTV的Top18-NiKo Linux家用服务器维护指南 游戏服务器开发经验(四)避免写Bug的习惯、技巧和心态 游戏服务器开发经验(三)线上维护 游戏服务器开发经验(二)避免内存泄露 游戏服务器开发经验(一)道具防刷 35岁找不到工作,绝对不会是软件开发人员的结局 用爱发电项目开发两个月的心得体会 以魏延“子午谷奇谋”讨论软件需求可行性问题 MQTT协议中可变长度的具体计算方式(有计算过程解析) 关于游戏服务器配置表功能的探讨 Java并发编程中上锁的几种方式 如何用C++分割一个字符串? CSAPP第二章-信息的表示与处理 我的自我介绍 Windows XP虚拟机中文版无需激活下载 Linux C++ Socket实战 传统软件服务器与游戏服务器架构区别 独立个人项目开发心得 - 任务切分、挑战性、实用性和半途而废 使用Python实现简单UDP Ping 使用Python开发一个简单的web服务器 Kotlin手动实现一个最简单的哈希表 Kotlin实现二叉堆、大顶堆、优先级队列 搭建Spark实战环境(3台linux虚拟机集群)(一)样板机的搭建 Springboot操作MongoDB,包括增改查及复杂操作 Unison在Linux下的安装与使用 Java实现类似WINSCP访问远程Linux服务器,执行命令、上传文件、下载文件 一个被废弃的项目——自动爬取信息然后发给我自己邮箱上 Python连接MongoDB和Oracle实战 MongoDB常用查询语句 vue和springboot项目部署到Linux服务器 Python的一些用法(可能不定时更新) java正则表达式 - 双反斜杠(\)和Pattern的matches()与find() 简述爬虫对两种网站的不同爬取方式 Vue的路由配置及手动改地址栏为啥又跳转回来?? [JavaScript]JS基础知识 [Mybatis]逆向工程中Select语句查询不出‘TEXT’字段 [编译原理]FIRST、FOLLOW和SELECT [Spring]Spring学习笔记 [算法]分布估计算法 - 一种求解多维背包问题的混合分布估计算法_王凌 [日常]我做独立博客的原因 人间值得 深入理解计算机系统 想想就开心! 最重要的事,只有一件 藏书 被讨厌的勇气 关于 简历 朋友 尊重自己:给予与接收的心灵艺术
Java TreeSet的一些用法和特性
JonathanLin · 2022-06-18 · via 风萧古道 - 勤学苦练,年复一年

就是一些例子啦。

先看一个例子(kotlin实现)

import java.util.TreeSet

/**
 * 定义一个用于测试TreeSet集合的结构
 * 用TreeSet进行排名
 * id: 玩家id
 * score: 玩家得分
 */
data class PlayerScore(var id: Int, var score: Int): Comparable<PlayerScore> {
    override fun compareTo(other: PlayerScore): Int {
        return if (score > other.score) {
            1
        } else if (score < other.score) {
            -1
        } else {
            0
        }
    }

}


fun main() {
    //创建一个TreeSet
    val treeSet: TreeSet<PlayerScore> = TreeSet()
    //创建3个PlayerScore,其中对id为101的对象存一个引用
    //将3个PlayerScore装入set中
    val id101Obj = PlayerScore(101,100)
    //按不同的顺序加入TreeSet
    treeSet.add(PlayerScore(102,200))
    treeSet.add(id101Obj)
    treeSet.add(PlayerScore(103,300))

    println("按不同的顺序加入TreeSet,按score从小到大输出:")
    showTreeSet(treeSet)

    println("再加入重复id,但分数不同的对象,按score从小到大输出:")
    treeSet.add(PlayerScore(101,500))
    showTreeSet(treeSet)

    println("直接修改id为101的对象的分数为400,按score从小到大输出:")
    id101Obj.score = 400
    showTreeSet(treeSet)

}

private fun showTreeSet(treeSet: TreeSet<PlayerScore>) {
    treeSet.forEachIndexed { index, s ->
        println("排名:${index+1} 分数:${s.score} id:${s.id}")
    }
    println()
}

运行结果:

按不同的顺序加入TreeSet,按score从小到大输出:
排名:1 分数:100 id:101
排名:2 分数:200 id:102
排名:3 分数:300 id:103

再加入重复id,但分数不同的对象,按score从小到大输出:
排名:1 分数:100 id:101
排名:2 分数:200 id:102
排名:3 分数:300 id:103
排名:4 分数:500 id:101

直接修改id为101的对象的分数为400,按score从小到大输出:
排名:1 分数:400 id:101
排名:2 分数:200 id:102
排名:3 分数:300 id:103
排名:4 分数:500 id:101

分析

首先,PlayerScore继承Comparable接口,实现了从小到大排序。在最开始只有3条数据时,按照不同的顺序插入TreeSet,可以正常的完成排序。

之后玩家101的分数发生改变,需要重新给玩家进行排名,我们分别通过两种方式进行操作:

  1. 通过id101Obj的引用来对这个对象的分数进行修改;
  2. 通过再往TreeSet中加入一个id为101,分数不同于之前的分数的对象。

结果: 第一种方式:玩家的积分被修改了,但是排名依旧为第1; 第二种方式:虽然积分正常排序,但是有两个id为101的对象。

所以如果我们的玩家积分发生改变的时候,要如何才能正常排序呢?

可以对某个对象先从TreeSet中删除,再往TreeSet中插入。这是因为TreeSet的底层是红黑树,在删除和插入的时候,会对树结构进行调整。 代码如下:

    //创建一个TreeSet
    val treeSet: TreeSet<PlayerScore> = TreeSet()
    //创建3个PlayerScore,其中对id为101的对象存一个引用
    //将3个PlayerScore装入set中
    val id101Obj = PlayerScore(101,100)
    //按不同的顺序加入TreeSet
    treeSet.add(PlayerScore(102,200))
    treeSet.add(id101Obj)
    treeSet.add(PlayerScore(103,300))

    println("按不同的顺序加入TreeSet,按score从小到大输出:")
    showTreeSet(treeSet)

    treeSet.remove(id101Obj)
    id101Obj.score = 400
    treeSet.add(id101Obj)
    println("先将id101Obj从TreeSet中删除,修改值,然后再插入TreeSet中,按score从小到大输出:")
    showTreeSet(treeSet)

结果如下:

按不同的顺序加入TreeSet,按score从小到大输出:
排名:1 分数:100 id:101
排名:2 分数:200 id:102
排名:3 分数:300 id:103

先将id101Obj从TreeSet中删除,修改值,然后再插入TreeSet中,按score从小到大输出:
排名:1 分数:200 id:102
排名:2 分数:300 id:103
排名:3 分数:400 id:101

更进一步

先删后加的方式是可以完成排序,但是TreeSet本身是线程不安全的。如果有多个线程都要更新玩家积分和排名,那么大概率会存在问题。 TreeSet虽然可以边插边排序,但是它只允许一次插入,插入之后积分的修改并不会修改排序。

对于排行榜上的排名经常变动的情况,用TreeSet是不太合理的。

另一种排行榜实现

本来选用TreeSet,是因为TreeSet拥有“边插入边排序”的特点,但在排行榜需要更新时并不方便。 那么换一种思路,如果只用变长的ArrayList来存储玩家积分对象,同样是在插入/更新/删除时进行排序?

先插入/更新/删除,对ArrayList内的数据进行修改,然后进行排序。