重新排列项目而不改变所有项目的排名

Reranking items without changing ranks of all items

我有一个项目列表,每个项目都有一个与之关联的等级。

Item 1, Rank=1
Item 2, Rank=2
Item 3, Rank=3
Item 4, Rank=4
Item 5, Rank=5

我想设计一种方法来处理项目的重新排名,而对其他项目的排名变化很小或没有变化。

我想到的一个解决方案是利用小数并使用 Java 的双变量类型。因此,例如,如果我在 item2 和 item3 之间移动 item5,这将是输出 -

Item 1, Rank=1
Item 2, Rank=2
Item 5, Rank=2.5
Item 3, Rank=3
Item 4, Rank=4

以此类推,

Item 1, Rank=1
Item 2, Rank=2
Item 4, Rank=2.25
Item 5, Rank=2.5
Item 3, Rank=3

这个解决方案有效,但在某个时间点后(~55 次在同一位置移动,我达到了双变量限制,那时我可能不得不重置所有等级)

我只是想知道是否有更好的方法来解决这个问题?

有几点需要牢记。

可能有多种解决方案,这是我更喜欢的一种

我会把这个问题分解成多个独立的问题:

  1. 在您的 java 后端中,您希望拥有以某种方式排序的项目列表,并有可能按顺序进行快速 O(1) 更改。

最好的结构——双链表。您将需要使用 hashmap 在此列表中按项目 name/id 快速查找对象。

你可以很容易地将这样的结构存储到数据库中,只需在项目中添加两个外键table。在存储期间,您将只需要更新受影响的行(请记住,prev/next 项目在您移动项目时也会受到影响)。它看起来像多个 update table set prev=?, next=? where id=?

  1. 在您的 java 服务中,您希望尽快显示已排序的项目列表,可能已分页。

最佳结构——预排序数组

要在数据库中存储这样的结构,您需要存储位置(等级)的列。当然,您需要在此列上建立索引。

要检索此类结构,您将使用非常简单、快速且高效的查询,例如 select item from table order by rank limit ?,?


现在你有矛盾了,你的编辑数据结构与你的检索数据结构不匹配,任何尝试使用单一数据结构来解决这两个问题都会导致一部分性能下降,让我们独立解决这个问题:

  1. 您将创建单独的异步服务(cron 作业),它将从一个 table 读取数据,转换(重新计算所有项目的排名)并存储在另一个 table。

这里您将有两个选择:要么在计算后完全替换第 2 个 table 中的数据,要么查找差异并仅更新更改的行。我相信完全替换更容易实现,实际上它可以更快。

因此,通过这种方法,您系统的客户可见部分表现出色(数据管理部分和数据显示部分尽可能快地工作)。

唯一的问题是更改传播,这通常很好,大多数用户会接受它作为合理的权衡。

如何编写一个小例程来均匀分布数组(或列表或其他)中一系列元素的排名值?

如果在位置 x 处插入一个新元素,则将范围 x-1 .. x+1 的元素传递到子例程中。开始位置和结束位置的排名值保持不变,其他位置以均匀距离计算。如果成功,return 为真。现在,如果距离变得太小 return false,调用者将范围扩展到 x-2 .. x+2 并再次进入子例程。

您必须注意触及数组边界,甚至 运行 超出值 - space。