泉州网站建设维护,网店营销模式,网站开发一键上架淘宝,php网站 源码平衡树
变量定义
tot表示结点数量#xff0c;rt表示根的编号
v[i]表示结点i的权值
fa[i]表示结点i的父亲节点
chi[i][2]表示结点i的左右孩子
cnt[i]表示结点i的权值存在数量#xff0c;如1123#xff0c;v[3]1#xff0c;则cnt[3]2;就是说i3的三号结点的权值为1…平衡树
变量定义
tot表示结点数量rt表示根的编号
v[i]表示结点i的权值
fa[i]表示结点i的父亲节点
chi[i][2]表示结点i的左右孩子
cnt[i]表示结点i的权值存在数量如1123v[3]1则cnt[3]2;就是说i3的三号结点的权值为1那么三号结点的权值存在数量为2即有两个1存在于数列当中也就是说自变量是结点编号因变量是结点的权值以及对应权值出现的次数
sz[i]表示结点i的子树中权值数量。sz[i]sz[chi[i][0]]sz[chi[i][1]]cnt[i]
就是说i号结点存在的value的值的数量chi[i][0]与chi[i][1]返回的是i号结点对应的两个孩子的编号加起来就是左边的数量和右边的数量与根节点的数量和
操作
查询x的前驱如果x有左子树那么前驱是左子树里最靠右的结点如果x没有左子树但有父亲结点那么前驱是它左子树内最靠右的结点。
查询x的排名如果x小于当前权值则向左子树。答案加上左子树大小如果x等于当前权值将答案1并返回否则加上当前节点的cnt并向右子树
查询排名为k的数值如果k小于左子树的大小则向左子树
将k减去左子树大小如果k0,则返回当前权值否则向右子树
旋转
旋转操作的输入是原根节点输出是新根结点
旋转的操作是对根节点而言的就是说左旋是右孩子向左旋转上来右旋是左孩子旋转上来
左旋就是右孩子成为根节点然后原根节点成为新根结点的左孩子新根结点的左孩子成为原根节点的最右侧孩子右旋是左孩子成为新根节点然后原根节点成为新根结点的右孩子新根结点的右孩子成为
就右旋而言要变的就两步一步是让左孩子成为新根也意味着左孩子失去原来的右孩子原根节点失去原来的左孩子另一步是让左孩子新根失去的右孩子接到原根新根的右子树的左侧
注意由于原根失去左孩子失去的左孩子成为了新根所以原根在成为新根的右孩子节点时是一定没有左孩子的所以不用担心接不上以及接的位置原根的左孩子的右孩子是一定可以接到原根的左孩子上的
原根A,原根左孩子B原根左孩子的右孩子C
用一个指针定义为A的左孩子即B即表示右旋后的新的新根结点B。然后让A的左孩子为新根结点B的右孩子C此时B还没发生改变之后A就发生了变化即左孩子不再是B而是C然后再用新根指针使B的右孩子为A
就是说在这一过程中用了两个指针一个指针为原根结点输入一个指针为新根结点输出
class TreeNode:def __init__(self, val):self.val valself.left Noneself.right Nonedef left_rotation(node):new_root node.rightnode.right new_root.leftnew_root.left nodereturn new_rootdef right_rotation(node):new_root node.leftnode.left new_root.rightnew_root.right nodereturn new_root
左旋
旋转操作是平衡二叉树中常用的操作用于调整树的结构以保持平衡性。平衡二叉树的旋转操作包括左旋、右旋、左右旋和右左旋。 1. 左旋Left Rotation对于一个节点将其右子节点变为新的根节点原根节点成为新根节点的左子节点原右子节点的左子节点成为原根节点的右子节点。这个操作用于解决在插入或删除某个节点导致右子树过高的情况。
2. 右旋Right Rotation对于一个节点将其左子节点变为新的根节点原根节点成为新根节点的右子节点原左子节点的右子节点成为原根节点的左子节点。这个操作用于解决在插入或删除某个节点导致左子树过高的情况。
3. 左右旋Left-Right Rotation先对节点的左子节点进行左旋然后再对节点自身进行右旋。这个操作用于解决在插入或删除某个节点导致左子树过高且其左子节点的右子树过高的情况。
4. 右左旋Right-Left Rotation先对节点的右子节点进行右旋然后再对节点自身进行左旋。这个操作用于解决在插入或删除某个节点导致右子树过高且其右子节点的左子树过高的情况。
通过这些旋转操作可以调整树的结构并保持树的平衡性。旋转操作的实质是通过节点之间的连接关系进行调整从而改变树的形态。在实际应用中旋转操作通常会涉及到节点的左右子树的高度计算、节点指针的重连等步骤。
需要注意的是旋转操作只能保持局部的平衡性有时可能需要多次旋转来达到整体的平衡。另外旋转操作可能会改变树中节点的相对顺序因此在进行旋转操作时需要注意维护节点的排序和二叉搜索树的性质。 struct Node
{int ch[2];int val;int ff;
}t[MAX];
ch是左右孩子。ff是记录这个结点的父节点
inline void rotate(int x)
{int yt[x].ff;int zt[y].ff;int k(xt[y].ch[1]);t[z].ch[yt[z].ch[1]]x;t[x].ffz;t[y].ch[k]t[x].ch[k^1];t[t[x].ch[k^1]].ffy;t[x].ch[k^1]y;t[y].ffx;
} 输入是x表示要旋转的结点的编号。通过y记录x的父节点就是说y是x的父节点z是y的父节点是x的爷爷结点
k是表示结点x是其父结点的什么孩子。t[y].ch[1]返回的是y号结点的右孩子编号。如果是右孩子,则判断出来是1.不然则判断出来是0就是说是左孩子就返回0是右孩子就返回1
对于旋转的操作就是利用了两个指针借助了爷爷结点即把x接到了爷爷结点上然后就是确定接到爷爷结点的哪个孩子结点上。
具体步骤是先让爷爷节点的孩子结点设置为x,这时会断掉z与y的联系z与x联系上
然后让x的父节点设置为z这时会断掉x与y的联系x与z联系上。此时y的孩子结点上记录的依然是x
然后让y的孩子结点变为x的孩子结点让x的孩子结点的父节点变为y结点
最后让x的孩子结点设置为y把y的父节点设置为x 设x为y的k孩子k为0时为左孩子k为1时为右孩子则需要进行相反的旋转操作即k^1(与1异或如果k为0x为左孩子则进行右旋操作x变为根节点如果k为1则进行左旋操作
1把x设置为新根结点 t[z].ch[yt[z].ch[1]]x;t[x].ffz;
z的作用就是接口省去了最后返回新根结点的过程就是让z的相应孩子结点位置变为x即所谓新根结点。
2.把原根结点的k孩子设为新根结点的k^1孩子 t[y].ch[k]t[x].ch[k^1]; t[t[x].ch[k^1]].ffy;
3.让新根结点的孩子设为原根节点 t[x].ch[k^1]y; t[y].ffx; 2与3不能反转因为如果先3的话新根结点的原孩子就会丢失就会导致在2的时候接不上原来的孩子导致丢失。而如果先2的话会使原根结点的孩子结点丢失但是其相应位置上孩子就是x,x已经成为新根结点所以无所谓.具体就是t[x].ch[k^1]