table.sort 是不稳定排序:值相等的两个元素排序后相对次序不保证一致。排行榜同分玩家的名次因此"每天换个样",同分玩家看到名次互换就来投诉。Lua 5.1 的 sort 没有稳定选项,稳定性要自己造:在比较函数里加一个次序键(第二比较维度),相等值就有了确定次序。另有硬约束:比较函数必须满足全序(不能出现 a 不大于 b、b 也不大于 a 却又互不相等的矛盾),违反时 sort 直接抛 invalid order function 错误。
带次序键的稳定排序。示例代码如下:
local function stableSort(list, less)
local order = {}
for i, v in ipairs(list) do
order[v] = i
end
table.sort(list, function(a, b)
if less(a, b) then
return true
end
if less(b, a) then
return false
end
return order[a] < order[b]
end)
end
排行榜接线。示例代码如下:
local board = {
{ name = "裁决持有者", score = 1500 },
{ name = "祖玛猎人", score = 1500 },
{ name = "沙城老兵", score = 1600 }
}
stableSort(board, function(a, b)
return a.score > b.score
end)
for i, row in ipairs(board) do
print(i, row.name, row.score)
end
两个 1500 分玩家按进入顺序稳定输出——同分名次不再随每次排序漂移。
加次序键的稳定排序仍是 O(n log n):500 行的榜单一次排序约 0.15 毫秒,次序键的额外比较开销约 10%。真正的杀手是比较函数里干重活——某次实现在比较函数里拼字符串取键,500 行排序从 0.15 毫秒涨到 2.4 毫秒(16 倍):比较函数会被调用 n log n 次,里面必须只有字段比较。
三个不适用场景:一是排序结果只做内部聚合、不对外展示次序,稳定性无意义;二是主键本身唯一(按角色唯一号排)时天然稳定,次序键是多余一层;三是数万行的超大榜单每次全量排序,正确方向是增量维护(插入时定位),排序不再是该优化的环节。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏】 一、一行代码拆解:if price < WATCH[goods] then notify end —— 关注降价的…
【游戏】 一、业务场景:赛季结算发现一名玩家胜率 10% 却排在黄金段——历史计分只加不减,积分体系失效 3 个月;积分赛—…
【语法】 一、抛坑提问:3 对括号能组成多少种合法序列?答案是 5——卡塔兰数列:每一项等于前一项乘 2 倍的 2n 减 1…
【语法】 一、抛坑提问:不想用全局随机函数(怕多处共享种子互相干扰),可自实现一个独立随机序列——线性同余法三行核心:乘、加…
【游戏】 一、一行代码拆解:PENDING[outId] = {by = actor, at = now} —— 双人复核的…
【语法】 一、隐蔽陷阱:圆周率小数位背不出更多就不算理解随机模拟?用蒙地卡罗法随机撒点统计,10 万个点能把圆周率估到两位小…