赞
踩
rbtree作为平衡二叉树在linux内核中的使用很广泛,如前文讲到的cfs调度类组织调度实体se,以及内存子系统中用来管理内存。
定义:
红黑树是接近平衡的二叉树,因为它的最大高度最大是最短高度的二倍。所谓的黑高相同的性质。每个节点不是黑色就是红色,且父节点和字节点不能都是红色。
特性:
操作:
旋转操作见后面的AVL树中。
插入操作:
规定插入的节点为红色,因为红色节点不增加树的“黑高”,如果是黑色势必会增加“黑高”,打破平衡的几率更高些。
现在来分析插入操作的几种情况:
如果父节点是黑色或树为空,那么直接插入就好。依旧保持平衡。
如果父亲是红色,则势必打破rbtree的平衡性,需要自平衡操作,rbtree的自平衡操作是通过染色+旋转来实现的。
来分析具体情境,由于对称性,我们之分析,一只情况,比如是父亲的左孩子和右孩子是对称的,只是左旋便右旋而已。
情景1. 叔叔为红:,只需染色,然后再向上传递。
由于红黑树红色互斥特性,则祖父(PP) 为黑色。只需将父亲和叔叔染成黑色,然后将祖父染红,在把祖父当成当前节点,向上再调整。
情景二:叔叔为黑色(黑色节点或NIL),我们需要再细分,再分插入节点是父亲的左孩子还是有孩子,左孩子则直接旋转,恢复平衡;若是右孩子则需先右旋再左旋恢复平衡。具体分析:
我们之分析父亲是祖父的左孩子的情况,因为右孩子的情况是对称的。
7. 1 叔叔为黑色,我是父亲的左孩子。
先染色,将父亲和曾祖父的颜色互换,为右旋做准备,之后右旋操作,恢复平衡。
2.2 叔叔为黑色,我是父亲的右孩子,比2.2多了一步操作,调整思路,将右孩子通过左旋操作,变为情景2.2 "我是父亲的左孩子"的情况。
结论:插入操作的旋转,最多只需要两步旋转操作,可能需要多步染色操作。
rbtree是自底向上添加层级的,如果旋转染色后根节点变成红色,则要把根节点染成黑色,这样就增加了rbtree的“黑高”
删除操作:
二叉树的删除操作都可以转换为删除叶子节点的操作,只是将叶子节点的值替换到删除节点上,然后删除叶子节点,该叶子节点我们称它为替代节点。然后情况就简单了许多,只讨论删除叶子节点。
由于对称性,我们也只讨论一侧的情况。
情景1. 替代节点为红色,则直接删除,不会影响树的“黑高”。
情景2: 替代节点是黑色,删除会影响“黑高”,所以需要做染色旋转操作。再细分:
先来看可以直接恢复平衡的情况:
情景2.1.2.1
我(替代节点,即将删除)是黑色,兄弟是黑 + 兄弟的左孩子为黑,右孩子为红。
其他情况最后都可以转换成2.1.2.1的情况。
情景2.1.2.2:
我(替代节点,即将删除)是黑色,兄弟是黑+ 兄弟的左孩子为红,右孩子为黑。 通过染色右旋转换成2.1.2.1的情况。
情景2.1.2.3:
我(替代节点,即将删除)是黑色,兄弟是黑+ 兄弟的两孩子都为黑。 只给兄弟染色,然后将父亲当作当前节点,再向上调整。
情景2.1.1:
我(替代节点,即将删除)是黑色,兄弟是红色,由于对称性只讨论我是父亲的左孩子的情况。
转换成2.2.1.3的对称侧,兄弟节点是红色,兄的两个儿子是黑色,但是我是父亲的右孩子,解法是同理。
结论:所以删除操作最多需要三次旋转。
使用实例:
java集合中的TreeSet和TreeMap,C++ STL中的set、map,以及Linux虚拟内存的管理,
二叉树python实现:
#-*- coding: UTF-8 -*- class bNode: def __init__(self, dat): self.data = dat self.lchild = None self.rchild = None class bTree: def __init__(self): self.root = None # from left to right to insert def insert(self, node): #广度优先插入 if self.root == None: self.root = node return cur_node = self.root #board travel queue = [cur_node] while queue : node_itr = queue.pop(0) if node_itr.lchild: queue.append(node_itr.lchild) else: node_itr.lchild = node return if node_itr.rchild: queue.append(node_itr.lchild) else: node_itr.rchild = node return def first_travel(self, root, func): if not root: return if func: func(root.data) self.first_travel(root.lchild, func) self.first_travel(root.rchild, func) def middle_travel(self, root, func): if not root: return self.middle_travel(root.lchild, func) if func: func(root.data) self.middle_travel(root.rchild, func) def last_travel(self, root, func): if not root: return self.last_travel(root.lchild, func) self.last_travel(root.rchild, func) if func: func(root.data) def broad_travel(self, root, func): queue = [root] while queue: node = queue.pop(0) func(node.data) if node.lchild: queue.append(node.lchild) if node.rchild: queue.append(node.rchild) def printf(data): print("%d " % data) def main(): root_tree = bTree() root_tree.insert(bNode(8)) root_tree.insert(bNode(10)) root_tree.insert(bNode(12)) root_tree.insert(bNode(0)) root_tree.insert(bNode(100)) root_tree.insert(bNode(101)) print("first_travel:") root_tree.first_travel(root_tree.root, printf) print("middle_travel:") root_tree.middle_travel(root_tree.root, printf) print("last_travel:") root_tree.last_travel(root_tree.root, printf) print("broad_travel:") root_tree.broad_travel(root_tree.root, printf) if __name__ == "__main__": main()
二叉搜索树,又名二叉排序树,是按顺序插入,左子树都比根节点小,右子树都比根节点大。
# a value is only once class bsTree(bTree): def insert(self, node): if self.root == None: self.root = node return cur_node = self.root while cur_node: if cur_node.data < node.data: if cur_node.rchild: cur_node = cur_node.rchild else: cur_node.rchild = node elif cur_node.data > node.data: if cur_node.lchild: cur_node = cur_node.lchild else: cur_node.lchild = node else: #already have return def delete(self, data): if self.root == None: return cur_node = self.root parent_node = None b_lchild = True # 0:left child 1:right child while cur_node: if cur_node.data < data: if cur_node.rchild: parent_node = cur_node b_lchild = False cur_node = cur_node.rchild elif cur_node.data > data: if cur_node.lchild: parent_node = cur_node cur_node = cur_node.lchild else: #find if not cur_node.lchild and not cur_node.rchild: ## no child if parent_node: if b_lchild: parent_node.lchild = None else : parent_node.rchild = None else : #root self.root = None return else : if not cur_node.lchild or not cur_node.rchild: ## with one child if cur_node.lchild: if parent_node: if b_lchild: parent_node.lchild = cur_node.lchild else : parent_node.rchild = cur_node.lchild else: self.root = cur_node.lchild return if cur_node.rchild: if parent_node: if b_lchild: parent_node.lchild = cur_node.rchild else : parent_node.rchild = cur_node.rchild else: self.root = cur_node.rchild return else: ## with two child tmp_node = cur_node.rchild if not tmp_node.lchild: if parent_node: if b_lchild: parent_node.lchild = tmp_node else : parent_node.rchild = tmp_node else: tmp_node.lchild = self.root.lchild self.root = tmp_node return while tmp_node.lchild.lchild: tmp_node = tmp_node.lchild cur_node.data = tmp_node.lchild.data ## switch with right child 's leftmost tmp_node.lchild = None def main_bstree(): root_tree = bsTree() root_tree.insert(bNode(8)) root_tree.insert(bNode(10)) root_tree.insert(bNode(12)) root_tree.insert(bNode(0)) root_tree.insert(bNode(100)) root_tree.insert(bNode(101)) print("first_travel:") root_tree.first_travel(root_tree.root, printf) print("middle_travel:") root_tree.middle_travel(root_tree.root, printf) print("last_travel:") root_tree.last_travel(root_tree.root, printf) print("broad_travel:") root_tree.broad_travel(root_tree.root, printf) root_tree.delete(10) print("2 middle_travel:") root_tree.middle_travel(root_tree.root, printf) if __name__ == "__main__": main_bstree()
二叉搜索树的时间复杂度最坏的情况下可能退化成链表,时间复杂度为O(n); 二叉树的搜索次数为树的层级。调整搜索树的层级,使其达到平衡均匀,看看平衡的二叉树的策略。
平衡搜索二叉树,要点左右子树的高度差不超过1;也就是小于2。那么AVL的搜索时间复杂度就是O(logn)。
AVL在插入和删除的时候可能会打破其平衡结构,所以在插入/删除时需要做旋转操作,维持其平衡。由插入节点的层逐层向上判断是否失去平衡,若失去,则作旋转,回复平衡,这个代码中可以通过递归来实现。
LL/RR旋转
特点:搜索二叉树特性,左子树<root<右子树。
LL/RR 结构则是出现在排序后的两端,,即大端或小端,即左子树的左节点,或右子树的右节点。由于类似,我们只讨论LL旋转。
图示:
旋转三步走:
1.断,2连,3替换。
LR/RL旋转
特点:插入的节点在排序后的中间,即左子树的右节点或右子树的左节点。则需要经过两次旋转,才能达到平衡。
以LR为例。先右旋调整为LL结构,在左旋达到平衡。
图示:
先以B为基准进行RR旋转,转化成LL结构,在以A为基准进行LL旋转达到平衡。
注:写代码时基准都是A,因为A的左右子树高度差>1了,所以做递归的判断,函数实现传入的参数为A。
代码实现:
要点,删除/插入后,判断高度差,大于2则要调整。每一层都要做。
改善AVL,如果插入时高度差没变化,则不在向上做判断和调整。
代码:
#include<bits/stdc++.h> using namespace std; struct Node{ Node *left; Node *right; int val; int height; void UpdateHeight(){ int Left = left ? left->height : 0; int Right = right ? right->height : 0; height = max(Left, Right) + 1; } int cal_height(){ int Left = left ? left->height : 0; int Right = right ? right->height : 0; return Left - Right; } }; Node* LL(Node* node){ Node* Right = node->right; Node* Left = Right->left; Right->left = node; node->right = Left; node->UpdateHeight(); Right->UpdateHeight(); return Right; } Node* RR(Node* node){ Node* Left = node->left; Node* Right = Left->right; Left->right = node; node->left = Right; node->UpdateHeight(); Left->UpdateHeight(); return Left; } Node *RL(Node* node){ node->right = RR(node->right); return LL(node); } Node *LR(Node* node){ node->left = LL(node->left); return RR(node); } Node* Insert(Node* node, int val){ if(node == NULL){ node = new Node(); node->val = val; // return node; } else if(val > node->val){ node->right = Insert(node->right, val); int Height = node->cal_height(); if(Height == -2){ if(val > node->right->val){ node = LL(node); } else node = RL(node); } } else { node->left = Insert(node->left, val); int Height = node->cal_height(); if(Height == 2){ if(val < node->left->val){ node = RR(node); } else node = LR(node); } } node->UpdateHeight(); return node; } Node *Delete(Node* node, int val){ if(node == NULL){ return NULL; } else if(node->val > val){ node->left = Delete(node->left, val); } else if(node->val < val){ node->right = Delete(node->right, val); } else { if(node->left){ Node* tmp; for(tmp = node->left; tmp->right != NULL; tmp = tmp->right); node->val = tmp->val; node->left = Delete(node->left, node->val); } else if(node->right){ Node *tmp; for(tmp = node->right; tmp->left != NULL; tmp = tmp->left); node->val = tmp->val; node->right =Delete(node->right, node->val); } else { delete(node); return NULL; } } if(node->cal_height()==2) { if(node->left->cal_height()==1) node = RR(node); else node = LR(node); } else if(node->cal_height()==-2) { if(node->right->cal_height()==-1) node = LL(node); else node = RL(node); } node->UpdateHeight(); return node; } void pre_travel(Node* node) { if(node==NULL) return; printf("%d ",node->val); pre_travel(node->left); pre_travel(node->right); } int main(){ Node *root = NULL; root = Insert(root, 5); // cout << 5 << endl; root = Insert(root, 6); // cout << 6 << endl; root = Insert(root, 3); // cout << 3 << endl; // root = Insert(root, 3); root = Insert(root, 2); // cout << 2 << endl; root = Insert(root, 4); // cout << 4 << endl; root = Insert(root, 1); // cout << 1 << endl; root = Insert(root, 9); cout << 9 << endl; root = Insert(root, 8); cout << 8 << endl; root = Insert(root, 7); cout << 7 << endl; root = Delete(root,6); root = Delete(root,1); printf("\n先序遍历:\n"); pre_travel(root); printf("\n"); printf("\n"); return 0; }
https://www.jianshu.com/p/e136ec79235c
https://www.cnblogs.com/letlifestop/p/11587354.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。