一棵关于树节点变色的问题,欢迎感兴趣的大佬们讨论

2023-02-16 17:04:45 +08:00
 baptismOfTime

1834 次点击
所在节点    程序员
19 条回复
seawing
2023-02-16 17:10:42 +08:00
树配一个 hash 表?
MoYi123
2023-02-16 17:16:03 +08:00
可以参考 线段树的懒标记 的做法
zhy0216
2023-02-16 17:29:34 +08:00
没什么好优化的吧 本来这个查询就只有 log ( n )的复杂度
tool2d
2023-02-16 17:30:16 +08:00
可以考虑多根节点。比如 Node3_2 有两个父节点,即属于 Node2_1 ,又属于红色节点。
JasonLaw
2023-02-16 17:37:10 +08:00
我觉得你应该说明“不同操作发生的次数”,这会影响最佳方案。
baptismOfTime
2023-02-16 18:22:07 +08:00
感谢各位回复,千万级别的节点 需要持久化各个节点的颜色和位置属性,查询操作大概有 3-4k 的 qps ,变色和失色频率比较低,tps 在 20 以内
baptismOfTime
2023-02-16 18:30:37 +08:00
棘手的地方在于每次变色和失色要考虑到向根 /子级追溯十几个层级、几万个节点的数据;有没有熟悉 neo4j 的大佬,请教一下在这种场景里把颜色当做边,节点当顶点,查询节点颜色实现为用边查询受关联影响的直接顶点属性,但是节点变色和失色的场景下会进行大量的边修改 这个理论上能否可行?
airwalkers
2023-02-16 18:37:01 +08:00
节点配一个时间戳,查询节点到跟路径上最新时间戳的颜色
zhy0216
2023-02-16 20:14:37 +08:00
想到一个 O ( log K ) 的办法 K 是节点上有颜色的 node
首先构造 id, id 是这个树在这一层的排序的 index 每多一层 加一个“-” 区分
比如 root 节点是 0
Node2_1 是 0-1

然后用字典树把这个每一层的 id 和颜色记录下来
当查询一个新的 node 的时候 就是查询字典树中的值 (最大前缀)
Maboroshii
2023-02-16 20:26:36 +08:00
给每个节点加一个日志,记录主动变色的历史。 子节点递归查找父节点的日志。 子节点的变色时间在父节点变色时间之前,那么和父节点同色,否则保持自己的颜色?
wlsnx
2023-02-16 21:00:01 +08:00
用一个 hash 表存到节点的指针,这样就可以快速找到这个节点,然后只有两种情况:节点本身有颜色,返回这个颜色;节点没颜色,向上找第一个有颜色的父节点。增加、删除、移动节点时要同步更新 hash 表。
Nazz
2023-02-16 21:13:31 +08:00
更新的时候只更新本节点颜色,记录下操作序列号(单调递增); 获取节点颜色需要递归到根节点,取最大序列号节点的颜色. 更新 O(1), 查找 O(logN)
robbaa
2023-02-16 21:41:11 +08:00
其实,主要是无限层级遍历问题。
分享 2 个方案,一个是看来的,另外一个算是改进,好不好不好说。

方案一:
每个节点 4 个属性:
id:编号
name:名称
parent:父节点编号
left:左子节点排序编号
right:右边子节点排序编号

1. 先构建树
2. 然后按照,先序遍历对每个节点的 left 、right 设值,每次加 1.
robbaa
2023-02-16 21:41:23 +08:00
大致如下:
root: 0,25
node2_1:1,18
node3_1:2,3
node3_2:4,15
node4_1:5,8
node5_1:6,7
ndoe4_2:9,14
node5_2:10,11
node5_3:12,13
node3_3:16,17
node2_2:19,22
node3_4:20,21
node2_3:23,24

需求 1:查询某节点下所有节点
select * from nodes where left > {left} and right < {right}

需求 2:查询某元素上级节点
select * from nodes where left < {left} and right > {right} order by left ASC

缺陷代价:
元素的添加与删除,都会导致大量 left 、right 值的更新。
robbaa
2023-02-16 21:41:38 +08:00
方案二:
基于方案一改良,把 left 和 right 的值换成 float 或 double ,不再递增只保证数值增加的。
新增元素,用两侧兄弟元素 right(leftNodeRight)与 left(rightNodeLeft)的值去计算新节点的 left 、right 。
left=(rightNodeLeft-leftNodeRight)/4+leftNodeRight
right=rightNodeLeft - (rightNodeLeft-leftNodeRight)/4

计算公式不一定,只要能保证有“足够空间”都可以,定时做好“空间”回收就行。
aragakiyuii
2023-02-16 23:03:17 +08:00
左右值
xiangyuecn
2023-02-17 00:46:51 +08:00
你看到的不一定是真的

所以,完全可以作假,前端视觉欺骗,点一下搞个几秒的动画

比如转个 5 秒的圈,夸张点,几百万人同时操作,都在那转圈迷惑一下,服务器将变更收集起来,几秒内只实际计算更新一次,随便搞
CapNemo
2023-02-17 17:45:41 +08:00
1. 删除颜色操作可以视为染成父节点颜色
2. 指定合适的遍历顺序时,树可以用数组表示
3. 因此应当搜索区间染色问题
CapNemo
2023-02-17 17:47:12 +08:00
@CapNemo 建议使用动态开点线段树

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/916715

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX