一、搜索二叉树(二叉排序树)
1、特点:
a.左子树上所有结点的值都小于根结点的值,右子树上所有结点的值都大于根结点的值,左右子树也分别为二叉搜索树
b.最多找高度次:O(N)
2、代码逻辑
a. 没有孩子(托孤)
b. 一个孩子(托孤)
c. 两个孩子(替换法:左子树的最大节点/最右节点,或者右子树的最小节点/最左节点)
#pragma once
namespace key
{
template
struct BSTreeNode
{
BSTreeNode* _left;
BSTreeNode* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
,_right(nullptr)
,_key(key)
{}
};
template
class BSTree
{
typedef BSTreeNode Node;
public:
BSTree()
:_root(nullptr)
{}
BSTree(const BSTree& t)
/*:_root(t._root)*/
{
_root = Copy(t._root);
}
BSTree& operator=(BSTree t)
{
swap(_root, t._root);
return *this;
}
~BSTree()
{
Destroy(_root);
}
bool Insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while(cur)
{
if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(key);
if (key < parent->_key)
{
parent->_left = cur;
}
else if (key > parent->_key)
{
parent->_right = cur;
}
else
{
return false;
}
return true;
}
bool InsertR(const K& key)
{
return _InsertR(_root, key);
}
bool find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (key < cur->_key)
{
cur = cur->_left;
}
else if (key > cur->_key)
{
cur = cur->_right;
}
else
{
return true;
}
}
return false;
}
bool FindR(const K& key)
{
return _FindR(_root, key);
}
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
{
//左为空
if (cur->_left == nullptr)
{
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (parent->_right == cur)
{
parent->_right = cur->_right;
}
else
{
parent->_left = cur->_right;
}
}
}
//右为空
else if (cur->_right == nullptr)
{
if (cur == _root)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
}
//左右都不为空
else
{
Node* parnet = cur;
Node* leftmax = cur->_left;//找左枝最大节点
while (leftmax->_right)
{
parent = leftmax;
leftmax = leftmax->_right;
}
swap(leftmax->_key, cur->_key);
if (parent->_left == leftmax)
{
parent->_left = leftmax->_left;
}
else
{
parent->_right = leftmax->_left;
}
cur = leftmax;
}
delete cur;
return true;
}
}
}
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
void Inorder()
{
_Inorder(_root);
cout << endl;
}
private:
Node* Copy(Node* root)
{
if(root == nullptr)
{
return nullptr;
}
Node* copyroot = new Node(root->_key);
Copy(root->_left);
Copy(root->_right);
return copyroot;
}
void Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
Destroy(root->_left);
Destroy(root->_right);
delete root;
root = nullptr;
}
void _Inorder(Node* root)
{
if (root == nullptr)
{
return;
}
_Inorder(root->_left);
cout << root->_key << " ";
_Inorder(root->_right);
}
bool _FindR(Node* root, const K& key)
{
if (root == nullptr)
{
return false;
}
if (key < root->_key)
{
FindR(root->_left);
}
else if (key > root->_key)
{
FindR(root->_right);
}
else
{
return true;
}
}
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (key < root->_key)
{
return _InsertR(root->_left, key);
}
else if (key > root->_key)
{
return _InsertR(root->_right, key);
}
else
{
return false;
}
}
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
{
return false;
}
if (key < root->_key)
{
return _EraseR(root->_left, key);
}
else if (key > root->_key)
{
return _EraseR(root->_right, key);
}
else
{
Node* del = root;
//左为空
if (root->_left == nullptr)
{
root = root->_right;
}
//右为空
else if (root->_right == nullptr)
{
root = root->_left;
}
//左右都不为空
else
{
Node* leftmax = root->_left;//找左枝最大节点
while (leftmax->_right)
{
leftmax = leftmax->_right;
}
swap(leftmax->_key, root->_key);
return _EraseR(root->_left, key);
}
delete del;
return true;
}
}
private:
Node* _root;
};
}
二、AVL树(高度平衡二叉搜索树)
1、特点:
a.左右子树都是avl树
b.左右子树高度之差(简称平衡因子)的绝对值不超过1(平衡因子=右子树的高度-左子树的高度)
2、代码逻辑
新增在左,parent平衡因子--。
新增在右,parent平衡因子++。
更新后parent平衡因子=0,说明parent所在的子数的高度不变,不会再影响祖先,不用再继续(沿着到root的路径)往上更新。
更新后parent平衡因子=-1/1,说明parent所在的子数的高度变化,会影响祖先,需要继续(沿着到root的路径)往上更新。
更新后parent平衡因子=-2/2,说明parent所在的子树的高度变化且不平衡,对parent所在的子树进行旋转,使之平衡。
#pragma once
#include
#include
using namespace std;
template
struct AVLTreeNode
{
pair _kv;
AVLTreeNode* _left;
AVLTreeNode* _right;
AVLTreeNode* _parent;
int _bf;
AVLTreeNode(const pair& kv)
:_kv(kv)
,_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_bf(0)
{}
};
template
struct AVLTree
{
typedef AVLTreeNode Node;
public:
bool Insert(const pair& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(kv);
if (kv.first < parent->_kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//控制平衡:更新平衡因子
while (parent)
{
if (parent->_left == cur)
{
parent->_bf--;
}
else if (parent->_right == cur)
{
parent->_bf++;
}
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == -1 || parent->_bf == 1)
{
//继续向上更新
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == -2 || parent->_bf == 2)
{
if (parent->_bf == -2 && cur->_bf == -1)
{
RotateR(parent);
}
else if (parent->_bf == 2 && cur->_bf == 1)
{
RotateL(parent);
}
else if (parent->_bf == -2 && cur->_bf == 1)
{
RotateLR(parent);
}
else if (parent->_bf == 2 && cur->_bf == -1)
{
RotateRL(parent);
}
break;
}
else
{
assert(false);
}
}
return true;
}
void RotateL(Node* parent)
{
Node* cur = parent->_right;
Node* curleft = cur->_left;
parent->_right = curleft;
if (curleft)
{
curleft->_parent = parent;
}
cur->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = cur;
if (parent == _root)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (parent == ppnode->_left)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
parent->_bf = cur->_bf = 0;
}
void RotateR(Node* parent)
{
Node* cur = parent->_left;
Node* curright = cur->_right;
parent->_left = curright;
if (curright)
{
curright->_parent = parent;
}
Node* ppnode = parent->_parent;
cur->_right = parent;
parent-> _parent = cur;
if (parent == _root)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
parent->_bf = cur->_bf = 0;
}
void RotateRL(Node* parent)
{
Node* cur = parent->_right;
Node* curleft = cur->_left;
int bf = curleft->_bf;
RotateR(cur);
RotateL(parent);
if (bf == 0)
{
parent->_bf = 0;
cur->_bf = 0;
curleft->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 0;
cur->_bf = 1;
curleft->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
cur->_bf = 0;
curleft->_bf = 0;
}
else
{
assert(false);
}
}
void RotateLR(Node* parent)
{
Node* cur = parent->_left;
Node* curright = cur->_right;
RotateL(cur);
RotateR(parent);
int bf = curright->_bf;
if (bf == 0)
{
parent->_bf = 0;
cur->_bf = 0;
curright->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
cur->_bf = 0;
curright->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = 0;
cur->_bf = -1;
curright->_bf = 0;
}
else
{
assert(false);
}
}
int Height()
{
return _Height(_root);
}
bool IsBalance()
{
return _IsBalance(_root);
}
private:
int _Height(Node* root)
{
if (root == nullptr)
{
return 0;
}
int LeftHeight = _Height(root->_left);
int RightHeight = _Height(root->_right);
return LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1;
}
bool _IsBalance(Node* root)
{
if (root == nullptr)
{
return true;
}
int LeftHeight = _Height(root->_left);
int RightHeight = _Height(root->_right);
if (RightHeight - LeftHeight != root->_bf)
{
cout << "平衡因子异常:" << _root->_kv.first << "->" << _root->_bf << endl;
return false;
}
return abs(RightHeight - LeftHeight) < 2
&& _IsBalance(root->_left)
&& _IsBalance(root->_right);
}
private:
Node* _root = nullptr;
};
三、红黑树
1、红黑树特点:
a.每个节点不是黑色就是红色(根节点是黑色的,NIL叶节点都为黑色)
b.如果一个节点是红色的,则它的两个孩子节点必须是黑色的(任何路径没有连续红节点)
c.每条路径上都包含相同数量的黑节点
b.黑色节点占比>=1/2
e.最长路径不超过最短路径的2倍(近似平衡)(从根到空节点NIL算一条路径),最短全黑,最长一黑一红相间
2、代码逻辑
红黑树插入关键看uncle
1、uncle存在且为红,变色+继续向上更新
2、uncle不存在,uncle存在且为黑,旋转+变色
#pragma once
#include
using namespace std;
enum Color
{
RED,
BLACK
};
template
struct RBTreeNode
{
RBTreeNode* _left;
RBTreeNode* _right;
RBTreeNode* _parent;
pair _kv;
Color _col;
RBTreeNode(const pair& kv)
: _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
,_col(RED)
{}
};
template
struct RBTree
{
typedef RBTreeNode Node;
public:
bool Insert(const pair& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kv.first < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
cur = new Node(kv);
cur->_col = RED;
if (kv.first < parent->_kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//如果父亲为黑,无需处理
//如果父亲为红
while (parent && parent->_col == RED)
{
Node* grandparent = parent->_parent;
//Node* uncle;//有可能没有叔叔节点
if (grandparent->_left == parent)
{
Node* uncle = grandparent->_right;
//叔叔节点存在且为红
if (uncle && uncle->_col == RED)
{
// g(R)
//
// p(B) u(B)
parent->_col = uncle->_col = BLACK;
grandparent->_col = RED;
//向上处理
cur = grandparent;
parent = cur->_parent;
}
//叔叔节点为黑或者叔叔节点不存在
else
{
// g(B) p(B)
// p(R) (u(B)) -> c(R) g(R)
//c(R) (u)
if (cur == parent->_left)
{
RotateR(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
// g(B) c(B)
//p(R) ->
// c(R) p(R) g(R)
else
{
RotateL(parent);
RotateR(grandparent);
cur->_col = BLACK;
grandparent->_col = RED;
}
break;
}
}
else
{
Node* uncle = grandparent->_left;
//叔叔节点存在且为红
if (uncle && uncle->_col == RED)
{
// g(R)
//
// u(B) p(B)
parent->_col = uncle->_col = BLACK;
grandparent->_col = RED;
//向上处理
cur = grandparent;
parent = cur->_parent;
}
//叔叔节点为黑或者叔叔节点不存在
else
{
// g(B) p(B)
// (u(R)) p(B) -> g(R) c(R)
// c(R) (u)
if (cur == parent->_right)
{
RotateL(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
//g(B) c(B)
// p(R) ->
//c(R) g(R) p(R)
else
{
RotateR(parent);
RotateL(grandparent);
cur->_col = BLACK;
grandparent->_col = RED;
}
}
}
}
}
_root->_col = BLACK;
return true;
}
void RotateL(Node* parent)
{
Node* cur = parent->_right;
Node* curleft = cur->_left;
parent->_right = curleft;
if (curleft)
{
curleft->_parent = parent;
}
cur->_left = parent;
Node* ppnode = parent->_parent;
parent->_parent = cur;
if (parent == _root)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
}
void RotateR(Node* parent)
{
Node* cur = parent->_left;
Node* curright = cur->_right;
parent->_left = curright;
if (curright)
curright->_parent = parent;
Node* ppnode = parent->_parent;
cur->_right = parent;
parent->_parent = cur;
if (ppnode == nullptr)
{
_root = cur;
cur->_parent = nullptr;
}
else
{
if (ppnode->_left == parent)
{
ppnode->_left = cur;
}
else
{
ppnode->_right = cur;
}
cur->_parent = ppnode;
}
}
int Height()
{
return Height(_root);
}
int Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = Height(root->_left);
int rightHeight = Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
//判断颜色:根为黑色,不能出现连续红色节点
bool checkcolor(Node* root, int blacknum, int benchmark)
{
if (root == nullptr)
{
if (blacknum != benchmark)
{
return false;
}
return true;
}
if (root->_col == BLACK)
{
++blacknum;
}
if (root->_col == RED && root->_parent && root->_parent->_col == RED)
{
cout << root->_kv.first << "出现连续红色节点" << endl;
return false;
}
return checkcolor(root->_left, blacknum, benchmark)
&& checkcolor(root->_right, blacknum, benchmark);
}
bool IsBalance()
{
return _IsBalance(_root);
}
bool _IsBalance(Node* root)
{
if (root == nullptr)
{
return true;
}
if (root->_col != BLACK)
{
return false;
}
int benchmark = 0;
Node* cur = root;
while (cur)
{
if (cur->_col == BLACK)
{
benchmark++;
}
cur = cur->_left;
}
return checkcolor(root, 0, benchmark);
}
private:
Node* _root = nullptr;
};
总结:AVL树和红黑树性能是同一量级的,但是AVL树控制严格平衡是要付出代价的,插入和删除需要进行大量的旋转