3.红黑树
1.AVL
每添加一个节点都要判断一次左右子树的高度差然后相应地进行左右旋转
当右子树高度大于左子树高度时,且高度差大于1:
左旋转:(本质:让一个更适中的数作根节点使得两边的节点数差不多,以此达到平衡)
1.创建一个新的节点,值等于当前根节点的值:Node*newNode=new Node(root->value);
2.把新节点的左子树设置为当前节点的左子树:newNode->left=left;
3.把新节点的右子树设置为当前节点的右子树的左子树:newNode->right=right->left;
4.把当前节点的值换为右子节点的值:value=right->value;
5.把当前节点的右子树设置成右子树的右子树:right=right->right;
6.把当前节点的左子树设置为新节点:left=newNode;
当左子树高度大于左子树高度时,且高度差大于1:
右旋转:
1.创建一个新的节点,值等于当前根节点的值:Node*newNode=new Node(root->value);
2.把新节点的右子树设置为当前节点的右子树:newNode->rihgt=right;
3.把新节点的左子树设置为当前节点的左子树的右子树:newNode->left=left->right;
4.把当前节点的值换为左子节点的值:value=left->value;
5.把当前节点的左子树设置成左子树的左子树:left=left->left;
6.把当前节点的左子树设置为新节点 right=newNode;
问题分析:
1.符合右旋转条件
2.如果当前节点的左子树的右子树高度大于它的左子树的左子树的高度
3.先对当前节点的左节点进行左旋转
4.再对当前节点进行右旋转
//创建节点
class Node {
public:
int value;
Node* left = NULL;
Node* right = NULL;
Node(int value) {
this->value = value;
}
//返回左子树高度
int leftheight() {
if (left == NULL) {
return 0;
}
return left->height();
}
//返回右子树高度
int rightheight() {
if (right == NULL) {
return 0;
}
return right->height();
}
//返回以该节点为根节点的树的高度
int height() {
return max(left ? left->height() : 0, right ? right->height() : 0)+1 ;
}
//左旋转方法
void leftRotate() {
//创建新的节点,以当前根节点的值
Node* newNode = new Node(value);
//把新节点的左子树设置为当前节点的左子树
newNode->left = left;
//把新的节点的右子树设置为当前节点的右子树的左子树
newNode->right = right->left;
//把当前节点的值替换成右子节点的值
value = right->value;
//把当前节点的右子树设置成右子树的右子树
right = right->right;
//把当前节点的左子树设置成新的节点
left = newNode;
}
void rightRotate() {
Node* newNode = new Node(value);
newNode->right = right;
newNode->left = left->right;
value = left->value;
left = left->left;
right = newNode;
}
//查找要删除的节点
Node* research(int value) {
if (value == this->value) {//就是该节点
return this;
}
else if (value < this->value) {//如果查找的值小于当前节点,向左子树递归
if (this->left == NULL)return NULL;
return this->left->research(value);
}
else {
if (this->right == NULL)return NULL;
return this->right->research(value);
}
}
//查找要删除节点的父节点
Node* searchParent(int value) {
if ((this->left != NULL && this->left->value == value) ||
(this->right != NULL && this->right->value == value)) {
return this;
}
else {
//如果查找的值小于当前节点的值,并且当前节点的左子节点不为空
if (value < this->value && this->left != NULL) {
return this->left->searchParent(value);//向左子树递归查找
}
else if (value >= this->value && this->right != NULL) {
return this->right->searchParent(value);
}
else {
return NULL;//没有父节点
}
}
}
//添加节点
//递归的形式添加节点,注意需要满足树的要求
void add(Node* node) {
if (!node) return;
//判断传入的节点的值和当前节点值得关系
if (node->value < this->value) {
//如果当前节点的左子节点为空
if (this->left == NULL) {
this->left = node;
}
else {
//递归向左子树添加
this->left->add(node);
}
}
else {//添加的节点的值大于当前节点的值
if (this->right == NULL) {
this->right = node;
}
else {
//递归向右子树添加
this->right->add(node);
}
}
//当添加完一个节点后,如果:(右子树的高度-左子树高度)>1,左旋转
if (rightheight() - leftheight() > 1) {
//如果它的右子树的左子树高度大于它的右子树的右子树的高度
if (right != NULL && right->leftheight() > right->rightheight()) {
right->rightRotate();
}
leftRotate();
return;//直接return,不然还要接下去做判断,以免引起不必要的bug
}
//当添加完一个节点,如果(左子树的高度-右子树的高度)>1,右旋转
if (leftheight() - rightheight() > 1) {
//如果它的左子树的右子树高度大于它的左子树的左子树的高度
if (left != NULL && left->rightheight() > left->leftheight()) {
//先对当前这个节点的左节点进行左旋转
left->leftRotate();
}
rightRotate();
return;
}
}
//1.返回以node为根节点的树的最小节点的值
//2.删除以node为根节点的树的最小节点
int delRightTreeMin(Node* node) {//node当作一棵树的根节点,返回以node为根节点的树的最小
//节点的值
Node* target = node;
//循环查找左节点,就会找到最小值
while (target->left != NULL) {
target = target->left;
}
//这时target就指向了最小节点
//删除最小节点,最小节点必然无子树,所以不会调用本函数
delNode(target->value);
return target->value;
}
//删除节点
void delNode(int value) {
if (root == NULL)return;
//1.需要先去找到要删除的节点targetNode
Node* targetNode = search(value);
//2.如果没有找到要删除的节点
if (targetNode == NULL) {
return;
}
//如果该树只有一个节点,且存在值为value的节点,那必然是root
if (root->left == NULL && root->right == NULL) {
root = NULL;
return;
}
//寻找targetNode的父节点
Node* parent = searchParent(value);
//删除叶子节点
if (targetNode->left == NULL && targetNode->right == NULL) {
//判断targetNode是父节点的左子节点。还是右子节点
if (parent->left != NULL && parent->left->value == value) {
parent->left = NULL;
}
else if (parent->right != NULL && parent->right->value == value) {
parent->value = NULL;
}
}
else if (targetNode->left!=NULL&&targetNode->right!=NULL) {//删除有两棵子树的节点
int minVal = delRightTreeMin(targetNode->right);
targetNode->value = minVal;
}
else {//删除只有一棵子树的节点,关键:当树只剩两个节点时,要注意父节点可能为空
//如果要删除的节点有左子节点
if (targetNode->left != NULL) {
if (parent != NULL) {
//如果targetNode是parent的左子节点
if (parent->left->value == value) {
parent->left = targetNode->left;
}
else {//targetNode是parent的右子节点
parent->right = targetNode->left;
}
}
else {
root = targetNode->left;
}
}
else {
if (parent != NULL) {
//如果targetNode是parent的左子节点
if (parent->left->value == value) {
parent->left = targetNode->right;
}
else {//targetNode是parent的右子节点
parent->right = targetNode->right;
}
}
else {
root = targetNode->right;
}
}
}
}
};
2.SB树
3.红黑树
红黑树:
1.每个结点不是红就是黑
2.头结点,叶节点(最下面的空白区域)必须为黑
3.红结点之间不相邻
4.从头部cur出发,每条到结束的路黑结点一样多。因为是红黑交替,所以可以保证长度大概一致