我正在构建一个文件共享系统,需要将单个文件传输给许多对等体。一个单根对等体具有整个文件,需要将其传输给所有其他对等体。如何最好地构建文件传输树,以使总等待时间最小化?
例如:
在这棵树中,我们需要等待4次才能完成传输。
这两个更好,因为我们只需要等待三次才能完成转移。
答案 0 :(得分:2)
我认为最佳算法(在史蒂夫指出的同时不发送和接收的约束下)将首先将log2(n)
节点放在根目录下。然后对于每个节点,它应该具有其父节点的子节点数减去其直接兄弟节点中的从左到右排序(即不查看其父节点的子节点)。
答案 1 :(得分:1)
参考Steve Jessops评论;为什么不直接使用BitTorrent等? (即一个经过充分测试,部署良好的基础设施,建立在一个已知良好的框架上,并且几乎不需要你做任何工作?)
如果需要,可以轻松修改BT客户端以接受某种形式的身份验证。
编辑:用户的回答很好; log2(n)
可能是客户的最佳数量; 假设每个客户端具有相同的下载带宽。
log2(n)
倾斜。如果您的管道是任何单个客户端的最大下载速度的n
倍,则这是最快的。 (编辑:当然,假设您可以同时发送给多个客户。但这是给定的,对吗?)
答案 2 :(得分:1)
想象一只兔子会产生另一只兔子。这两只兔子产卵了另外两只兔子,这4只兔子产生了另外4只兔子......现在,带有代表亲子关系的兔子的树有点奇特的形状。根节点具有度D = log2(n)。 Root的后代(其中的D)具有从0到D-1的度数。实际上,每个具有X度的节点都有X个子节点,其度数从0到X.
你可能会说这是一个“分形树”,完美的“不平衡”。
所有这些假设每个节点的上传速度等于每个节点的下载速度。在现实世界中情况并非如此,因此您实际上需要重新检查(再次)您的初始问题: - )
答案 3 :(得分:1)
如果您想象给定节点的第二个和后续子节点实际上是第一个子节点的后代链,那么答案就更容易实现,例如。
O
/|\
/ | \
/ | \
O O O
实际上表示为
O
/
/
/
O===O===O
(我将“sibling-of”边缘表示为===
。)在这个新表示中,除根之外的每个节点最多可以有2个子节点:一个是其实际的第一个子节点,另一个节点是它是右边的第一个兄弟姐妹。 (根可以没有兄弟姐妹,所以最多只有一个孩子。)例如,OP的帖子中的第二棵树,
O
/ \
/ \
/ \
O O
/ \
/ \
/ \
O O
可以在“兄弟边缘”表示中表示为
O
/
/
/
O=======O
/
/
/
O=======O
诀窍是转移到节点的两个孩子将同时发生。这使我们可以在视觉上排列树,以便同时传输到的所有节点都出现在同一垂直位置。我们现在得到:
0 O
/
/
/
1 O
/ \\
/ \\
/ \\
2 O O
\\
\\
\\
3 O
要计算出可以按时间t
传输的最大节点数,我们需要在上面的布局中有一棵树,其最底层(t
行)没有间隙。我们称之为最大节点数m(t)
。对于t
> 1,我们可以通过获取t-1
的最大大小树并为每个最右边的节点创建2个子节点(=原始树中的1个子节点和1个兄弟节点)来构建这样的树。列出m(t)
的几个值可以得到:
t Total Rightmost
nodes nodes
0 1 1
1 1+1*1=2 1 (only multiply by 1 because the root can't have siblings)
2 2+1*2=4 2
3 4+2*2=8 4
4 8+4*2=16 8
显然,m(t) = 2^(t-1)
,这是有道理的,因为这个最优的树只是一个完整的二叉树,根节点顶部有一个小“干”。
由此得出,如果节点n
的数量是2的幂,则n = 2^t
节点的最佳树需要t+1
时间,而如果不是,则需要n
节点比下一个2的较小功率多1个单位时间。因此,发送到roundup(log2(n)) + 1
个节点所需的时间为roundup(log2(n)) + 1
。
要实现实际的通信树,您现在可以将“兄弟”边缘转换回左节点的父节点和右节点之间的边缘。这表明,对于2次幂节点计数,离开根的边数将与所需的总时间({{1}})相同。离开任何节点的第一个子节点的边数总是比其父节点少一个,并且每个第二个和后续子节点的边数总是比其左边节点少一个。