简体   繁体   English

Python-将n元树转换为二叉树

[英]Python - Converting an n-ary tree to a binary tree

class Tree:

        def __init__(self, new_key):
    self.__key = new_key    # Root key value
    self.__children = []     # List of children
    self.__num_of_descendants = 0 # Number of Descendants of this node    

# Prints the given tree
def printTree(self):
    return self.printTreeGivenPrefix("", True)   

# Prints the given tree with the given prefix for the line
# last_child indicates whether the node is the last of its parent"s child
# or not
def printTreeGivenPrefix(self, line_prefix, last_child):
    print(line_prefix, end="")
    if last_child:
        print("â””--> ", end="")
    else:
        print("|--> ", end="")
    print(self.__key)

    if len(self.__children) > 0:
        next_pre = line_prefix
        if last_child:
            next_pre += "     "
        else:
            next_pre += "|    "
        for child_index in range(len(self.__children)-1):
            self.__children[child_index].\
                printTreeGivenPrefix(next_pre, False)
        self.__children[-1].printTreeGivenPrefix(next_pre, True)

def __repr__(self):
    return "[" + str(self.__key) + "".join(
        [ repr(child) for child in self.__children ]) + "]"

# This static function will load a tree with the format of below:
# [root[child_1][child_2]...[child_n]]
# Each child_i can be a tree with the above format, too
# pos is the position in the given string
@staticmethod
def loadTree(tree_str, pos = 0):
    new_node = None
    while pos < len(tree_str):
        if tree_str[pos] == "[":
            pos += 1
            new_node = Tree(tree_str[pos])
            while pos < len(tree_str) and tree_str[pos + 1] != "]":
                pos += 1
                child_tree, pos = Tree.loadTree(tree_str, pos)
                if child_tree:
                    new_node.__children.append(child_tree)
                    new_node.__num_of_descendants += \
                        1 + child_tree.__num_of_descendants
            return new_node, pos + 1
        else:
            pos += 1
    return new_node, pos

def find_largest(self):
    if self.__num_of_descendants == 1:
        return self.__children[0]

    else:
        largest_child = self.__children[0]
        for child in self.__children:
            if child.__num_of_descendants > \
               largest_child.__num_of_descendants:
                largest_child = child
            if child.__num_of_descendants == \
               largest_child.__num_of_descendants:
                if child.__key > largest_child.__key:
                    largest_child = child
    return largest_child

def convert_to_binary_tree(self):
    if self.__num_of_descendants != 0:
        if self.__num_of_descendants < 3:
            for child in self.__children:
                child.convert_to_binary_tree()

        if self.__num_of_descendants > 2:
            left_child = self.__children[0]
            for child in self.__children[1:]:
                if len(child.__children) > len(left_child.__children):
                    left_child = child
                elif len(child.__children) == len(left_child.__children):
                    if child.__key > left_child.__key:
                        left_child = child
            self.__children.remove(left_child)
            self.__num_of_descendants -= 1

            right_child = self.__children[0]
            for child in self.__children[1:]:
                if len(child.__children) > len(right_child.__children):
                    right_child = child
                elif len(child.__children) == len(right_child.__children):
                    if child.__key > right_child.__key:
                        right_child = child
            self.__children.remove(right_child)
            self.__num_of_descendants -= 1
            print(self.__num_of_descendants)
            print(self.__children)
            print(left_child)
            print(right_child)

            #Move remaining children two either left_child or right_child.
            while self.__num_of_descendants != 0:
                largest_child = self.find_largest()
                print(largest_child)
                if left_child.__num_of_descendants < \
                   right_child.__num_of_descendants:
                    left_child.__children.append(largest_child)
                    left_child.__num_of_descendants += 1
                    self.__children.remove(largest_child)
                    self.__num_of_descendants -= 1                        

                elif left_child.__num_of_descendants > \
                   right_child.__num_of_descendants:
                    right_child.__children.append(largest_child)
                    right_child.__num_of_descendants += 1
                    self.__children.remove(largest_child)
                    self.__num_of_descendants -= 1                        

                elif left_child.__num_of_descendants == \
                   right_child.__num_of_descendants:
                    if left_child.__key > right_child.__key:
                        left_child.__children.append(largest_child)
                        left_child.__num_of_descendants += 1
                        self.__children.remove(largest_child)
                        self.__num_of_descendants -= 1                            
                    else:
                        right_child.__children.append(largest_child)
                        right_child.__num_of_descendants += 1
                        self.__children.remove(largest_child)
                        self.__num_of_descendants -= 1
            #Now run recursion on left and right binary children.
            self.__children.append(left_child)
            self.__children.append(right_child)
            self.__num_of_descendants = 2
            print(self.__children)
            for child in self.__children:
                child.convert_to_binary_tree()
