簡體   English   中英

在python類中實現樹的遞歸函數

[英]Implementing recursive functions for trees in python class

我創建了一個類Tree和一個Node類。 現在我需要實現preOrderpostOrderinOrder遍歷。 我是用私人功能做的。 但有沒有辦法只使用一個函數來做同樣的事情?

class Node:
    def __init__(self, data):
        self.left = None
        self.right = None
        self.data = data

class Tree:
    def __init__(self):
        self.root = None

    # Private helper functions
    def __insert(self, data, root):
        if data < root.data:
            if root.left is None:
                root.left = Node(data)
            else:
                self.__insert(data, root.left)
        elif data >= root.data:
            if root.right is None:
                root.right = Node(data)
            else:
                self.__insert(data, root.right)

    # Traversals
    def __preOrder(self, root):
        print root.data
        if root.left:
            self.__preOrder(root.left)
        if root.right:
            self.__preOrder(root.right)

    # Wrapper Functions 
    def insert(self, data):
        if self.root == None:
            self.root = Node(data)
        else:
            self.__insert(data, self.root)

    def preOrder(self):
        self.__preOrder(self.root)


tree = Tree()
print "Enter elements to be inserted in the tree(End with a -1): "
while True:
    elem = int(raw_input())
    if elem == -1:
        break
    tree.insert(elem)

print "Preorder traversal: "
tree.preOrder()

這里我必須使用輔助函數,因為我不希望用戶顯式提供根元素。

是的,您可以在單個函數中實現所有3種類型的遍歷。 我已經將遍歷函數轉換為生成器,以使它們更加通用。 因此,它們不是打印數據,而是生成數據的迭代器。 這使您可以在數據生成時處理數據,也可以將數據捕獲到列表(或其他集合)中。

在Python 2中,您的類應該繼承自object ,否則您將獲得舊式類,與新式類相比,它們相當有限(Python 3只有新式類)。

順便說一句,沒有必要為私有函數(調用Python的名稱修改機制)使用雙下划線,單個前導下划線就足夠了。

我還在類中添加了簡單的__repr__方法,這在開發和調試過程中非常方便。

class Node(object):
    def __init__(self, data):
        self.left = None
        self.right = None
        self.data = data

    def __repr__(self):
        return repr((self.data, self.left, self.right))


class Tree(object):
    def __init__(self):
        self.root = None

    def __repr__(self):
        return repr(self.root)

    # Private helper functions
    def _insert(self, data, root):
        if data < root.data:
            if root.left is None:
                root.left = Node(data)
            else:
                self._insert(data, root.left)
        else: # data >= root.data:
            if root.right is None:
                root.right = Node(data)
            else:
                self._insert(data, root.right)

    def _traverse(self, root, mode):
        if mode == 'pre':
            yield root.data
        if root.left:
            for u in self._traverse(root.left, mode):
                yield u
        if mode == 'in':
            yield root.data
        if root.right:
            for u in self._traverse(root.right, mode):
                yield u
        if mode == 'post':
            yield root.data

    # Wrapper Functions 
    def insert(self, data):
        if self.root == None:
            self.root = Node(data)
        else:
            self._insert(data, self.root)

    def preOrder(self):
        for u in self._traverse(self.root, 'pre'):
            yield u

    def inOrder(self):
        for u in self._traverse(self.root, 'in'):
            yield u

    def postOrder(self):
        for u in self._traverse(self.root, 'post'):
            yield u

# Test

tree = Tree()

for elem in '31415926':
    tree.insert(elem)

print tree

print "Preorder traversal: "
print list(tree.preOrder())

print "InOrder Traversal: "
print list(tree.inOrder())

print "PostOrder Traversal: "
print list(tree.postOrder())

產量

