算法第四版- 3.3
1.红黑树
红黑树漫画
红黑树有点难。就先不讲了。。。
2.AVL树
AVL树漫画
AVL树的查找和BST一样。重点在于插入和删除时的保持平衡操作。
1)判断是否为平衡二叉树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isBalanced(TreeNode* root) {
return height(root)>=0 ;
}
int height(TreeNode *root)
{
if(root==nullptr)
return 0;
int height_left=height(root->left);
int height_right=height(root->right);
if(height_left==-1 || height_right==-1 || abs(height_left-height_right)>1)
return -1;
else
return 1+max(height_right,height_left);
}
};
简单的递归。-1就是子树已经崩了,那上面也肯定要崩。
2)插入和删除
AVLTree的插入与删除
主要可以参考以上博客。把inline全删去就能跑。分离式编译用inline好像会出问题。
下面是测试代码和运行结果:
//main.cpp
#include <iostream>
#include "AVLTree.h"
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
AVLTree tree1;
vector<int> v1 = { 1,2,3,4,5 };
random_shuffle(v1.begin(), v1.end());
for (int i : v1) tree1.insert(i);
tree1.inOrder();
cout << endl;
return 0;
}
中序遍历成功,random_shuffle为随机重排算法。
然后对AVLTree.h和AVLTree.cpp写了一点注释,配合小灰的漫画,便于理解。
//AVLTree.h
#pragma once
typedef int ElemType;
struct AVLTreeNode {
ElemType val;
int height;
AVLTreeNode* left;
AVLTreeNode* right;
AVLTreeNode(const ElemType& _val = ElemType(), const int& _height = int(),
AVLTreeNode* _left = nullptr, AVLTreeNode* _right = nullptr)
: val(_val), height(_height), left(_left), right(_right) {}
};
class AVLTree {
public:
AVLTree(void) { root = nullptr; }
~AVLTree(void) { clear(root); }
void insert(const ElemType&);
void erase(const ElemType&);
void inOrder(void) { inOrder(root); }
private:
AVLTreeNode* rotateRR(AVLTreeNode*);
AVLTreeNode* rotateRL(AVLTreeNode*);
AVLTreeNode* rotateLR(AVLTreeNode*);
AVLTreeNode* rotateLL(AVLTreeNode*);
AVLTreeNode* insert(AVLTreeNode*, const ElemType&);
AVLTreeNode* erase(AVLTreeNode*, const ElemType&);
int getHeight(AVLTreeNode*);
void clear(AVLTreeNode*);
void inOrder(AVLTreeNode*);
private:
AVLTreeNode* root;
};
下面是cpp代码
//AVLTree.cpp
#include <algorithm>
#include <iostream>
#include "AVLTree.h"
void AVLTree::insert(const ElemType& val) {
root = insert(root, val);
}
void AVLTree::erase(const ElemType& val) {
root = erase(root, val);
}
//这个对应的是LL局面
AVLTreeNode* AVLTree::rotateRR(AVLTreeNode* node) { //node为A节点
AVLTreeNode* child = node->left; //child为B节点
AVLTreeNode* rGrandchild = child->right; //rGrandchild为3号节点
child->right = node; //把A接到B的右边
node->left = rGrandchild; //把3号节点接到A的左边
node->height = 1 + std::max(getHeight(node->left), getHeight(node->right));
child->height = 1 + std::max(getHeight(node), getHeight(child->left)); //max的两个参数为A和C
return child; //B节点变为根节点
}
//这个对应于RL局面
AVLTreeNode* AVLTree::rotateRL(AVLTreeNode* node) {
node->right = rotateRR(node->right); //对B进行右旋,转化为RR局面
return rotateLL(node); //对A节点左旋
}
//这个对应于LR局面
AVLTreeNode* AVLTree::rotateLR(AVLTreeNode* node) {
node->left = rotateLL(node->left); //对B节点进行左旋,转化为LL局面
return rotateRR(node); //现在是LL局面,对A节点进行右旋
}
//这个对应的是RR局面
AVLTreeNode* AVLTree::rotateLL(AVLTreeNode* node) { //node为A节点
AVLTreeNode* child = node->right; //child为B节点
AVLTreeNode* lGrandchild = child->left; //lGrandchild为2号节点
child->left = node; //把A节点安到B的左边
node->right = lGrandchild; //把2号节点安到A的右边
node->height = 1 + std::max(getHeight(node->left), getHeight(node->right));
child->height = 1 + std::max(getHeight(node), getHeight(child->right));
return child; //B节点变为根节点
}
//先插入节点,然后发现不平衡了,一步步往上走的过程中进行调整
AVLTreeNode* AVLTree::insert(AVLTreeNode* node, const ElemType& val) {
if (nullptr == node) {
node = new AVLTreeNode(val);
}
else if (node->val < val) {
node->right = insert(node->right, val);
}
else {
node->left = insert(node->left, val);
}
node->height = 1 + std::max(getHeight(node->left), getHeight(node->right));
if (getHeight(node->left) - getHeight(node->right) >= 2) { //node为4号节点
if (node->left->val < val) {
node = rotateLR(node);
}
else { //显然2>1,进行右旋
node = rotateRR(node);
}
}
else if (getHeight(node->right) - getHeight(node->left) >= 2) {
if (node->right->val < val) {
node = rotateLL(node);
}
else {
node = rotateRL(node);
}
}
return node;
}
AVLTreeNode* AVLTree::erase(AVLTreeNode* node, const ElemType& val) {
if (nullptr == node) {
return nullptr;
}
//找到目标节点
if (val == node->val) {
if (nullptr == node->left) {
AVLTreeNode* tmp = node;
node = node->right;
delete tmp;
return node;
}
else if (nullptr == node->right) {
AVLTreeNode* tmp = node;
node = node->left;
delete tmp;
return node;
}
else { //比如要删除2,左右节点均不为空
AVLTreeNode* tmp = node->right; //tmp=4
while (tmp->left) { //右子树的最小节点,即在子树中中序排序后删除的节点的右一位,tmp为最小的节点3
tmp = tmp->left;
}
node->val = tmp->val; //把2的值改为3
node->right = erase(node->right, tmp->val); //删除3节点
}
}
//没有找到目标节点
else if (node->val < val) {
node->right = erase(node->right, val);
}
else {
node->left = erase(node->left, val);
}
//这个时候已经删好了,开始调整高度
node->height = 1 + std::max(getHeight(node->left), getHeight(node->right));
if (getHeight(node->left) - getHeight(node->right) >= 2) {
if (getHeight(node->left->left) > getHeight(node->left->right)) {
node = rotateLR(node);
}
else {
node = rotateRR(node);
}
}
else if (getHeight(node->right) - getHeight(node->left) >= 2) {
if (getHeight(node->right->right) > getHeight(node->right->left)) {
node = rotateLL(node);
}
else { //显然0<1,走这条路,先右旋再左旋。
node = rotateRL(node);
}
}
return node;
}
int AVLTree::getHeight(AVLTreeNode* node) {
return nullptr == node ? -1 : node->height;
}
void AVLTree::inOrder(AVLTreeNode* node) {
if (nullptr == node) {
return;
}
inOrder(node->left);
// output
std::cout << node->val;
inOrder(node->right);
}
void AVLTree::clear(AVLTreeNode* node) {
if (nullptr != node) {
clear(node->left);
clear(node->right);
delete node;
node = nullptr;
}
}