def splay(self, v: BinNode) -> BinNode: # v为最近访问需要伸展的节点 if not v: return None while v.parent and v.parent.parent: # 短路,父节点不存在直接跳出 # 父节点,祖父节点都存在时进行一次调整 # 将节点v上移两层,并同时有可能缩减三个节点的高度 p: BinNode = v.parent g: BinNode = p.parent gg: BinNode = p.parent # 记录g的父节点,调整后接入该节点 if v.IsLChild(): if p.IsLChild(): # zig-zig attach_as_lchild(g, p.rc) attach_as_lchild(p, v.rc) attach_as_rchild(p, g) attach_as_rchild(v, p) else: # zig-zag attach_as_lchild(p, v.rc) attach_as_rchild(g, v.lc) attach_as_lchild(v, g) attach_as_rchild(v, p) else: if p.IsRChild(): # zag-zag attach_as_rchild(g, p.lc) attach_as_rchild(p, v.lc) attach_as_lchild(v, g) attach_as_rchild(v, p) else: # zag-zig attach_as_rchild(p, v.lc) attach_as_lchild(g, v.rc) attach_as_rchild(v, g) attach_as_lchild(v, p) if gg is None: # gg不存在时,v为根节点 v.parent = None else: # 根据原来节点g的位置接入当前子树 if g == gg.lc: attach_as_lchild(gg, v) else: attach_as_rchild(gg, v) self.updateHeight(g) # 更新相关节点高度 self.updateHeight(p) self.updateHeight(v) p: BinNode = v.parent if p is not None: # 上面的调整是三层一组进行调整 # 如果v只有父节点,进行一次两层的调整 if v.IsLChild(): attach_as_lchild(p, v.rc) attach_as_rchild(v, p) else: attach_as_rchild(p, v.lc) attach_as_lchild(v, p) self.updateHeight(p) self.updateHeight(v) v.parent = None # 调整后v为根节点 return v
def rotate_at(self, v: BinNode): """根据中序遍历结果确定3代节点顺序以及4棵子树顺序""" p: BinNode = v.parent # 父节点 g: BinNode = p.parent # 祖父节点 if p.IsLChild(): if v.IsLChild(): p.parent = g.parent # 重构后子树与原来avl树连接 return self.connect34(v, p, g, v.lc, v.rc, p.rc, g.rc) else: v.parent = g.parent return self.connect34(p, v, g, p.lc, v.lc, v.rc, g.rc) else: if v.IsRChild(): p.parent = g.parent return self.connect34(g, p, v, g.lc, p.lc, v.lc, v.rc) else: v.parent = g.parent return self.connect34(g, v, p, g.lc, v.lc, v.rc, p.rc)
def insert(self, e): """插入节点,返回插入后节点""" node = self.search(e) if node: # 约定不含重复元素,故元素重复是不做操作直接返回 return node node = BinNode(data=e, parent=self._hot) # 插入节点,空树也可正常处理 self._size += 1 self.updateHeightAbove(node) # 更新x历代祖先高度 return node
def insert(self, e) -> BinNode: if self._root is None: # 处理空树的情况 self._size += 1 self._root = BinNode(e) return self._root node = self.search(e) if node.data == e: # 约定不含重复元素,已有该元素是直接返回该节点 return self._root t = self._root if self._root.data < e: # 判断新节点的插入位置 t.parent = self._root = BinNode(e, None, t, t.rc) if t.HasRChild(): t.rc.parent = self._root t.rc = None else: t.parent = self._root = BinNode(e, None, t.lc, t) if t.HasLChild(): t.lc.parent = self._root t.lc = None self._size += 1 self.updateHeight(t) return self._root
def removeAt(self, x: BinNode): """实际移除节点方法""" remove_node = x # 实际摘除的节点,初始值为x succ = None # 实际被删除节点的接替者 if not x.HasLChild(): # 没有左节点,直接用右节点代替 succ = x = x.rc elif not x.HasRChild(): succ = x = x.lc else: remove_node = remove_node # 寻找移除节点的后继节点 # 后继节点是当前节点右子树左侧分支的末端,一定没有左孩子 x.data, remove_node.data = remove_node.data, x.data # 移除节点与后继节点交换,可以只交换数据 # 待删除节点交换后至多只有一个右孩子 u = remove_node.parent # 获取后继节点的父节点 if u == x: # 只有当移除节点是后继节点的父节点时,删除后插入右分支 u.rc = succ = remove_node.rc else: # 其他情况都是插入左分支 u.lc = succ = remove_node.rc self._hot = remove_node.parent # 可能需要更新高度的最低节点 if succ: # succ不为None时需指定父节点 succ.parent = self._hot del remove_node return succ
def connect34(self, a: BinNode, b: BinNode, c: BinNode, t0: BinNode, t1: BinNode, t2: BinNode, t3: BinNode): """3+4重构,根据中序遍历结果确定的顺序,直接重构子树,不进行zig,zag旋转""" a.lc = t0 if t0: t0.parent = a a.rc = t1 if t1: t1.parent = a self.updateHeight(a) c.lc = t2 if t2: t2.parent = c c.rc = t3 if t3: t3.parent = c self.updateHeight(c) b.lc = a a.parent = b b.rc = c c.parent = b self.updateHeight(b) return b
class Splay(BST): def search(self, e) -> BinNode: # 调整搜索结果到树根,查找失败时也将_hot节点调整至树根 p = self.serrch_in(self._root, e) self._root = self.splay(p if p else self._hot) return self._root def insert(self, e) -> BinNode: if self._root is None: # 处理空树的情况 self._size += 1 self._root = BinNode(e) return self._root node = self.search(e) if node.data == e: # 约定不含重复元素,已有该元素是直接返回该节点 return self._root t = self._root if self._root.data < e: # 判断新节点的插入位置 t.parent = self._root = BinNode(e, None, t, t.rc) if t.HasRChild(): t.rc.parent = self._root t.rc = None else: t.parent = self._root = BinNode(e, None, t.lc, t) if t.HasLChild(): t.lc.parent = self._root t.lc = None self._size += 1 self.updateHeight(t) return self._root def remove(self, e): if self._root is None or self.search(e).data != e: # 空树或者待删除节点不存在,则无法删除 return False w = self._root if self._root.HasLChild(): # 没有左子树直接删除 self._root = self._root.rc if self._root is not None: self._root.parent = None elif self._root.HasRChild(): # 没有右子树直接删除 self._root = self._root.lc if self._root is not None: self._root.parent = None else: # 两个子树都存在 l_tree = self._root.lc l_tree.parent = None self._root.lc = None # 暂时摘除左子树 self._root = self._root.rc # 右子树保留 self._root.parent = None self.search(w.data) # 在右子树中查找原来根节点,查找失败,但是会将最小节点伸展至根节点 # 该节点最小,故其左子树肯定是空 self._root.lc = l_tree # 空的左子树接入原来的左子树 l_tree.parent = self._root self.size -= 1 if self._root is not None: # 更新根节点高度,其他节点高度在伸展过车工中已经更新过 self.updateHeight(self._root) return True def splay(self, v: BinNode) -> BinNode: # v为最近访问需要伸展的节点 if not v: return None while v.parent and v.parent.parent: # 短路,父节点不存在直接跳出 # 父节点,祖父节点都存在时进行一次调整 # 将节点v上移两层,并同时有可能缩减三个节点的高度 p: BinNode = v.parent g: BinNode = p.parent gg: BinNode = p.parent # 记录g的父节点,调整后接入该节点 if v.IsLChild(): if p.IsLChild(): # zig-zig attach_as_lchild(g, p.rc) attach_as_lchild(p, v.rc) attach_as_rchild(p, g) attach_as_rchild(v, p) else: # zig-zag attach_as_lchild(p, v.rc) attach_as_rchild(g, v.lc) attach_as_lchild(v, g) attach_as_rchild(v, p) else: if p.IsRChild(): # zag-zag attach_as_rchild(g, p.lc) attach_as_rchild(p, v.lc) attach_as_lchild(v, g) attach_as_rchild(v, p) else: # zag-zig attach_as_rchild(p, v.lc) attach_as_lchild(g, v.rc) attach_as_rchild(v, g) attach_as_lchild(v, p) if gg is None: # gg不存在时,v为根节点 v.parent = None else: # 根据原来节点g的位置接入当前子树 if g == gg.lc: attach_as_lchild(gg, v) else: attach_as_rchild(gg, v) self.updateHeight(g) # 更新相关节点高度 self.updateHeight(p) self.updateHeight(v) p: BinNode = v.parent if p is not None: # 上面的调整是三层一组进行调整 # 如果v只有父节点,进行一次两层的调整 if v.IsLChild(): attach_as_lchild(p, v.rc) attach_as_rchild(v, p) else: attach_as_rchild(p, v.lc) attach_as_lchild(v, p) self.updateHeight(p) self.updateHeight(v) v.parent = None # 调整后v为根节点 return v
def attach_as_rchild(p: BinNode, rc: BinNode) -> None: p.rc = rc if rc is not None: rc.parent = p
def attach_as_lchild(p: BinNode, lc: BinNode) -> None: p.lc = lc if lc is not None: lc.parent = p