파이썬은 일반 이진 트리를 구현합니다.

파이썬은 일반 이진 트리를 구현합니다.

바이너리 트리는 노드 당 최대 2 개의 하위 트리가있는 트리 구조입니다.이 기사에서는 Python을 사용하여 일반 바이너리 트리를 구현합니다.

바이너리 트리에 대한 소개는 https://blog.csdn.net/weixin_43790276/article/details/104737870을 참조하십시오.

하나, 노드 클래스 구현

모든 트리 구조는 하나의 노드로 구성되어 있으며이 기사에서는 체인 방식을 사용하여 이진 트리를 구현하므로 먼저 노드 클래스를 구현합니다.

# coding=utf-8
class Node(object):
    """节点类"""
    def __init__(self, data, left_child=None, right_child=None):
        self.data = data
        self.parent = None
        self.left_child = left_child
        self.right_child = right_child

이진 트리에 노드를 추가 할 때 먼저 노드를 생성해야합니다. 노드 클래스가 있으면 노드 클래스의 인스턴스를 인스턴스화하십시오. 노드가 초기화되면 격리 된 노드입니다. 상위 노드, 왼쪽 하위 노드 , 그리고 가리키는 오른쪽 자식 노드는 모두 공기입니다. 노드가 트리에 "매달려"(트리에 추가됨) 트리의 일부가됩니다.

둘째, 이진 트리 클래스를 실현하십시오.

이진 트리 클래스 BinaryTree를 구현하려면 이진 트리를 만들 때 BinaryTree 클래스의 인스턴스를 생성합니다.

class BinaryTree(object):
    """二叉树类"""
    def __init__(self):
        self.__root = None
        self.prefix_branch = '├'
        self.prefix_trunk = '|'
        self.prefix_leaf = '└'
        self.prefix_empty = ''
        self.prefix_left = '─L─'
        self.prefix_right = '─R─'

    def is_empty(self):
        return not self.__root

    @property
    def root(self):
        return self.__root

    @root.setter
    def root(self, data):
        self.__root = Node(data)

    def show_tree(self):
        if self.is_empty():
            print('空二叉树')
            return
        print('-' * 20)
        print(self.__root.data)
        self.__print_tree(self.__root)
        print('-' * 20)

    def __print_tree(self, node, prefix=None):
        if prefix is None:
            prefix, prefix_left_child = '', ''
        else:
            prefix = prefix.replace(self.prefix_branch, self.prefix_trunk)
            prefix = prefix.replace(self.prefix_leaf, self.prefix_empty)
            prefix_left_child = prefix.replace(self.prefix_leaf, self.prefix_empty)
        if self.has_child(node):
            if node.right_child is not None:
                print(prefix + self.prefix_branch + self.prefix_right + str(node.right_child.data))
                if self.has_child(node.right_child):
                    self.__print_tree(node.right_child, prefix + self.prefix_branch + ' ')
            else:
                print(prefix + self.prefix_branch + self.prefix_right)
            if node.left_child is not None:
                print(prefix + self.prefix_leaf + self.prefix_left + str(node.left_child.data))
                if self.has_child(node.left_child):
                    prefix_left_child += '  '
                    self.__print_tree(node.left_child, self.prefix_leaf + prefix_left_child)
            else:
                print(prefix + self.prefix_leaf + self.prefix_left)

    def has_child(self, node):
        return node.left_child is not None or node.right_child is not None

    def __str__(self):
        return str(self.__class__)

이진 트리의 경우 트리의 루트 노드 (Root)가 먼저 발견되면 노드의 부모-자식 관계에 따라 모든 노드를 차례로 찾을 수 있으므로 이진 트리를 초기화 할 때 트리의 루트 노드에 먼저 추가하고 이진 트리에 노드를 추가하지 않습니다. 중간 시간에 트리는 빈 이진 트리이고 트리의 루트는 비어 있습니다.

바이너리 트리 초기화시 트리의 루트는 private 속성으로 설정되며, 이는 루트 노드의 안정성 확보를 위해 필요합니다. 그러나 인스턴스 개체를 통해 트리의 루트를 조작해야하므로 @property와 @ root.setter를 사용하여 이진 트리의 루트 노드를 가져 오거나 설정하는 인스턴스 개체에 대한 한 쌍의 메서드를 제공합니다.

