我正在调试一个算法任务,为了测试的目的,我想生成一个二进制树,其中n个顶点以0为根,换句话说,生成一对对,这样如果序列中的第i对是(a,b),那么第i个节点的左子节点是a,右子节点是b,除非a(或b)= -1,那么第i个节点没有左(或右)子节点。 (例如,序列:(1,2),( - 1,-1),( - 1,-1)是具有根(0)的树,以及两个子(1和2)) 我写了下面的python递归函数,其中listAdd是所需的对列表,listDel是尚未生成的所有顶点,n是当前正在查看的节点:
def generateTree(listAdd, listDel, n):
if not listDel:
return
ifLeft = bool(randint(0,1))
ifRight = bool(randint(0,1))
if ifLeft:
chosen = choice(listDel)
listDel.remove(chosen)
listAdd[n] = (chosen, listAdd[n][1])
generateTree(listAdd, listDel, chosen)
else:
listAdd[n] = (-1, listAdd[n][1])
if not listDel:
return
if ifRight:
chosen = choice(listDel)
listDel.remove(chosen)
listAdd[n] = (listAdd[n][0], chosen)
generateTree(listAdd, listDel, chosen)
else:
listAdd[n] = (listAdd[n][0], -1)
然而,在编写它时,我注意到这不能正常工作,因为如果ifLeft和ifRight都是假的,那么函数可能只在一个顶点之后停止。
所以我的问题是,生成这样一棵树的好方法是什么?我不需要它在python中,因为它只用于生成输入文件,我只需要一个好的算法,或者另一种表示树的方法,这样它就更容易生成并可以转换成所需的格式。
答案 0 :(得分:1)
一种简单的迭代方法:
import random
# start with root node and no children
tree = [[-1, -1]]
free_edges = [(0, 0), (0, 1)]
n = 4 # how many nodes do you want?
while len(tree) < n:
e = random.choice(free_edges) # select a free edge
node, child = e
assert tree[node][child] == -1 # make sure we made no mistake
k = len(tree) # index of new node
tree.append([-1, -1]) # add new node
tree[node][child] = k # set new node as child of an old node
free_edges.extend([(k, 0), (k, 1)]) # new node has two free edges
free_edges.remove(e) # edge is no longer free
print(tree)
# [[1, 2], [-1, 3], [-1, -1], [-1, -1]]
随机将新节点插入树中,直到达到节点总数。
自由边用红色表示。在每个步骤中,随机选择一个自由边。节点位于该边缘,此节点向树中添加两个新的自由边。
此过程不会生成特定的节点顺序。可以先将左孩子或右孩子插入树中。即你可能得到像[(2, 1), (-1, -1), (-1, -1)]
这样的序列。如果这是一个问题,可能需要重新排序节点。
我认为这种方法平均会产生比不平衡树更平衡的树,因为较老的边缘被更频繁地考虑。您可以选择不插入新节点,仅以一定概率移除自由边。这应该将趋势转向更深的树木。只需确保在完成之前不要移除所有边缘:)
答案 1 :(得分:0)
当你在树的右端同时仍然有一些自由元素时,你不能得到双零,这是正确的吗?
所以我认为您需要确定何时发生这种情况,并强制重新检查。我能想到两种方法。
如果你给它一个根,那就做一个检查你在哪里的函数。
创建一个数组,并使用0
,1
或"L"
,"R"
填充该数组。如果你有
ifLeft == ifRight == 0
len(listDel) > 0
和If "L" not in check_array
if len(check_array) == sum(check_array)
重新加载整个东西。
顺便说一句,您必须在函数开头将检查添加到数组中并在结尾处将其删除。所以它的长度将是这样的:
0,1,2,3,4,3,2,3,4,5,4,3,2,1,2,3,2,1,0
check_array = []
def generateTree(listAdd, listDel, n):
if not listDel:
return
ifLeft = bool(randint(0,1))
ifRight = bool(randint(0,1))
if (ifLeft + ifRight == 0) and (
"L" not in checked_array) and (
len(listDel) > 0):
// Force a 1, or use randint (you need a while-loop for it)
ifLeft = 1
if ifLeft:
check_array.push("L")
chosen = choice(listDel)
listDel.remove(chosen)
listAdd[n] = (chosen, listAdd[n][1])
generateTree(listAdd, listDel, chosen)
check_array = check_array[:-1]
else:
listAdd[n] = (-1, listAdd[n][1])
if not listDel:
return
if ifRight:
check_array.push("R")
chosen = choice(listDel)
listDel.remove(chosen)
listAdd[n] = (listAdd[n][0], chosen)
generateTree(listAdd, listDel, chosen)
check_array = check_array[:-1]
else:
listAdd[n] = (listAdd[n][0], -1)