python之树的实现

一、前言

树的术语是生物学、家谱学和几何学术语的一个特殊混合体。它很好的表示了层级结构,它的两个主要特征:

  • 每个项都有多个子节点。
  • 除了叫做根(树最顶端的节点)的特殊项,所有其他的项都只有一个父节点。

普通的树和二叉树的递归定义:

  • 普通的树------普通的树要么为空,要么包含一个有限的节点的集合T。有一个和所有其他节点不同的节点r,称为根,此外,集合T-{r}被划分为不相连的子集,每个子集都是一个普通的树。
  • 二叉树------一个二叉树要么为空,要么包含一个根节点,外加一个左子树和一个右子树,每个子树都是一个二叉树。

二、二叉搜索树(Binary Search Tree,BST)

在一个BST中,给定节点的左子树中的节点要小于它,其右子树中的节点要大于给定的节点。

2.1  二叉搜索树接口中的方法

BST方法 作用
tree.isEmpty() 如果为空,返回True,否则返回False
tree.__len__() 返回树中元素的数目
tree.__iter__() 对树进行一次前向遍历
tree.__str__() 返回字符串,表示树的形状
tree.__contains__(item) 如果item在树中,返回True,否则返回False
tree.__add__(otherTree) 返回一个新树,内容为tree和otherTree的内容
tree.__eq__(anyObject) 若tree==otherTree,返回True,否则返回False
tree.clear() 让树变成空树
tree.add(item) 将item添加到树中适当的位置
tree.remove(item) 从树中删除item,先验条件:item在树中
tree.replace(item,newItem) 使用newItem替代树中匹配的项,并返回匹配的项
tree.inorder() 返回一个迭代器,对树执行中序遍历
tree.postorder() 返回一个迭代器,对树执行后序遍历
tree.levelorder() 返回一个迭代器,对树执行层序遍历

2.2代码实现

2.2.1 创建抽象集类,并保存为abstractcollection.py文件,具体代码见博客:https://blog.csdn.net/lzh_12345/article/details/79759960中的“二、利用链表实现栈”之2.1的代码。

2.2.2创建二叉搜索树节点类BSTNode,并保存为bstnode.py文件

class BSTNode(object):
    """Represents a node for a linked binary search tree."""

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

2.2.3创建LinkedStack和LinkedQueue类,并分别保存为linkedstack.py和linkedqueue.py文件。

LinkedStack类的具体代码:见博客:https://blog.csdn.net/lzh_12345/article/details/79759960中的“二、利用链表实现栈”。

LinkedQueue类的具体代码:见博客:https://blog.csdn.net/lzh_12345/article/details/79762861中的“二、队列的链表实现”。

2.2.4 链表实现BST

from abstractcollection import AbstractCollection
from bstnode import BSTNode
from linkedstack import LinkedStack
from linkedqueue import LinkedQueue