동시에 이진 트리가 비어 있는지 판단하는 is_empty () 메서드와 트리 구조에 따라 이진 트리를 인쇄하는 show_tree () 메서드도 구현되어 있습니다. 이진 트리. https://blog.csdn.net/weixin_43790276/article/details/104033490을 참조 할 수 있습니다.

셋, 이진 트리에 노드 추가

완전한 이진 트리에 추가 된 노드는 위에서 아래로, 왼쪽에서 오른쪽으로 추가됩니다. 일반 이진 트리는 노드를 불규칙적으로 추가합니다. 노드 추가는 요청에 따라 추가됩니다. 이진 트리의 하위 노드는 왼쪽 하위 노드와 오른쪽으로 구분됩니다. 자식 노드, 그래서 노드를 추가하는 두 가지 방법의 실현은 각각 왼쪽 자식 노드와 오른쪽 자식 노드를 추가하는 것입니다.

    def add_left_child(self, parent, value):
        """添加左子节点"""
        if parent is None:
            print("父节点不存在")
            return
        if parent.left_child is not None:
            print("父节点已有左子节点")
            return
        node = value if isinstance(value, Node) else Node(value)
        parent.left_child = node
        node.parent = parent

    def add_right_child(self, parent, value):
        """添加右子节点"""
        if parent is None:
            print("父节点不存在")
            return
        if parent.right_child is not None:
            print("父节点已有右子节点")
            return
        node = value if isinstance(value, Node) else Node(value)
        parent.right_child = node
        node.parent = parent

add_left_child (parent, value) : 왼쪽 자식 노드를 추가합니다. 첫째, 부모 노드가 주어집니다. 부모 노드에 이미 왼쪽 자식 노드가 있으면 추가 할 수 없습니다. 부모 노드의 왼쪽 자식 노드가 없으면 왼쪽 자식 노드 위치에 새 노드가 추가됩니다. . 부모 노드의 left_child는 새 노드를 가리키고 새 노드의 부모는 부모 노드를 가리 킵니다. 이 메서드는 새 노드 전달을 지원하고 새 노드에 저장된 데이터 전달도 지원합니다.

add_right_child (parent, value) : 오른쪽 자식 노드를 추가합니다. 원칙은 왼쪽 자식 노드를 추가하는 것과 동일합니다.

if __name__ == '__main__':
    tree = BinaryTree()
    tree.root = 'A'
    node1 = Node('B')
    tree.add_left_child(tree.root, node1)
    node2 = Node('C')
    tree.add_right_child(tree.root, node2)
    node3 = Node('D')
    node4 = Node('E')
    node5 = Node('F')
    tree.add_right_child(node1, node3)
    tree.add_left_child(node2, node4)
    tree.add_right_child(node2, node5)
    tree.add_left_child(node3, 'G')
    tree.add_left_child(node4, 'H')
    tree.add_right_child(node4, 'I')
    tree.add_right_child(node5, 'J')
    tree.show_tree()

작업 결과 :

--------------------
A
├─R─C
| ├─R─F
| | ├─R─J
| | └─L─
| └─L─E
|   ├─R─I
|   └─L─H
└─L─B
  ├─R─D
  | ├─R─
  | └─L─G
  └─L─
--------------------

데이터 추가 후 바이너리 트리는 다음과 같습니다.

네, 이진 트리의 네 가지 순회 방법

이진 트리의 레벨 시퀀스 순회, 사전 주문 순회, 중간 순서 순회 및 사후 순회를 실현합니다.

    def levelorder_traversal(self):
        """层序遍历"""
        if self.is_empty():
            print('空二叉树')
            return
        queue = list()
        queue.insert(0, self.__root)
        while len(queue):
            cur = queue.pop()
            print(cur.data, end=' ')
            if cur.left_child is not None:
                queue.insert(0, cur.left_child)
            if cur.right_child is not None:
                queue.insert(0, cur.right_child)
        print()

    def preorder_traversal(self, node):
        """先序遍历"""
        if node is None:
            return
        print(node.data, end=' ')
        self.preorder_traversal(node.left_child)
        self.preorder_traversal(node.right_child)

    def inorder_traversal(self, node):
        """中序遍历"""
        if node is None:
            return
        self.inorder_traversal(node.left_child)
        print(node.data, end=' ')
        self.inorder_traversal(node.right_child)

    def postorder_traversal(self, node):
        """后序遍历"""
        if node is None:
            return
        self.postorder_traversal(node.left_child)
        self.postorder_traversal(node.right_child)
        print(node.data, end=' ')