def main():
    tree, processed_chars = Tree.loadTree('[z[y][x][w][v]]]')
    tree.convert_to_binary_tree()
    tree.printTree()
    print(tree)

if __name__ == "__main__":
    main()

I have to convert a given tree into a binary tree. 我必须将给定的树转换为二叉树。 If a node in the tree has more than 2 children, I have to assign the child with the most descendants as the left node and the child with the second largest number of descendents as the right child. 如果树中的一个节点有两个以上的子节点,则必须将后代最多的子节点分配为左节点,后代数目第二大的子节点分配为右子节点。 The remaining children are added as following: 1) Take child with largest number of descendants 2) Add it to Left/Right node. 其余子项的添加如下:1)接收具有最大后代数的子项2)将其添加到“左/右”节点。 Whichever has fewer children at that time. 那个时候孩子少的那个。

*If at any time I need to select the child with the largest number of descendants, but there are two+ with the same number of descendents, I take the one with the larger key value. *如果在任何时候我都需要选择后代数量最多的子代,但后代数量相同的有两个+,则我选择键值较大的子代。

I get a print out like this...
2 #Number of 'z' children after left and right node chosen.
[[w], [v]] #Children of 'z'
[y] #Binary left child of 'z'
[x] #Binary right child of 'z'
[w] #This is a bug. It should be choosing 'v' as larger child of 'z' and assigning it to left child 'y'
[v] #This is a bug. see above.
[[y[w]], [x[v]]] #These are the children of node 'z'
â””--> z #schematic of binary tree
     |--> y
     |    â””--> w
     â””--> x
          â””--> v
[z[y[w]][x[v]]] #final binary tree 

DSM's comment helped me see what is going on. DSM的评论帮助我了解了发生的情况。 After you pick left_child and right_child in the first parts of your convert_to_binary_tree method, you're not removing them from the list of children. convert_to_binary_tree方法的第一部分中选择left_childright_child之后,您没有将它们从子级列表中删除。 This means that later, when you go to add all of the current node's children into new parents, you're adding the left and right children to themselves (or each other). 这意味着以后,当您将当前节点的所有子代添加到新的父代中时,您将向左或向右添加自己的子代(或彼此添加)。 When you recurse into those children, you can end up infinitely looping. 当您递归到那些孩子时,您可能会无限循环。

I don't really understand the logic of your left_child and right_child selections, so I don't have fixed code to suggest to you. 我不太了解您选择left_childright_child的逻辑,因此我没有固定的代码可以建议您。 A quick but ugly fix would be to put a if child in (left_child, right_child): continue statement at the top of the for loop where you're assigning the other children to new parents. 一个快速但丑陋的解决方法是将if child in (left_child, right_child): continue for循环顶部的if child in (left_child, right_child): continue语句,在该循环中您将其他子项分配给新的父项。

Note that there's another bug in your current code, where the descendent counts for the left and right children will become incorrect. 请注意,当前代码中还有另一个错误,其中左右子级的后代计数将变得不正确。 That's because you're not updating the count when you push some of their former siblings into them as children. 那是因为当您将一些以前的兄弟姐妹作为孩子推入他们时,您并没有更新计数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM