Python implementation tree

 Tree (Tree) is a very efficient nonlinear storage structure. Tree can be very vivid understanding, have roots, leaves only, and is corresponding to the root, leaf nodes in the data structure, called sibling with a layer of leaves, called near different layers of parent-child, very easy to understand.

Note: Definition from Baidu Encyclopedia.

Other concepts explained

  • Binary tree is a tree each node has at most two child nodes.

  • Full binary tree is in addition to the leaf nodes, each node has about two children, this is called a binary tree full binary tree.

  • Complete binary tree is a leaf node in the bottom two layers, the last layer of leaf nodes are arranged to the left, and except for the last one, the number of other layers of nodes should be maximized, this is called a binary tree complete binary tree.

In the following pages, we'll walk through how the specific function of a binary tree is realized.

Ideas:

  1. Define a class node node, stores the data DATA and the left child node and the right child node left right.

  2. Then binary_tree achieve binary class should have at least the following properties and functions: properties: there is a root node (the root), which is a node class. Function: add a child node add, return to the parent node get_parent, the child is removed delete.

Proceed as follows:

1. Create a Node class

Create a Node class, as basic data structures: link point, and initializes the corresponding internal reference.

Specific codes are as follows:

class Node(object):
    def __init__(self,item):
        self.item = item #表示对应的元素
        self.left=None #表示左子节点
        self.right=None #表示右子节点
    def __str__(self):
        return str(self.item)  #print 一个 Node 类时会打印 __str__ 的返回值

2. 创建 Tree 类

创建一个 Tree 的类,定义根节点。

具体实现代码如下:

class Tree(object):
    def __init__(self):
        self.root=Node('root')  #根节点定义为 root 永不删除,作为哨兵使用。

3. 添加 add 函数

添加一个 add(item) 的函数,功能是添加子节点到树里面。

具体实现代码如下:

def add(self,item):
        node = Node(item)
        if self.root is None:  #如果二叉树为空,那么生成的二叉树最终为新插入树的点
            self.root = node
        else:
            q = [self.root] # 将q列表,添加二叉树的根节点
            while True:
                pop_node = q.pop(0)
                if pop_node.left is None: #左子树为空则将点添加到左子树
                    pop_node.left = node
                    return
                elif pop_node.right is None: #右子树为空则将点添加到右子树
                    pop_node.right = node
                    return
                else:
                    q.append(pop_node.left)
                    q.append(pop_node.right)

4. 添加 get_parent 函数

添加一个 get_parent(item) 函数,功能是找到 item 的父节点。

具体实现代码如下:

def get_parent(self, item):
        if self.root.item == item:
            return None  # 根节点没有父节点
        tmp = [self.root] # 将tmp列表,添加二叉树的根节点
        while tmp:
            pop_node = tmp.pop(0)
            if pop_node.left and pop_node.left.item == item: #某点的左子树为寻找的点
                return pop_node #返回某点,即为寻找点的父节点
            if pop_node.right and pop_node.right.item == item: #某点的右子树为寻找的点
                return pop_node #返回某点,即为寻找点的父节点
            if pop_node.left is not None: #添加tmp 元素
                tmp.append(pop_node.left)
            if pop_node.right is not None:
                tmp.append(pop_node.right)
        return None

5. 添加 delete 函数

添加一个 delete(item) 函数,功能是从二叉树中删除一个子节点。

思路如下:

先获取待删除节点 item 的父节点。
    如果父节点不为空,判断 item 的左右子树:
        如果左子树为空,那么判断 item 是父节点的左孩子,还是右孩子;
            如果是左孩子,将父节点的左指针指向 item 的右子树,反之将父节点的右指针指向 item 的右子树。
        如果右子树为空,那么判断 item 是父节点的左孩子,还是右孩子;
            如果是左孩子,将父节点的左指针指向 item 的左子树,反之将父节点的右指针指向 item 的左子树。
        如果左右子树均不为空,寻找右子树中的最左叶子节点 x ,将 x 替代要删除的节点。
    删除成功,返回 True。
    删除失败, 返回 False。

效果演示:对已知二叉树删除元素 32

具体实现代码如下:

def delete(self, item):
        if self.root is None:  # 如果根为空,就什么也不做
            return False

        parent = self.get_parent(item)
        if parent:
            del_node = parent.left if parent.left.item == item else parent.right  # 待删除节点
            if del_node.left is None:
                if parent.left.item == item:
                    parent.left = del_node.right
                else:
                    parent.right = del_node.right
                del del_node
                return True
            elif del_node.right is None:
                if parent.left.item == item:
                    parent.left = del_node.left
                else:
                    parent.right = del_node.left
                del del_node
                return True
            else:  # 左右子树都不为空
                tmp_pre = del_node
                tmp_next = del_node.right
                if tmp_next.left is None:
                    # 替代
                    tmp_pre.right = tmp_next.right
                    tmp_next.left = del_node.left
                    tmp_next.right = del_node.right

                else:
                    while tmp_next.left:  # 让tmp指向右子树的最后一个叶子
                        tmp_pre = tmp_next
                        tmp_next = tmp_next.left
                    # 替代
                    tmp_pre.left = tmp_next.right
                    tmp_next.left = del_node.left
                    tmp_next.right = del_node.right
                if parent.left.item == item:
                    parent.left = tmp_next
                else:
                    parent.right = tmp_next
                del del_node
                return True
        else:
            return False

最终完整代码如下:

class Node(object):
    def __init__(self,item):
        self.item=item #表示对应的元素
        self.left=None #表示左节点
        self.right=None #表示右节点
    def __str__(self):
        return str(self.item)  #print 一个 Node 类时会打印 __str__ 的返回值