levelorder_traversal () : 이진 트리의 레벨 순서 순회. 계층 적 순회는 너비 우선 순회이며, 이진 트리를 위에서 아래로, 왼쪽에서 오른쪽으로 순회합니다. 이진 트리의 시퀀스 순회는 큐 또는 스택에 의존해야합니다. Python에서는 목록을 큐로 직접 사용할 수 있습니다.

preorder_traversal () : 이진 트리의 사전 주문 순회.

inorder_traversal () : 이진 트리의 Inorder 순회.

postorder_traversal () : 이진 트리의 사후 순회.

이진 트리의 세 가지 깊이 우선 순회 방법에 대해서는 여기에서 재귀 방법을 사용합니다. 코드는 매우 간단합니다. 핵심은 순회 순서를 이해하는 것입니다.

https://blog.csdn.net/weixin_43790276/article/details/105473527을 참조 할 수 있습니다.

    print('层次遍历: ', end='')
    tree.levelorder_traversal()
    print('先序遍历: ', end='')
    tree.preorder_traversal(tree.root)
    print()
    print('中序遍历: ', end='')
    tree.inorder_traversal(tree.root)
    print()
    print('后序遍历: ', end='')
    tree.postorder_traversal(tree.root)
    print()

위의 데이터를 추가 한 후이 네 가지 방법을 사용하여 이진 트리를 탐색하면 실행 결과는 다음과 같습니다.

层次遍历: A B C D E F G H I J 
先序遍历: A B D G C E H I F J 
中序遍历: B G D A H E I C F J 
后序遍历: G D B H I E J F C A 

다섯, 이진 트리의 높이, 리프 노드 수 및 노드 수

이진 트리의 높이 (깊이)를 반환하는 방법, 모든 리프 노드를 인쇄하는 방법, 이진 트리 노드 수를 반환하는 방법, k 번째 수준의 노드 수를 반환하는 방법을 실현합니다.

    def height(self, root):
        """二叉树的深度"""
        if root.data is None:
            return 0
        if root.left_child is None and root.right_child is None:
            return 1
        if root.left_child is not None and root.right_child is None:
            return 1 + self.height(root.left_child)
        if root.left_child is None and root.right_child is not None:
            return 1 + self.height(root.right_child)
        if root.left_child is not None and root.right_child is not None:
            return 1 + max(self.height(root.left_child), self.height(root.right_child))

    def leaves(self, root):
        """二叉树的叶节点"""
        if root.data is None:
            return None
        if root.left_child is None and root.right_child is None:
            print(root.data, end=' ')
        if root.left_child is not None:
            self.leaves(root.left_child)
        if root.right_child is not None:
            self.leaves(root.right_child)

    def node_count(self, root):
        """二叉树的节点个数"""
        return self.node_count(root.left_child) + self.node_count(root.right_child) + 1 if root else 0

    def kth_node_count(self, root, k):
        """二叉树第k层的节点个数"""
        if not root or k <= 0:
            return 0
        if k == 1:
            return 1
        return self.kth_node_count(root.left_child, k-1) + self.kth_node_count(root.right_child, k-1)

height (root) : 이진 트리의 높이 (깊이)를 반환합니다. 이진 트리가 빈 이진 트리 인 경우 트리의 깊이는 0입니다. 이진 트리가 비어 있지 않고 루트 노드 만있는 경우 이진 트리의 깊이는 1이고 이진 트리의 깊이는 계층 수가 증가 할 때마다 1 씩 증가하며 항상 가장 깊은 계층을 찾습니다. 재귀를 사용합니다. 왼쪽 하위 트리가 더 깊든 오른쪽 하위 트리가 더 깊든 관계없이 이진 트리의 깊이는 최대 2 개를 사용합니다.

leaves (root) : 이진 트리의 모든 리프 노드를 가져옵니다. 이진 트리의 리프 노드는 자식 노드가없는 노드이며 이진 트리가 빈 이진 트리 인 경우 리프 노드가 없습니다. 이진 트리가 비어 있지 않고 루트 노드 만있는 경우 루트 노드 자체는 리프 노드입니다. 루트 노드에 하위 트리가있는 경우 재귀 방법을 사용하여 하위 트리를 판단하고 모든 리프 노드를 차례로 찾습니다.