class LinkedBST(AbstractCollection):
    """An link-based binary search tree implementation."""

    def __init__(self, sourceCollection = None):
        """Sets the initial state of self, which includes the
        contents of sourceCollection, if it's present."""
        self._root = None
        AbstractCollection.__init__(self, sourceCollection)
        
    # Accessor methods
    def __str__(self):
        """Returns a string representation with the tree rotated
        90 degrees counterclockwise."""
        def recurse(node, level):
            s = ""
            if node != None:
                s += recurse(node.right, level + 1)
                s += "| " * level
                s += str(node.data) + "\n"
                s += recurse(node.left, level + 1)
            return s
        return recurse(self._root, 0)

    def __iter__(self):
        """Supports a preorder traversal on a view of self."""
        if not self.isEmpty():
            stack = LinkedStack()
            stack.push(self._root)
            while not stack.isEmpty():
                node = stack.pop()
                yield node.data
                if node.right != None:
                    stack.push(node.right)
                if node.left != None:
                    stack.push(node.left)

    def preorder(self):
        """Supports a preorder traversal on a view of self."""
        return None

    def inorder(self):
        """Supports an inorder traversal on a view of self."""
        lyst = list()
        def recurse(node):
            if node != None:
                recurse(node.left)
                lyst.append(node.data)
                recurse(node.right)
        recurse(self._root)
        return iter(lyst)

    def postorder(self):
        """Supports a postorder traversal on a view of self."""
        return None

    def levelorder(self):
        """Supports a levelorder traversal on a view of self."""
        return None

    def __contains__(self, item):
        """Returns True if target is found or False otherwise."""
        return self.find(item) != None

    def find(self, item):
        """If item matches an item in self, returns the
        matched item, or None otherwise."""
        def recurse(node):
            if node is None:
                return None
            elif item == node.data:
                return node.data
            elif item < node.data:
                return recurse(node.left)
            else:
                return recurse(node.right)
        return recurse(self._root)

    # Mutator methods
    def clear(self):
        """Makes self become empty."""
        self._root = None
        self._size = 0

    def add(self, item):
        """Adds item to the tree."""

        # Helper function to search for item's position 
        def recurse(node):
            # New item is less, go left until spot is found
            if item < node.data:
                if node.left == None:
                    node.left = BSTNode(item)
                else:
                    recurse(node.left)
            # New item is greater or equal, 
            # go right until spot is found
            elif node.right == None:
                node.right = BSTNode(item)
            else:
                recurse(node.right)
            # End of recurse

        # Tree is empty, so new item goes at the root
        if self.isEmpty():
            self._root = BSTNode(item)
        # Otherwise, search for the item's spot
        else:
            recurse(self._root)
        self._size += 1

    def remove(self, item):
        """Precondition: item is in self.
        Raises: KeyError if item is not in self.
        postcondition: item is removed from self."""
        if not item in self:
            raise KeyError("Item not in tree.""")

        # Helper function to adjust placement of an item
        def liftMaxInLeftSubtreeToTop(top):
            # Replace top's datum with the maximum datum in the left subtree
            # Pre:  top has a left child
            # Post: the maximum node in top's left subtree
            #       has been removed
            # Post: top.data = maximum value in top's left subtree
            parent = top
            currentNode = top.left
            while not currentNode.right == None:
                parent = currentNode
                currentNode = currentNode.right
            top.data = currentNode.data
            if parent == top:
                top.left = currentNode.left
            else:
                parent.right = currentNode.left

        # Begin main part of the method
        if self.isEmpty(): return None
        
        # Attempt to locate the node containing the item
        itemRemoved = None
        preRoot = BSTNode(None)
        preRoot.left = self._root
        parent = preRoot
        direction = 'L'
        currentNode = self._root
        while not currentNode == None:
            if currentNode.data == item:
                itemRemoved = currentNode.data
                break
            parent = currentNode
            if currentNode.data > item:
                direction = 'L'
                currentNode = currentNode.left
            else:
                direction = 'R'
                currentNode = currentNode.right
                
        # Return None if the item is absent
        if itemRemoved == None: return None
        
        # The item is present, so remove its node

        # Case 1: The node has a left and a right child
        #         Replace the node's value with the maximum value in the
        #         left subtree
        #         Delete the maximium node in the left subtree
        if not currentNode.left == None \
           and not currentNode.right == None:
            liftMaxInLeftSubtreeToTop(currentNode)
        else:
            
        # Case 2: The node has no left child
            if currentNode.left == None:
                newChild = currentNode.right
                
        # Case 3: The node has no right child
            else:
                newChild = currentNode.left
                
        # Case 2 & 3: Tie the parent to the new child
            if direction == 'L':
                parent.left = newChild
            else:
                parent.right = newChild
            
        # All cases: Reset the root (if it hasn't changed no harm done)
        #            Decrement the collection's size counter
        #            Return the item
        self._size -= 1
        if self.isEmpty():
            self._root = None
        else:
            self._root = preRoot.left
        return itemRemoved

    def replace(self, item, newItem):
        """
        If item is in self, replaces it with newItem and
        returns the old item, or returns None otherwise."""
        probe = self._root
        while probe != None:
            if probe.data == item:
                oldData = probe.data
                probe.data = newItem
                return oldData
            elif probe.data > item:
                probe = probe.left
            else:
                probe = probe.right
        return None

2.2.5 测试文件

from linkedbst import LinkedBST

def main():
    tree = LinkedBST()
    print("Adding D B A C F E G")
    tree.add("D")
    tree.add("B")
    tree.add("A")
    tree.add("C")
    tree.add("F")
    tree.add("E")
    tree.add("G")

    print("\nExpect True for A in tree: ", "A" in tree)

    print("\nString:\n" + str(tree))

    clone = LinkedBST(tree)
    print("\nClone:\n" + str(clone))
    
    print("Expect True for tree == clone: ", tree == clone)

    print("\nFor loop: ", end="")
    for item in tree:
        print(item, end=" ")

    print("\n\ninorder traversal: ", end="")
    for item in tree.inorder(): print(item, end = " ")
    
    print("\n\npreorder traversal: ", end="")
    for item in tree.preorder(): print(item, end = " ")
    
    print("\n\npostorder traversal: ", end="")
    for item in tree.postorder(): print(item, end = " ")
    
    print("\n\nlevelorder traversal: ", end="")
    for item in tree.levelorder(): print(item, end = " ")

    print("\n\nRemoving all items:", end = " ")
    for item in "ABCDEFG":
        print(tree.remove(item), end=" ")

    print("\n\nExpect 0: ", len(tree))

    tree = LinkedBST(range(1, 16))
    print("\nAdded 1..15:\n" + str(tree))
    
    lyst = list(range(1, 16))
    import random
    random.shuffle(lyst)
    tree = LinkedBST(lyst)
    print("\nAdded ", lyst, "\n" + str(tree))

    
if __name__ == "__main__":
    main()

你可能感兴趣的:(数据结构)