如何将金字塔转换为二叉树

时间:2021-03-11 17:09:55

标签: python binary-tree

假设我有一个像这样的金字塔,但更大

     2
    4 9
   4 9 6
  7 7 8 9

并希望将其转换为二叉树,这意味着我们实际上想要一棵这样的树:

            2
       4         9
    4    9     9    6
   7 7  7  8  7  8  8 9

在列表格式中,结果是

2,4,9,4,9,9,6,7,7,7,8,7,8,8,9

我尝试了以下方法,但它仅适用于长度为 4 的树。作为输入,我在 txt 文件中取了一棵树。

def give_input(name):
    index = 0
    lis_of_listas = []
    f = open(name, "r")
    for x in f:
        x = x.replace(' ', '')
        x = x.replace('\n', '')
        lista = [int(i) for i in list(x)]
        if (index > 1 and index % 2 == 0):
            podlista = lista[1:-1]
            podpodlista = []
            for i in podlista:
                podpodlista.append(i)
                podpodlista.append(i)
            podpodlista.append(lista[-1])
            podpodlista.insert(0, lista[0])
        elif (index > 1 and index % 2 == 1):
            podlista = lista[1:-1]
            print(len(podlista)/2)
            podlista1 = podlista[0:int(len(podlista) / 2)]
            podlista2 = podlista[int(len(podlista) / 2):len(podlista)]
            podpodlista = []
            for i in podlista1:
                podpodlista.append(i)
                podpodlista.append(i)
            podpodlista.append(podlista1[-1])
            podpodlista.append(podlista2[0])
            for j in podlista2:
                podpodlista.append(j)
                podpodlista.append(j)
            podpodlista.append(lista[-1])
            podpodlista.insert(0, lista[0])
        if index <= 1:
            lis_of_listas.append(lista)
        else:
            lis_of_listas.append(podpodlista)
        index += 1
    return [item for sublist in lis_of_listas for item in sublist]

3 个答案:

答案 0 :(得分:1)

我们可以看到,对于父行中索引为 j 的每个元素,我们需要在下一行中取出索引为 jj+1 的元素:

illustration

例如,要在二叉树中从索引为 ix = [0, 1] 的第 2 行到第 3 行,我们将获取第 2 行中的索引并将它们中的每一个拆分为其子节点 j => [j, j+1],使其{ {1}} 在第 3 行。

同样,可以通过将具有相同逻辑的 ix = [0, 1, 1, 2] 拆分为 ix = [0, 1, 1, 2],依此类推,从第 3 行计算第 4 行。

基于这些索引数组,我们可以创建一个二叉树:

binary-tree

现在要获得二叉树的实际列表表示,剩下的就是连接索引列表并获取这些索引处的值。

以下是如何在代码中完成此操作:

[0, 1, 1, 2, 1, 2, 2, 3]

输出:

s = \
"""  2
    4 9
   4 9 6
  7 7 8 9"""

# convert string to a list of lists (row, values)
# l = [['2'], ['4', '9'], ['4', '9', '6'], ['7', '7', '8', '9']]
l = [x.split() for x in s.split('\n')]


# init
out = [l[0][0]]   # store output here, init with root
ix = [0]          # indices of the previous row

# loop
for i in range(len(l)-1):
    ix_new = []              # indices for the new row
                             # if parent has index (j), then
                             # - left child will have index (j)
                             # - right child will have index (j+1)
    for j in ix:
        ix_new.append(j)     # left
        ix_new.append(j+1)   # right
    ix = ix_new
    
    # appending elements with corresponding indices to out:
    for k in ix_new:
        out.append(l[i+1][k])

out

附言对于那些有兴趣从列表格式中获得树的可视化表示的人,请参阅 this question

答案 1 :(得分:0)

这是一个简单的变异方法:

from dataclasses import dataclass

@dataclass
class Node:
    value: int
    left: object
    rite: object

def tree_from_list(l, depth):
    l = iter(l)
    root = Node(next(l), None, None)
    leaves = [root]
    for _ in range(depth):
        new_leaves = [Node(next(l), None, None)]
        for leaf in leaves:
            leaf.left = new_leaves[-1]
            leaf.rite = Node(next(l), None, None)
            new_leaves.append(leaf.rite)
        leaves = new_leaves
    return root

以上对树的左右分支使用相同的对象,从而节省内存。

用法:

def print_tree(node, indent=''):
    if node is None:
        return
    print(indent + str(node.value))
    print_tree(node.left, indent=indent+'  ')
    print_tree(node.rite, indent=indent+'  ')

print_tree(tree_from_list([
          1,
        2,  3,
      4,  5,  6,
], depth=2))

这应该打印:

1
  2
    4
    5
  3
    6
    7

答案 2 :(得分:0)

解决方案比您想象的要容易得多。首先,将您的金字塔视为一个图表,其中级别 l 和索引 i 上的节点与两个节点链接

  • 级别 l + 1,索引 i

  • 级别 l + 1,索引 i + 1

现在您以预排序的方式从 0 级的唯一节点开始探索您的图形,您会注意到可以在许多路径上找到相同的节点,这对应于二叉树中的重复条目。例如,要查找节点 8,有以下路径:

    2
   /
  4 9
   \
 4  9 6
     \
7 7   8 9
   2
    \
  4  9
    /
 4 9 6
    \
7 7  8 9
   2
    \
  4  9
     |
 4 9 6
     |
7 7  8 9

我只是意识到如果我向您展示代码可能会更容易:

pyramid = [(2,), (4,9), (4,9,6), (6,7,8,9), (1,2,3,4,5)]
final_tree = [[] for _ in range(len(pyramid))]

def pyramid_visit(pyramid, cur_lvl, cur_index):
    if cur_lvl == len(pyramid):
        return
    
    final_tree[cur_lvl].append(pyramid[cur_lvl][cur_index])
    pyramid_visit(pyramid, cur_lvl + 1, cur_index)
    pyramid_visit(pyramid, cur_lvl + 1, cur_index + 1)

pyramid_visit(pyramid, 0, 0)
print(final_tree)

然后返回:

[[2], [4, 9], [4, 9, 9, 6], [6, 7, 7, 8, 7, 8, 8, 9], [1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5]] 

尝试使用 3 层高的金字塔,非常类似于一棵树:

    2
   / \
  4   9
 / \ / \
4   9   6

接下来添加一个级别,并确定 2 个底层金字塔:

      1                 1
     /                   \
    2   3             2   3
   / \                   / \
  4   9   4         4   9   4
 / \ / \               / \ / \
4   9   6   5     4   9   6   5

您应该清楚地看到 2 个子树,这是我的解决方案背后的递归推理。