考虑具有order
属性的对象。对象将根据此属性进行排序。
如果给出以下限制和操作,您将如何分配order
属性?
操作(按重要性排序)
push(object)
:在索引0处插入对象。
swap(indexN, indexM)
:在索引N处交换对象,索引为M的对象。
remove(object)
:删除对象。剩余元素必须保持相同的顺序。
insert(object)
:按给定顺序插入对象。
限制
更改对象的order
属性非常昂贵。应尽量减少变化。
order
可以是实现所需的整数或浮点数。
如果order
保持唯一,则操作insert
必须包含修复order
的方法(如果已存在),尽可能少地进行更改。可以假设,如果插入的对象与现有对象具有相同的order
,则还有另一个标准可以确定哪个对象首先出现。
如果order
允许重复,那么操作swap
必须包含一种方法来修复交换元素的order
,如果它们具有相同的值,则再次进行尽可能少的更改。惩罚操作insert
是首选。
这个问题很可能已经有了名称和已知的解决方案,但我乍看之下找不到它。
答案 0 :(得分:2)
使用浮点订单
对于push
,为对象分配一个等于当前在索引1处的对象的顺序,减去1(list[0].order = list[1].order - 1
)
对于swap
,交换两个对象的订单(temp = list[i]; list[i] = list[j]; list[j] = list[i]; temp = list[i].order; list[i].order = list[j].order; list[j].order = temp
);如果这可能会引入一致性问题,那么理想情况下你可以在元素上放置一个transit
标志来指示它们的顺序正在被修改过程中,或者最坏情况下锁定对象直到它们是一致的
对于remove
,什么都不做 - 列表中的对象仍然是有序的,你刚刚在顺序中引入了一个不应该是问题的空白
insert
是唯一有问题的。如果要在索引i
处插入元素,则其顺序等于索引i-1
和i+1
(list[i].order = (list[i-1].order + list[i+1].order)/2
)处元素的顺序的平均值。验证此新订单不等于索引i-1
或i+1
(list[i].order != list[i-1].order && list[i].order != list[i+1].order
)的订单 - 这表示您已点击机器epsilon。当发生这种情况时(这应该很少发生)你有两个选择:
0
订单,在索引1处指定订单1
,在索引n处指定订单n
list[i-1].order = (list[i-2].order + list[i-1].order)/2
之前,将相邻元素重新排序为list[i+1].order = (list[i+2].order + list[i+1].order)/2
和list[i] = (list[i-1] + list[i+1])/2
,再次验证您的[i-1]和[i + 1]重新排序时未到达机器episilon - 如果你已经到达机器epsilon例如[i-1],然后首先将[i-2]重新排序为list[i-2].order = (list[i-3].order + list[i-2].order)/2
,然后重新排序[i-1]。如果[i-2]重新排序命中机器epsilon,则首先重新排序[i-3],依此类推。 (如果你到达列表的末尾然后简单地减少元素[0]的顺序或增加元素[n]的顺序。)正如你所看到的,在最坏的情况下你有一个更昂贵的级联重新排序你只是咬紧牙关并重新排序整个清单;但是,重新排序很可能仍然是本地的。一个很好的折衷方案是,如果你级联太多次(合理的“太多”值),那就做一个完整的重新排序。答案 1 :(得分:0)
只是把它扔出去,一个双重链表给你:
push(object)
:O(1),命令比当前头部少1。swap(indexN, indexM)
:O(n),交换订单remove(object)
:O(1),不要触及任何订单insert(object)
:O(n),插入订单以便按顺序对列表进行排序可能不好,因为第二个最重要的一个有昂贵的(变更单)操作。