node_count (root) : 이진 트리의 노드 수를 반환합니다. 이진 트리가 빈 이진 트리 인 경우 노드 수는 0입니다. 이진 트리가 비어 있지 않고 루트 노드 만있는 경우 노드 수는 1 개이고 이진 트리의 왼쪽 하위 트리와 오른쪽 하위 트리는 순환 적으로 판단됩니다. 노드 수는 왼쪽 하위 트리입니다. + 오른쪽 하위 트리 + 루트 노드 번호.

kth_node_count (root, k) : 이진 트리의 k 번째 수준에있는 노드 수를 반환합니다. 이진 트리가 빈 이진 트리 인 경우 노드 수는 0입니다. 이진 트리가 비어 있지 않은 경우 k가 0보다 작거나 같으면 노드 수가 0이고, k가 1이면 노드 수가 1이고, k가 다른 값이면 k-1 수준을 반환합니다. 왼쪽 및 오른쪽 하위 트리의 노드 수의 합계입니다. 여기서 1을 빼는 이유는 무엇입니까? 전체 이진 트리 (예 : 트리의 세 번째 수준에있는 k = 3 노드, 왼쪽 및 오른쪽 하위 트리)의 경우 이러한 노드는 왼쪽 및 오른쪽 하위 트리 (3-1)의 두 번째 수준에 있습니다. k 번째 레이어의 노드 수를 얻을 수 있습니다.

    print('二叉树的深度为:', tree.height(tree.root))
    print('二叉树的叶节点有:', end='')
    tree.leaves(tree.root)
    print()
    print('二叉树的节点数为:', tree.node_count(tree.root))
    print('二叉树的第三层节点数为:', tree.kth_node_count(tree.root, 3))

위의 노드를 추가 한 후 이진 트리를 보려면 다음 방법을 사용하십시오. 실행 결과는 다음과 같습니다.

二叉树的深度为: 4
二叉树的叶节点有:G H I J 
二叉树的节点数为: 10
二叉树的第三层节点数为: 3

여섯, 완전한 코드

# coding=utf-8
class Node(object):
    """节点类"""
    def __init__(self, data, left_child=None, right_child=None):
        self.data = data
        self.parent = None
        self.left_child = left_child
        self.right_child = right_child


class BinaryTree(object):
    """二叉树类"""
    def __init__(self):
        self.__root = None
        self.prefix_branch = '├'
        self.prefix_trunk = '|'
        self.prefix_leaf = '└'
        self.prefix_empty = ''
        self.prefix_left = '─L─'
        self.prefix_right = '─R─'

    def is_empty(self):
        return not self.__root

    @property
    def root(self):
        return self.__root

    @root.setter
    def root(self, data):
        self.__root = Node(data)

    def show_tree(self):
        if self.is_empty():
            print('空二叉树')
            return
        print('-' * 20)
        print(self.__root.data)
        self.__print_tree(self.__root)
        print('-' * 20)

    def add_left_child(self, parent, value):
        """添加左子节点"""
        if parent is None:
            print("父节点不存在")
            return
        if parent.left_child is not None:
            print("父节点已有左子节点")
            return
        node = value if isinstance(value, Node) else Node(value)
        parent.left_child = node
        node.parent = parent

    def add_right_child(self, parent, value):
        """添加右子节点"""
        if parent is None:
            print("父节点不存在")
            return
        if parent.right_child is not None:
            print("父节点已有右子节点")
            return
        node = value if isinstance(value, Node) else Node(value)
        parent.right_child = node
        node.parent = parent

    def levelorder_traversal(self):
        """层序遍历"""
        if self.is_empty():
            print('空二叉树')
            return
        queue = list()
        queue.insert(0, self.__root)
        while len(queue):
            cur = queue.pop()
            print(cur.data, end=' ')
            if cur.left_child is not None:
                queue.insert(0, cur.left_child)
            if cur.right_child is not None:
                queue.insert(0, cur.right_child)
        print()

    def preorder_traversal(self, node):
        """先序遍历"""
        if node is None:
            return
        print(node.data, end=' ')
        self.preorder_traversal(node.left_child)
        self.preorder_traversal(node.right_child)

    def inorder_traversal(self, node):
        """中序遍历"""
        if node is None:
            return
        self.inorder_traversal(node.left_child)
        print(node.data, end=' ')
        self.inorder_traversal(node.right_child)

    def postorder_traversal(self, node):
        """后序遍历"""
        if node is None:
            return
        self.postorder_traversal(node.left_child)
        self.postorder_traversal(node.right_child)
        print(node.data, end=' ')

    def height(self, root):
        """二叉树的深度"""
        if root.data is None:
            return 0
        if root.left_child is None and root.right_child is None:
            return 1
        if root.left_child is not None and root.right_child is None:
            return 1 + self.height(root.left_child)
        if root.left_child is None and root.right_child is not None:
            return 1 + self.height(root.right_child)
        if root.left_child is not None and root.right_child is not None:
            return 1 + max(self.height(root.left_child), self.height(root.right_child))

    def leaves(self, root):
        """二叉树的叶节点"""
        if root.data is None:
            return None
        if root.left_child is None and root.right_child is None:
            print(root.data, end=' ')
        if root.left_child is not None:
            self.leaves(root.left_child)
        if root.right_child is not None:
            self.leaves(root.right_child)

    def node_count(self, root):
        """二叉树的节点个数"""
        return self.node_count(root.left_child) + self.node_count(root.right_child) + 1 if root else 0

    def kth_node_count(self, root, k):
        """二叉树第k层的节点个数"""
        if not root or k <= 0:
            return 0
        if k == 1:
            return 1
        return self.kth_node_count(root.left_child, k-1) + self.kth_node_count(root.right_child, k-1)

    def __print_tree(self, node, prefix=None):
        if prefix is None:
            prefix, prefix_left_child = '', ''
        else:
            prefix = prefix.replace(self.prefix_branch, self.prefix_trunk)
            prefix = prefix.replace(self.prefix_leaf, self.prefix_empty)
            prefix_left_child = prefix.replace(self.prefix_leaf, self.prefix_empty)
        if self.has_child(node):
            if node.right_child is not None:
                print(prefix + self.prefix_branch + self.prefix_right + str(node.right_child.data))
                if self.has_child(node.right_child):
                    self.__print_tree(node.right_child, prefix + self.prefix_branch + ' ')
            else:
                print(prefix + self.prefix_branch + self.prefix_right)
            if node.left_child is not None:
                print(prefix + self.prefix_leaf + self.prefix_left + str(node.left_child.data))
                if self.has_child(node.left_child):
                    prefix_left_child += '  '
                    self.__print_tree(node.left_child, self.prefix_leaf + prefix_left_child)
            else:
                print(prefix + self.prefix_leaf + self.prefix_left)

    def has_child(self, node):
        return node.left_child is not None or node.right_child is not None

    def __str__(self):
        return str(self.__class__)


if __name__ == '__main__':
    tree = BinaryTree()
    tree.root = 'A'
    node1 = Node('B')
    tree.add_left_child(tree.root, node1)
    node2 = Node('C')
    tree.add_right_child(tree.root, node2)
    node3 = Node('D')
    node4 = Node('E')
    node5 = Node('F')
    tree.add_right_child(node1, node3)
    tree.add_left_child(node2, node4)
    tree.add_right_child(node2, node5)
    tree.add_left_child(node3, 'G')
    tree.add_left_child(node4, 'H')
    tree.add_right_child(node4, 'I')
    tree.add_right_child(node5, 'J')
    tree.show_tree()

    print('层次遍历: ', end='')
    tree.levelorder_traversal()
    print('先序遍历: ', end='')
    tree.preorder_traversal(tree.root)
    print()
    print('中序遍历: ', end='')
    tree.inorder_traversal(tree.root)
    print()
    print('后序遍历: ', end='')
    tree.postorder_traversal(tree.root)
    print()

    print('二叉树的深度为:', tree.height(tree.root))
    print('二叉树的叶节点有:', end='')
    tree.leaves(tree.root)
    print()
    print('二叉树的节点数为:', tree.node_count(tree.root))
    print('二叉树的第三层节点数为:', tree.kth_node_count(tree.root, 3))

 

 

추천

출처blog.csdn.net/weixin_43790276/article/details/105750155