[算法][Python]随机生成一棵具有N个节点的二叉树

查了一圈网上现有的资料,基本都是“天下文章一大抄”或者过时、甚至无法运行的代码,也没有讲明原理,代码质量烂得一比,怒而亲自动手。


思路很简单:

  1. 初始化N个树节点,每次随机从中选出一个父节点和子节点,随机决定子节点作为父节点的左叶或右叶;
  2. 特别的,使用并查集来避免出现构建回环的情况;(并查集的相关知识请参考《算法4》)
  3. 考虑到每个节点最多只会有一个入度和两个出度,因此可以添加父、子节点的待选列表,解决随机碰撞影响效率的问题。

给出对树节点的结构定义:

class TreeNode:
    def __init__(self, value=None):
        self.v = value
        self.left, self.right = None, None
        self.father = None

上述思路的具体实现,请参考以下代码及详实的注释来理解:

def build_random_tree(n):
    """
    构建一棵随机树
    :param n: 树的节点
    :return: 根节点,和所有节点的list;根节点默认为arr的第一个元素
    """
    assert n > 1
    import random as r
    all_nodes = [[0, TreeNode(i + 1)] for i in range(n)]  # (出度, 节点)
    in_nodes = [i for i in range(n)]  # in < 1 的点,待选作为子节点的列表
    out_nodes = [i for i in range(n)]  # out < 2 的点,待选作为父节点的列表
    uf = [i for i in range(n)]  # 并查集联通表

    def uf_find(x):  # 并查集辅助函数
        return x if x == uf[x] else uf_find(uf[x])

    def uf_union(i, j):  # 并查集辅助函数
        if r.random() > 0.5:  # 均衡并查集的查找树高
            i, j = j, i
        uf[uf_find(i)] = uf_find(j)

    while len(in_nodes) > 1:
        fa_id = out_nodes[r.randint(0, len(out_nodes) - 1)]  # 任意挑选一个节点作为父节点
        ch_id = in_nodes[r.randint(0, len(in_nodes) - 1)]  # 为其随机挑选一个子节点

        if uf_find(fa_id) == uf_find(ch_id):  # 防止回环
            continue

        fa, ch = all_nodes[fa_id], all_nodes[ch_id]

        if fa[0] == 0:  # 父节点出度为0时,随机决定ch其成为左/右节点
            if r.random() > 0.5:
                fa[1].left = ch[1]
            else:
                fa[1].right = ch[1]
            fa[0] += 1  # 出度加一
        elif fa[0] == 1:  # 父节点出度为1时,ch成为其不为空的子节点
            if fa[1].left:
                fa[1].right = ch[1]
            elif fa[1].right:
                fa[1].left = ch[1]
            out_nodes.remove(fa_id)  # 同时,fa已拥有左右儿子,可以从待选父节点中删去

        ch[1].father = fa[1]  # 构建父指针
        uf_union(fa_id, ch_id)  # 在并查集中联通父子节点

        in_nodes.remove(ch_id)  # 从合法子节点中删去

    root_id = in_nodes[0]  # 入节点列表中唯一剩下的节点就是根节点
    nodes = [all_nodes[root_id][1]]
    for i, tree_node in all_nodes:  # 构建节点列表
        if i != root_id:
            nodes.append(tree_node)
    return nodes[0], nodes

你可能感兴趣的:(Python,Matlab,算法,面试,算法,二叉树,python,数据结构)