class Tree(object):
    def __init__(self):
        self.root=Node('root')  #根节点定义为 root 永不删除,作为哨兵使用。
    def add(self,item):
        node = Node(item)
        if self.root is None:  #如果二叉树为空,那么生成的二叉树最终为新插入树的点
            self.root = node
        else:
            q = [self.root] # 将q列表,添加二叉树的根节点
            while True:
                pop_node = q.pop(0)
                if pop_node.left is None: #左子树为空则将点添加到左子树
                    pop_node.left = node
                    return
                elif pop_node.right is None: #右子树为空则将点添加到右子树
                    pop_node.right = node
                    return
                else:
                    q.append(pop_node.left)
                    q.append(pop_node.right)
    def get_parent(self, item):
        if self.root.item == item:
            return None  # 根节点没有父节点
        tmp = [self.root] # 将tmp列表,添加二叉树的根节点
        while tmp:
            pop_node = tmp.pop(0)
            if pop_node.left and pop_node.left.item == item: #某点的左子树为寻找的点
                return pop_node #返回某点,即为寻找点的父节点
            if pop_node.right and pop_node.right.item == item: #某点的右子树为寻找的点
                return pop_node #返回某点,即为寻找点的父节点
            if pop_node.left is not None: #添加tmp 元素
                tmp.append(pop_node.left)
            if pop_node.right is not None:
                tmp.append(pop_node.right)
        return None
    def delete(self, item):
        if self.root is None:  # 如果根为空,就什么也不做
            return False

        parent = self.get_parent(item)
        if parent:
            del_node = parent.left if parent.left.item == item else parent.right  # 待删除节点
            if del_node.left is None:
                if parent.left.item == item:
                    parent.left = del_node.right
                else:
                    parent.right = del_node.right
                del del_node
                return True
            elif del_node.right is None:
                if parent.left.item == item:
                    parent.left = del_node.left
                else:
                    parent.right = del_node.left
                del del_node
                return True
            else:  # 左右子树都不为空
                tmp_pre = del_node
                tmp_next = del_node.right
                if tmp_next.left is None:
                    # 替代
                    tmp_pre.right = tmp_next.right
                    tmp_next.left = del_node.left
                    tmp_next.right = del_node.right

                else:
                    while tmp_next.left:  # 让tmp指向右子树的最后一个叶子
                        tmp_pre = tmp_next
                        tmp_next = tmp_next.left
                    # 替代
                    tmp_pre.left = tmp_next.right
                    tmp_next.left = del_node.left
                    tmp_next.right = del_node.right
                if parent.left.item == item:
                    parent.left = tmp_next
                else:
                    parent.right = tmp_next
                del del_node
                return True
        else:
            return False

二叉搜索树又称二叉查找树,亦称二叉排序树,如下图所示:

它主要用于搜索。 它或者是一棵空树,或者是具有下列性质的二叉树:

  1. 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;

  2. 若右子树不空,则右子树上所有结点的值均大于它的根结点的值;

  3. 左、右子树也分别为二叉排序树。

 

平衡二叉树(平衡二叉树又被称为 AVL 树 )是基于二分法的策略提高数据的查找速度的二叉树的数据结构。

特点:平衡二叉树是采用二分法思维把数据按规则组装成一个树形结构的数据,用这个树形结构的数据减少无关数据的检索,大大的提升了数据检索的速度;平衡二叉树的数据结构组装过程有以下规则:

  1. 非叶子节点只能允许最多两个子节点存在。

  2. 每一个非叶子节点数据分布规则为左边的子节点小于前节点的值,右边的子节点大于当前节点的值(这里值是基于自己的算法规则而定的,比如 hash 值)。

注:定义来自百度百科。

 

遍历原理

二叉树的遍历:是指从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。

这里有两个关键词:访问和次序。

访问其实是要根据实际的需要来确定具体做什么,比如对每个结点进行相关计算,输出打印等。它算作是一个抽象操作。

二叉树的遍历次序不同于线性结构,最多也就是从头到尾、循环和双向等简单的遍历方式。树的结点之间不存在唯一的前驱和后继关系,在访问一个结点后,下一个被访问的结点面临着不同的选择。

 

二叉树的遍历方式可以有很多,如果我们限制从左到右的顺序,就主要分为三种:

  1. 中序遍历

  2. 后序遍历

  3. 前序遍历

 

中序遍历

  1. 先处理左子树,然后处理当前节点,再处理右子树;

  2. 对于一颗二叉查找树,所有的信息都是有序排列的,中序遍历可以是信息有序输出,且运行时间为 O(n);

  3. 递归实现中序遍历。

在之前的 Tree 类里面添加 inorder 函数

参考代码如下:

def inorder(self,node):  # 中序遍历
        if node is None:
            return []
        result = [node.item]
        left_item = self.inorder(node.left)
        right_item = self.inorder(node.right)
        return left_item + result + right_item

中序遍历的效果演示:

 

后序遍历
  1. 先处理左右子树,然后再处理当前节点,运行时间为 O(n)

  2. 递归实现后序遍历

参考代码如下:

def postorder(self,node):  # 后序遍历
        if node is None:
            return []
        result = [node.item]
        left_item = self.postorder(node.left)
        right_item = self.postorder(node.right)
        return left_item + right_item + result
 
先序遍历
  1. 先处理当前节点,再处理左右子树;

  2. 递归实现先序遍历。

参考代码如下:

def preorder(self,node):  # 先序遍历
        if node is None:
            return []
        result = [node.item]
        left_item = self.preorder(node.left)
        right_item = self.preorder(node.right)
        return result + left_item + right_item

  

Guess you like

Origin www.cnblogs.com/MasterMonkInTemple/p/11363382.html