('3', ('1', None, ('1', None, ('2', None, None))), ('4', None, ('5', None, ('9', ('6', None, None), None))))
Preorder traversal: 
['3', '1', '1', '2', '4', '5', '9', '6']
InOrder Traversal: 
['1', '1', '2', '3', '4', '5', '6', '9']
PostOrder Traversal: 
['2', '1', '1', '6', '9', '5', '4', '3']

以下是處理數據時的示例:

for data in tree.inOrder():
    print data

FWIW,這段代碼在Python 3中會更加清晰,因為我們可以使用語法的yield from而不是for循環。 而不是

for u in self._traverse(root.left, mode):
    yield u

我們能做到

yield from self._traverse(root.left, mode)

我不確定將遍歷函數實現為單行,但是您嘗試做的另一種方法是通過將遍歷邏輯抽象為一系列單獨的類來使策略模式適應您的用例。所有都繼承自一個常見的TraversalStrategy 然后,您可以將遍歷策略對象注入為Tree的依賴項,從而將Tree的結構與用於遍歷它的邏輯分離。

這種方法有以下好處:

  • 它允許您擺脫當前Tree方法的大部分
  • 它增加了程序的可測試性(您可以單獨測試樹遍歷策略,與其他樹相關的邏輯隔離)
  • 它增加了可重用性(您可以在其他情況下使用這些遍歷策略)
  • 一般來說,它使您的程序更加穩固
    • 您的Tree類現在具有單一職責 - 改變的一個原因
    • 您可以為樹實現新的遍歷行為,而無需觸及Tree的源代碼,即它已關閉以進行修改
    • 您將遍歷邏輯注入為依賴關系,因此在不同的實現(包括模擬)之間進行替換非常容易

下面的代碼是為Python 3編寫的,因此需要對Python 2進行一些小的更改。

from abc import ABC, abstractmethod


class Node:
    def __init__(self, data):
        self.left = None
        self.right = None
        self.data = data

    def __repr__(self):
        return str(self.data)


class Tree:
    def __init__(self, traversal_strategy):
        self.root = None
        self.traversal_strategy = traversal_strategy

    def insert(self, data):
        if self.root is None:
            self.root = Node(data)
        else:
            self.__insert(data, self.root)

    def __insert(self, data, root):
        if data < root.data:
            if root.left is None:
                root.left = Node(data)
            else:
                self.__insert(data, root.left)
        elif data >= root.data:
            if root.right is None:
                root.right = Node(data)
            else:
                self.__insert(data, root.right)

    def traverse(self):
        self.traversal_strategy.traverse(self.root)


class TraversalStrategy(ABC):
    @abstractmethod
    def traverse(self, node):
        pass

    def _attempt_traverse(self, node):
        if node:
            self.traverse(node)


class PreOrderTraversal(TraversalStrategy):
    def traverse(self, node):
        print(node)
        self._attempt_traverse(node.left)
        self._attempt_traverse(node.right)


class InOrderTraversal(TraversalStrategy):
    def traverse(self, node):
        self._attempt_traverse(node.left)
        print(node)
        self._attempt_traverse(node.right)


class PostOrderTraversal(TraversalStrategy):
    def traverse(self, node):
        self._attempt_traverse(node.left)
        self._attempt_traverse(node.right)
        print(node)


def build_tree(traversal_strategy):
    tree = Tree(traversal_strategy)
    elements = [1, 3, 6, 9, 2, 8]

    for element in elements:
        tree.insert(element)

    return tree


if __name__ == '__main__':
    pre_order_tree = build_tree(PreOrderTraversal())
    in_order_tree = build_tree(InOrderTraversal())
    post_order_tree = build_tree(PostOrderTraversal())

    print('Pre order traversal: ')
    pre_order_tree.traverse()
    print()

    print('In order traversal: ')
    in_order_tree.traverse()
    print()

    print('Post order traversal: ')
    post_order_tree.traverse()
    print()

產量

Pre order traversal: 
1
3
2
6
9
8

In order traversal: 
1
2
3
6
8
9

Post order traversal: 
2
8
9
6
3
1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM