这个学期的高级数据结构课程,我被分配到了概叙新加坡某个博士的论文,我刚开始看的时候我也是一脸懵的,认真地对细节进行理解后,觉得很厉害,现在我就来介绍一下Baton Tree。
Baton 的概念
首先,我们需要知道,baton 是一个基于平衡树构建起来的树状对等网络结构。有关平衡树的概念如下:
A tree is balanced if and only if at any node in the tree, the height of its two subtrees differ by at most one.
中文意思:对于树中的任意节点,当且仅当其两个子树的高度最多相差1时,树就是平衡的。
在平衡树的基础上,BatonTree的每个节点还附带了以下内容(在本PPT中,全部都以二叉平衡树为例):
Level(层级):层级就相当每个节点的高度,根节点的层级为0,然后依次类推,子节点的层级比父节点的层级多1。
Number(序号):任意层级L,序号从左到右分别分配为1到2^L,不管当前位置是否存在节点。
Link(链接):包括父节点链接,子节点链接,邻接节点链接。邻接节点为当前节点按中序遍历顺序的前一个和后一个节点。
Routing table(路由表):包括左路由表和右路由表。每个路由表的每个条目都有一个指向同层级节点的链接和其相关信息。
Bound(边界):包括索引上界(Upper bound)和索引下界(Lower bound),用来进行数据的搜索。
这样说,大家可能不太理解,下面我讲进行特别说明。
当节点在Baton Tree上的位置确定后,其序号也跟着确定。
每个节点的路由表的条目数(也是节点链接数)是固定的,由其所在层级L和序号N决定。如果当前位置无节点,那么链接标记为null。如果一个节点的某个路由表都没有null,称这个路由表是满的。
路由表每个链接节点的序号跟源节点的序号相差2^i(i为非负整数),如果是左路由表,那么比源节点序号小;如果是右路由表,那么比源节点序号大。
接下来,我会举个例子来展示baton tree。
在下面这幅图中,根节点为a,层级为0,然后层级不断往下递增。节点p的序号为7而不是1,因为它在这个层级的位置从左到右数的话是第七个。看一下节点m,它的左路由表的链接可以根据比它序号小2^i(i为非负整数)来判断,右路由表则与左路由表相反。节点l的序号为5,比m的序号小1,也就是2^0,所以l在m的左路由表中。同理,可以看到节点k比吗序号小2,节点i比m的序号小4。比节点m的序号小8的节点是不可能存在的,因为序号在层级L中只分配有1到2^L。看一下节点p,由图可以看出,p的左路由表应该存在3个链接,但是p的左边都没有节点,所以它的左路由表的链接都为null。而p的右路由表有4个链接,但是只有两个链接为非null,即存在一个链接指向q和一个链接指向s。
Baton Tree的定理
定理一:
The tree is a balanced tree if every node in the tree that has a child also has both its left and right routing tables full.
如果树中每个有子节点的节点的左右路由表也都是满的,那么这棵树就是平衡树。
关于定理一的证明如下:
(1)加入节点:向层级为L的节点x添加子节点,以x为根的树仍是平衡的,但以x的祖先节点为根的树不一定平衡。从x的处于任意层级i的祖先节点y来看,假设x位于y的左子树。如果左子树的深度从L变成了L + 1,以“有子节点的节点的左右路由表也都是满的”为前提,一定有某个节点z,处于x的右路由表中,且处于y的右子树。因为节点x与y的右子树的最远距离为2^( L - 1 - i ),而以y为根的树在层级L有2^( L - i )个位置可以存放节点。x的序号 N + 2^( L - 1 - i ) <= 2^( L - i )恒成立。右子树深度至少为L,左子树变化不会导致不平衡。如果左子树深度不变,那么根本不会产生不平衡。
(2)删除节点:从树中删除一个节点u,它是层级为L的节点x的子节点。从x的处于任意层级i的祖先节点y来看,假设x位于y的左子树。如果左子树的深度从L+1变成了L,以“有子节点的节点的左右路由表也都是满的”为前提,一定有某个节点z,处于x的右路由表中,且处于y的右子树。当右子树深度至少为L+2时,有两种情况。
情况一:z有一个子节点v,且在u的右路由表中,v同时还有子节点,由此可知u也在v的左路由表中。那么在“有子节点的节点的左右路由表也都是满的”这个前提下,u不可能被删除,否则v的左路由表就不会是满的。所以此时树仍然是平衡的。
情况二:不存在满足这样条件的节点v。这就意味着在y的右子树的层级为L+2的任意一个节点w,都会有一个在L+1的父节点s,这个父节点s的左路由表必定有一个节点h,h在y的左子树上,与u是同层级的。所以此时删除u并不会影响左子树的深度。所以此时树仍然是平衡的。
当右子树深度少于L+2时,节点u是否删除都不会影响平衡。
(3)总结:在前面的证明中,从x的任意一个祖先节点看,无论是删除x的子节点或者是给x加入子节点,只要是在满足“有子节点的节点的左右路由表也都是满的”的前提下,树都是平衡的,所以定理一是正确的。
接下来是定理二:
定理二:
If a node, say x, contains a link to another node, say y, in its left or right routing tables, the parent node of x must also contain a link to the parent node of y unless the same node is parent of both x and y.
如果一个节点x的左路由表或右路由表包含一个节点y,那么x的父节点的左路由表或右路由表也应该包含y的父节点,除非x和y的父节点是同一个。
证明如下:
设X为节点x的序号,设x的父节点为w,序号为W。如果x是w的右子节点,那么X为偶数,且W = X / 2。如果x是w的左子节点,那么X为奇数,且W = (X +1)/ 2。同样,设节点y序号为Y,父节点为z,序号为Z。接下来有三种情况:
情况一:假设y到x的距离至少为2。那么Y = X + 2^k或Y = X - 2^k 对于整数k>1成立。那么由此可得,Z = W + 2^(k-1)或Z = W - 2^(k-1)。所以z一定在w的路由表中。定理二成立。
情况二:假设y与x距离为1,且互为兄弟节点。那么y与x有同一个父节点,定理二仍然成立。
情况三:假设y与x距离为1,但不是兄弟节点。但是由于Y = X +1 或Y = X -1,所以Z = W +1或Z = W - 1。由此可知,z一定在w的路由表中。此时定理二仍然成立。
节点加入和节点离开的处理
节点加入
节点加入有两个阶段:
阶段一:确定新节点应该加入的位置;
阶段二:将新节点在指定的位置中加入网络。
接下来介绍第一阶段:
第一步:假设节点x收到一个加入请求,则进行判断,如果其路由表都满了,且仍缺少子节点,则可以接受新节点为子节点。否则进行下一步。
第二步:进行判断,如果是因为路由表没有满,则将加入请求传给x的父节点。如果是因为不缺子节点,那么就在x的路由表中找到一个缺少子节点的节点y,将加入请求传给y。如果不存在这样的y,就将加入请求传给自己的邻接节点。节点收到加入请求后,节点进行上一步的处理。
接下来我们看下面一个节点加入的例子:
假设节点u想要加入网络,它向节点b发送加入请求,如图所示。 然后将请求转发给p,p是它的邻接节点。由于p的路由表未满,它将请求转发给它的父节点j,反过来,j检查它的路由表,并将请求转发给没有足够子节点的 邻居节点n。最后,n接受u作为它的子节点。
节点加入的第二阶段如下:
当一个节点x接受新的节点y作为它的子节点时,它将一半的内容 分割给它的子节点。换句话说,与x相关的范围被划分为自身和它的新子节点。
具体来说,如果y成为x的左子节点,x也会将其指向z的左邻接链接发送给y, 并将其左邻接链接更新为y,然后y会创建其指向z的左邻接链接和指向x的右邻接链接,并且还通知z,z会更新其右邻接节点为y。
当y成为x的右子节点时,则进行的处理与y成为x的左子节点时的处理一样,只不过左邻接链接换成右邻接链接,而右邻接链接换成左邻接链接。
节点离开
只有叶子节点可以自愿离开网络,而且只有在它们的离开不会扰乱树的平衡的情况下。在其他情况下,希望离开网络的节点必须为自己找到一个替代者,这个替代者只会是叶子节点,而且这个叶子节点的缺席不会影响树的平衡。
接下来会分析节点离开的三种情况:
第一种情况:如果一个叶子节点想要离开网络或者成为接收到一个寻找替代节点请求,并且它的路由表中的节点均没有子节点,它可以离开网络或替代其他节点而不影响树的平衡。
第二种情况:如果一个叶子节点希望离开网络或者接收到一个寻找替代节点请求,但是在它的路由表中有带子节点的邻居节点,因此它不可能成为替代节点,它需要通过向它的某个邻居节点的子节点发送一个寻找替代节点请求来找到一个节点来替换它。
第三种情况:如果非叶子节点希望离开网络或者接收到一个寻找替代节点请求,则通过向其相邻节点之一发送寻找替代节点请求,然后逐渐深入地找到一个节点来替换它。
无论是那种情况,离开的节点必须将它的所有内容,以及它所负责的索引值范围传递给它的父节点,如果它是左子节点则传递它的左相邻链路给父节点,如果它是右子节点则传递它的右相邻链路给父节点。而且离开的节点要向它的路由表里面的节点发送离开消息以更新它们的路由表。父节点在接收到离开节点发来的内容后,也需要向自己路由表里的节点发送消息,通知节点自己有了新的内容和子节点,同时通知自己新的邻接节点。
接下来举一个节点离开的例子:
例子:如图中的节点b,如果它想离开网络,就必须找到一个叶子节点作为替代。 b创建一个寻找替代节点的请求,发送给它的相邻节点j,j检查它的路由表,意识到有一些有子节点的邻居节点,j因此将请求转发给r, r是j的邻居节点的子节点,在r处,由于它没有任何子节点,也没有有子节点的邻居节点,r可以安全地替换b。
Baton Tree的重组
节点加入的重组
在上面的描述中,当节点的离开导致不平衡时,需要找到一个替代节点;当节点加入网络导致不平衡时,会被强制转移到树的其他部分。但是这种方法并不能够满足全部情况,此时有另一种方法来处理节点的加入和离开,这个方法就是网络重组。
第一步:当一个节点y想要加入网络成为x的子节点时,如果违背了定理一,那么就会启动网络重组。假设重组是向右进行的,也就是沿着中序遍历的顺序进行重组。
第二步:如果y想要成为x的左子节点,那么为了平衡树的结构,y会替换x的位置,设z为x的右邻接节点,那么x会替换z的位置。如果y想要成为x的右子节点,那么y就直接替换z的位置,x保持不变。
第三步:z检查它的右邻接节点t,看看t的左子节点是否为空。如果是空的,且向t添加左子节点并不影响树的平衡,那么z将成为t的左子节点,重组过程结束。如果z不能成为t的左子节点,那么z会替换t的位置,t会重复与z一样的寻找新位置的操作。
接下来举一个节点加入的重组例子:
节点离开的重组
第一步:当一个节点y离开网络,导致树不平衡时,如果y是叶节点,那么y的父节点x会开始重组过程;如果y是非叶节点,那么y仍需要寻找一个替换节点。假设重组是向左进行的,也就是沿着中序遍历相反的顺序进行重组。
第二步:如果y是x的右子节点,为了平衡树的结构,x必须顶替y的位置,x的左邻接节点z接着来顶替x的位置。如果y是x的左子节点,那么z就是y的左邻接节点,且z会直接顶替y的位置,x保持不变。
第三步:如果z到新位置后树已平衡,那么重组结束。如果z到新位置后树未平衡,那么z 的左邻接节点t会顶替z原来位置,并继续判断是否平衡,就这样一直替换到树平衡为止。
接下来我们举一个节点离开的重组的例子:
Baton Tree的查询索引
在对等网络中,每个节点都存有自己的数值和内容,整个网络的查询索引会根据中序遍历得到的节点序列均匀地分给节点。如果我们所需要的内容不在目标网络节点里面,那么就需要到其他网络节点上寻找了。正常来说,可以根据中序遍历得到的顺序进行寻找,但是这样会遍历从目标网络节点到满足条件的网络节点之间的所有节点,十分损耗效率。接下来,另一种快速查询的算法将会被介绍。
第一步:在节点n发起查询请求,输入索引v,先进行判断。
第二步:如果v处于n的索引范围内(n的索引下界 <= v <= n的索引上界),那么就会在节点n里面搜索。如果v不在n的索引范围内,就会跑到其他节点进行搜索。
第三步:v跑到其他节点搜索要分成两种情况,第一种是v小于n的索引下界,第二种是v大于n的索引上界。
第一种情况:第一种情况:如果v小于n的搜索下界,那么会在n的左路由表里面找到一个节点r,满足v <= r的搜索上界,且r是在满足这条件的节点中离n最远的。然后把查询请求传给r,r重复上面n的操作。如果不存在这个节点r,那么n会把查询请求传给它的左邻接节点z,z也会重复上面n的操作。就这样,直至查询成功。
第二种情况:第二种情况:如果v大于n的搜索上界,那么会在n的右路由表里面找到一个节点r,满足v >= r的搜索下界,且r是在满足这条件的节点中离n最远的。然后把查询请求传给r,r重复上面n的操作。如果不存在这个节点r,那么n会把查询请求传给它的右邻接节点z,z也会重复上面n的操作。就这样,直至查询成功。
接下来我们来介绍一个索引的例子:
关于Baton Tree的介绍就这样结束了。