AVL树和伸展树

在树的结构中,一个最重要的用途是用作二叉搜索树。接下来使用搜索树结构有效的实现有序映射。

二叉搜索树的结构特性产生的最重要的结果是搜索算法。在search中,搜索一次下降一层,树高为h,每一个节点的搜索时间为O(1)(至于为什么是O(1),则涉及到哈希表的设计),则最坏情况下总的搜索时间为O(h)。

基于二叉搜索树,提供了聊两种性能更高的搜索树算法。分别是AVL树,伸展树。当然还有红黑树和多路搜索树,改日再聊。

1. AVL树

AVL树中定义的一个属性为,对于T中的每一个位置p,p的孩子的高度最多相差1。一棵有n个节点的AVL树的高度为O(logn)。(LeetCode经常遇到此类题)

"""
    AVL树
"""
class AVLTreeMap():
    class _Node():
        __sloats__ = '_height, _left, _right, _parent, _element'
        def __init__(self, element, parent=None, left=None, right=None):
            self._height = 0
        def left_height(self):
            return self._left._height if self._left is not None else 0
        def right_height(self):
            return self._right._height if self._right is not None else 0

    def _relink(self, parent, child, make_left_child):
		"""正确关联父亲和孩子节点"""
        if make_left_child:
            parent._left = child   # 使child成为左节点,child允许为None
        else:
            parent._right = child   # 使child成为右节点,child允许为None
        if child is not None:
            child._parent = parent   # 如果child存在,指向父节点(定义双指针)

    def _rotate(self, p):
		"""旋转节点和原来的祖父母节点进行关联"""
        a = p._node
        b = a._parent
        c = b._parent
        if c is None:    # 这种情况是b为根节点,旋转之后a变为根节点
            self._root = a
            x._parent = None
        else:
            self._relink(c, a, b == c._left)  # 如果b为c的左节点,就直接使a变为c的左节点
        if a == b._left:                      # 如果a也为b的左节点,就使a的右节点变为b的左节点
            self._relink(b, a._right, True)
            self._relink(a, b, False)
        else:								  # 如果a也为b的右节点,就使a的右节点变为b的右节点
            self._relink(b, a._left, False)
            self._relink(a, b, True)

    def _restructure(self, x):
		"""判断需要旋转一次还是两次"""
        y = self.parent(x)
        z = self.parent(y)
        if (x == self.right(y)) == (y == self.right(z)):  # 此时三个节点在一条直线上,旋转一次, 使y成为root节点
            self._rotate(y)
            return y
        else:					
            self._rotate(x)	 # 旋转一次, 使三个节点成为一条线
            self._rotate(x)  # 旋转两次,使三个节点变平衡
            return x

    def _recompute_height(self, p):
		"""计算树的高度"""
        p._node._height = 1 + max(p._node.left_height(), p._node.right_height())

    def _isbalanced(self, p):
		"""判断树是否平衡"""
        return abs(p._node.left_height() - p._node.right_height()) <= 1

    def _tall_child(self, p, favorleft=False):
        if p._node.left_height() + (1 if favorleft else 0) > p._node.right_height():
            return self.left(p)
        else:
            return self.right(p)

    def _tall_grandchild(self, p):
        child = self._tall_child(p)
        alignment = (child == self.left(p))
        return self._tall_child(child, alignment)

    def _rebalance(self, p):
		"""恢复树的平衡"""
        while p is not None:
            old_height = p._node._height
            if not self._rebalance(p):
                p = self._restructure(self._tall_grandchild(p))
                self._recompute_height(self.left(p))
                self._recompute_height(self.right(p))
            self._recompute_height(p)
            if p._node._height == old_height:
                p = None
            else:
                p = self.parent(p)

    def _reblance_insert(self, p):
		"""插入操作后重新使树平衡"""
        self._rebalance(p)

    def _reblance_delete(self, p):
		"""删除操作后重新使树平衡"""
        self._rebalance(p)

2. 伸展树

伸展树对树的高度没有严格的对数上界,它的效率体现在某一位置移动到根的操作,每次搜索、插入、删除都要从最底层位置开始、伸展操作会是的频繁访问的元素更快接近于根,从而减少典型的搜索时间。

"""
    伸展树
"""
class SplayTreeMap():
    def _rotate(self, p):
        pass
    def _splay(self, p):
        while p != self.root():
            parent = self.parent(p)
            grand = self.parent(parent)
            if grand is None:
                # zig case
                self._rotate(p)
            elif (parent == self.left(grand)) == (p == self.left(parent)):
                # zig-zag case
                self._rotate(parent)  # move parent up
                self._rotate(p)       # move p up
            else:
                # zig-zig case
                self._rotate(p)  # move p up
                self._rotate(p)  # move p up again

    def _reblance_insert(self, p):
        self._splay(p)

    def _reblance_delete(self, p):
        if p is not None:
            self._splay(p)

    def _reblance_access(self, p):
        self._splay(p)

三种类型:

zig-zig 型: 三个节点在同一直线上

zig-zag型: 三个节点不在同一直线上

zig型:没有祖父节点

在最坏情况下,搜索的位置可能位于树的最深处,所以对一颗高度为为h的伸展树进行搜索、插入、删除操作中,全部运行时间为O(h), h最大可能接近n,所以最坏情况时间复杂度也为O(n)。

 

    原文作者:AVL树
    原文地址: https://blog.csdn.net/fenglei0415/article/details/84891699
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