使用python实现二叉搜索树

二叉查找(搜索)树是一种把较小数据存储在左节点二较大数据存储在右节点的二叉树。二叉搜索树要求:每个节点都不比它左子树的任意元素小,而且不比它的右子树的任意元素大。

遍历一个二叉搜索树,有三种顺序
中序遍历:利用递归的方法,有序地输出二叉搜索树中的所有元素,递归式表示为:
digui(tree):
    digui(tree.left)
    print(tree.key)
    digui(tree.right)
先序遍历:输出根的关键字在左右子树的关键值之前,递归式表示为:
digui(tree):
    print(tree.key)
    digui(tree.left)
    digui(tree.right)
可以做成先根后枝叶的显示图例
后序遍历:输出根的关键字在左右子树的关键值之后,递归式表示为:
digui(tree):
    digui(tree.left)
    digui(tree.right)
    print(tree.key)
可以做成先枝叶后根的显示图例

查找
查找某个元素,时间复杂度为O(lgn)
伪代码(递归)
TREE-SEARCH(x,k)
    if x == NIL or k == x.key
        return x
    if k < x.key
        return TREE-SEARCH(x.left,k)
    else
        return TREE-SEARCH(x.right,k)
伪代码(循环)
TREE-SEARCH(x,k)
    while x!= NIL and k != x.key
        if k < x.key
            x = x.left
        else
            x = x.right
    return x
查找最小关键字元素
伪代码(循环)
TREE-MINMUM(x)
    while x.left != NIL
        x = x.left
    return x
查找最大关键字元素
伪代码(循环)
TREE-MAXMUM(x)
    while x.right != NIL
        x = x.right
    return x
查找节点的后继(后继就是关键字大小是该节点之后最小的节点)
TREE-SUCCESSOR(x)
    if x.right != NIL                                    //如果该节点有右子树,那么直接在其右子树中执行查找最小元素的过程
        return TREE-MINMUM(x.right)
    y = x.p                                                   //否则,就找到其父节点
    while y != NIL and x== y.right            //如果父节点非空,并且x是父节点y的右子节点则还需要继续循环
        x = y                                                  //将父节点赋值给x
        y = y.p                                                //父节点的父节点赋值给y,循环迭代到不满足条件为止
    return y                                                  //最后返回y
查找节点的前驱(前驱就是关键字大小是该节点之前最大的节点),方法和查找后继的对称
TREE-PRESUCCESSOR(x)
    if x.left != NIL                                    //如果该节点有左子树,那么直接在其左子树中执行查找最大元素的过程
        return TREE-MAXMUM(x.left)
    y = x.p                                                   //否则,就找到其父节点
    while y != NIL and x== y.left            //如果父节点非空,并且x是父节点y的左子节点则还需要继续循环
        x = y                                                  //将父节点赋值给x
        y = y.p                                                //父节点的父节点赋值给y,循环迭代到不满足条件为止
    return y      

插入
首先,执行查找插入元素的操作,并使用一个变量保存循环中的父节点(即插入元素的父节点)。然后按照其相比父节点的大小,决定将其插入到父节点的左子节点还是右子节点。
伪代码
TREE-INSERT(T,z)
    y = NIL                    //存储父节点的变量
    x = T.root                //存储查找节点的变量
    while x != NIL        //查找该元素直至叶节点,而此时x已经是叶节点的节点了,该叶节点就是插入元素的父节点
        y = x                    //x赋值于y,然后x开始下次迭代
        if z.key < x.key       
            x = x.left
        else
            x = x.right
    z.p = y                    //查找完毕,将y保存的叶节点,赋值给插入节点的父元素指针
    if y == NIL            //如果叶节点是空的,那么整个树是空的
        T.root = z            //直接将插入元素存为根节点
    else if z.key < y.key    //否则按照其大小,存为叶节点的左或右子节点
        y.left = z
    else
        y.right = z


删除
从逻辑上来讲,从一棵二叉搜索树T中删除一个节点z的整个策略分为三种基本情况:
1,如果z没有孩子节点,那么只是简单地将它删除,并修改它的父节点,用NIL作为子节点来替换z
2,如果z只有一个子节点(另一个为NIL),那么将这个孩子提升到树中z的位置上,并修改z的父节点,用z的子节点来替换z
3,如果z有两个子节点,那么找z的后继y(如果有右子树,则一定在其右子树中,否则,是其某个祖先节点),并让y占据树中z的位置。然后递归执行对节点y的删除操作
伪代码
TREE-DELETE(T,z)
    pa = z.p     //获取z的父节点
    if pa == NIL and z.left == NIL and z.right == NIL            //如果是根节点
        T.root = NIL        //则树成空树了

    if z.left == NIL and z.right == NIL  //如果待删除节点z左右子节点为空
        if z.key < pa.key 
            pa.left = NIL
        else
            pa.right = NIL
    else if z.left == NIL and z.right != NIL     //只有一个右子节点的情况
        pa.right = NIL
    else if z.left != NIL and z.right == NIL       //只有一个左子节点的情况
        pa.left = NIL
    else                                                        //最后只剩下,拥有两个子节点的情况了
        y = TREE-SUCCESSOR(z)                 //查找到z的后继节点y
        if z.key < pa.key                                //用y替换z
            pa.left = y
        else
            pa.right = y
        y.left = z.left
        y.right = z.right
        TREE-DELETE(T,y)                    //替换完成后,递归执行删除节点y的操作。
        
python实现

class Node(object):
    '''Tree's nodes factory'''
    def __init__(self, value):
        self.value = value
        self.father = None
        self.left = None
        self.right = None


class Tree(object):
    '''A search tree which has two children nodes'''
    def __init__(self, nodes_list):
        self.root = None
        for node in nodes_list:
            self.insert(node)

    def ergodic_middle(self):
        def middle(node):
            if node != None:
                middle(node.left)
                print node.value,
                middle(node.right)
        middle(self.root)

    def search(self, value):
        def _search(node, value):
            current = node
            while current != None and current.value != value:
                if current.value > value:
                     current = current.left
                else:
                     current = current.right
            return current
        return _search(self.root, value)

    def _min(self, node):
        current = node
        while current.left != None:
            current = current.left
        return current

    def min(self):
        return self._min(self.root)

    def _max(self, node):
        current = node
        while current.right != None:
            current = current.right
        return current

    def max(self):
        return self._max(self.root)

    def next(self, node):
        current = node
        if current.right != None:
            return self._min(current.right)
        father = current.father
        while father != Node and current == father.right:
            current = father
            father = father.father
        return father

    def pre(self, node):
        current = node
        if current.left != None:
            return self._max(current.left)
        father = current.father
        while father != None and current == father.left:
            current = father
            father = father.father
        return father

    def insert(self, node):
        father = None
        current = self.root

        while current != None:
            if current.value == node.value:
                raise ValueError('node.value is already in the search tree')
            father = current
            if node.value < current.value:
                current = current.left
            else:
                current = current.right

        node.father = father
        if father == None:
            self.root = node
        elif node.value < father.value:
            father.left = node
        else:
            father.right = node

    def delete(self, node):
        def _delete(tree, node):
            if node.left == None and node.right == None:
                _nochild(tree, node)
            elif node.left == None and node.right != None:
                _onechild(tree, node)
            elif node.left != None and node.right == None:
                _onechild(tree, node)
            else:
                _twochildren(tree, node)

        def _nochild(tree, node):
            if tree.root == node:
                tree.root = None
            else:
                if node.value < node.father.value:
                    node.father.left = None
                else:
                    node.father.right = None

        def _onechild(tree, node):
            if tree.root == node:
                if node.right != None:
                    tree.root = node.right
                else:
                    tree.root = node.left
            else:
                if node.right != None:
                    if node.value < node.father.value:
                        node.father.left = node.right
                    else:
                        node.father.right = node.right
                    node.right.father = node.father
                else:
                    if node.value < node.father.value:
                        node.father.left = node.left
                    else:
                        node.father.right = node.left
                    node.left.father = node.father

        def _twochildren(tree, node):
            if tree.root == node:
                next = self.next(node)
                _delete(tree,next)
                tree.root = next
                next.left = node.left
                next.right = node.right
                node.left.father = next
                node.right.father = next
            else:
                next = self.next(node)
                _delete(tree,next)
                if node.value < node.father.value:
                    node.father.left = next
                else:
                    node.father.right = next
                next.left = node.left
                next.right = node.right
                node.left.father = next
                node.right.father = next

        node_in_tree = self.search(node.value)
        if node_in_tree and node_in_tree.left == node.left \
                    and node_in_tree.right == node.right \
                    and node_in_tree.father == node.father:
            _delete(self, node)
        else:
            raise ValueError('No such Node')


使用方法

>>> from search_tree import Node, Tree
>>> t1 = Tree([Node(100)])
>>> t1.root.value
100
>>> t1.insert(Node(200))
>>> t1.insert(Node(50))
>>> t1.insert(Node(80))
>>> t1.insert(Node(10))
>>> t1.insert(Node(150))
>>> t1.insert(Node(250))
>>> t1.ergodic_middle()
10 50 80 100 150 200 250
>>> t1.min()

>>> t1.min().value
10
>>> t1.max().value
250
>>> t1.search(80)

>>> t1.search(88)
>>> t1.delete(100)
Traceback (most recent call last):
  File "", line 1, in 
  File "search_tree.py", line 156, in delete
    node_in_tree = self.search(node.value)
AttributeError: 'int' object has no attribute 'value'
>>> t1.delete(t1.search(100))
>>> t1.ergodic_middle()
10 50 80 150 200 250
>>> t1.root.value
150


你可能感兴趣的:(数据结构,二叉树,数据结构,python)