SBT树的概念及其相关性质
众所周知二叉搜索树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(logN)。缺点是若待插入的序列是有序的,那么它会退化成单链表,这样查询时间将会退化为O(N)。
AVL树和红黑树对二叉搜索树进行了升级,增加平衡和旋转操作。但是红黑树实现起来比较复杂,AVL过于平衡导致旋转的开销过大。
SBT树是一个相对来讲容易实现,并且平衡性又不错的树。
SBT树相关性质: 任何一个叔叔节点为根的子树节点的个数不能少于侄子节点的个数,比如:
节点的定义
struct SBTNode
{
SBTNode(const pair<K, V>kv = pair<K, V>())
:_kv(kv)
,_left(nullptr)
,_right(nullptr)
,_size(1)
{}
pair<K, V>_kv;
SBTNode<K, V>* _left;
SBTNode<K, V>* _right;
int _size;
};
旋转操作
- LL型违规
LL型违规顾名思义就是根节点左孩子的左孩子的size比根节点右孩子大。
此时我们对根节点进行右旋,让D节点来做叔叔节点,C节点作为D的侄子节点。
但是进行右旋之后,我们会发现B和A的孩子发生了变化,此时需要递归检查它们是否符合BST的性质。
- RR型违规
根节点右孩子的右孩子的size比根节点的左孩子大。
同样的我们也需要对C和A进行递归检查操作。
- LR型违规
LR型是指根节点左孩子的右孩子节点的个数大于根节点右孩子的个数。
经过旋转之后ABE这三个节点的左右孩子发生了变化,因此需要对其进行递归检查。
- RL型违规
RL型是指根节点右孩子的左孩子节点的个数大于根节点左孩子的个数。 经过旋转之后ACF这三个节点的左右孩子发生了变化,因此需要对其进行递归检查。
代码操作:
Node* rightRotate(Node* cur)
{
Node* leftNode = cur->_left;
cur->_left = leftNode->_right;
leftNode->_right = cur;
leftNode->_size = cur->_size;
cur->_size = (cur->_left ? cur->_left->_size : 0) + (cur->_right ? cur->_right->_size : 0) + 1;
return leftNode;
}
Node* leftRotate(Node* cur)
{
Node* rightNode = cur->_right;
cur->_right = rightNode->_left;
rightNode->_left = cur;
rightNode->_size = cur->_size;
cur->_size = (cur->_left ? cur->_left->_size : 0) + (cur->_right ? cur->_right->_size : 0) + 1;
return rightNode;
}
Node* maintain(Node* cur)
{
if (cur == nullptr)
{
return nullptr;
}
int leftSize = cur->_left != nullptr ? cur->_left->_size : 0;
int leftLeftSize = cur->_left && cur->_left->_left ? cur->_left->_left->_size : 0;
int leftRightSize = cur->_left && cur->_left->_right ? cur->_left->_right->_size : 0;
int rightSize = cur->_right ? cur->_right->_size : 0;
int rightLeftSize = cur->_right && cur->_right->_left ? cur->_right->_left->_size : 0;
int rightRightSize = cur->_right && cur->_right->_right ? cur->_right->_right->_size : 0;
if (leftLeftSize > rightSize)
{
cur = rightRotate(cur);
cur->_right = maintain(cur->_right);
cur = maintain(cur);
}
else if (leftRightSize > rightSize)
{
cur->_left = leftRotate(cur->_left);
cur = rightRotate(cur);
cur->_left = maintain(cur->_left);
cur->_right = maintain(cur->_right);
cur = maintain(cur);
}
else if (rightRightSize > leftSize)
{
cur = leftRotate(cur);
cur->_left = maintain(cur->_left);
cur = maintain(cur);
}
else if (rightLeftSize > leftSize)
{
cur->_right = rightRotate(cur->_right);
cur = leftRotate(cur);
cur->_left = maintain(cur->_left);
cur->_right = maintain(cur->_right);
cur = maintain(cur);
}
return cur;
}
插入和删除操作
插入与删除操作与AVL树相同,不过插入时要对路径上的节点中的size+1,删除时-1,并且在返回前对他们进行调整。
Node* add(Node*& cur, const pair<K, V>& kv)
{
if (cur == nullptr)
{
return new Node(kv);
}
else
{
cur->_size++;
if (cur->_kv.first > kv.first)
{
cur->_left = add(cur->_left, kv);
}
else
{
cur->_right = add(cur->_right, kv);
}
}
return maintain(cur);
}
bool insert(const pair<K, V>& kv)
{
Node* lastNode = findLastIndex(kv.first);
if (lastNode && lastNode->_kv.first == kv.first)
{
return false;
}
_root = add(_root, kv);
return true;
}
Node* deleteNode(Node*& cur, const K& key)
{
cur->_size--;
if (cur->_kv.first > key)
{
cur->_left = deleteNode(cur->_left, key);
}
else if (cur->_kv.first < key)
{
cur->_right = deleteNode(cur->_right, key);
}
else
{
if (!cur->_left && !cur->_right)
{
delete cur;
cur = nullptr;
}
else if (!cur->_left && cur->_right)
{
Node* subR = cur->_right;
delete cur;
cur = subR;
}
else if (cur->_left && !cur->_right)
{
Node* subL = cur->_left;
delete cur;
cur = subL;
}
else
{
Node* pre = nullptr;
Node* des = cur->_right;
des->_size--;
while (des->_left)
{
pre = des;
des = des->_left;
des->_size--;
}
if (pre)
{
pre->_left = des->_right;
des->_right = cur->_right;
}
des->_left = cur->_left;
des->_size = des->_left->_size + (des->_right ? des->_right->_size : 0) + 1;
delete cur;
cur = des;
}
}
cur = maintain(cur);
return cur;
}
总代码
#pragma once
#include<math.h>
#include<iostream>
#include<vector>
using namespace std;
template<class K, class V>
struct SBTNode
{
SBTNode(const pair<K, V>kv = pair<K, V>())
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _size(1)
{}
pair<K, V>_kv;
SBTNode<K, V>* _left;
SBTNode<K, V>* _right;
int _size;
};
template<class K, class V>
class SizeBalancedTreeMap {
typedef SBTNode<K, V> Node;
public:
Node* rightRotate(Node* cur)
{
Node* leftNode = cur->_left;
cur->_left = leftNode->_right;
leftNode->_right = cur;
leftNode->_size = cur->_size;
cur->_size = (cur->_left ? cur->_left->_size : 0) + (cur->_right ? cur->_right->_size : 0) + 1;
return leftNode;
}
Node* leftRotate(Node* cur)
{
Node* rightNode = cur->_right;
cur->_right = rightNode->_left;
rightNode->_left = cur;
rightNode->_size = cur->_size;
cur->_size = (cur->_left ? cur->_left->_size : 0) + (cur->_right ? cur->_right->_size : 0) + 1;
return rightNode;
}
Node* maintain(Node* cur)
{
if (cur == nullptr)
{
return nullptr;
}
int leftSize = cur->_left != nullptr ? cur->_left->_size : 0;
int leftLeftSize = cur->_left && cur->_left->_left ? cur->_left->_left->_size : 0;
int leftRightSize = cur->_left && cur->_left->_right ? cur->_left->_right->_size : 0;
int rightSize = cur->_right ? cur->_right->_size : 0;
int rightLeftSize = cur->_right && cur->_right->_left ? cur->_right->_left->_size : 0;
int rightRightSize = cur->_right && cur->_right->_right ? cur->_right->_right->_size : 0;
if (leftLeftSize > rightSize)
{
cur = rightRotate(cur);
cur->_right = maintain(cur->_right);
cur = maintain(cur);
}
else if (leftRightSize > rightSize)
{
cur->_left = leftRotate(cur->_left);
cur = rightRotate(cur);
cur->_left = maintain(cur->_left);
cur->_right = maintain(cur->_right);
cur = maintain(cur);
}
else if (rightRightSize > leftSize)
{
cur = leftRotate(cur);
cur->_left = maintain(cur->_left);
cur = maintain(cur);
}
else if (rightLeftSize > leftSize)
{
cur->_right = rightRotate(cur->_right);
cur = leftRotate(cur);
cur->_left = maintain(cur->_left);
cur->_right = maintain(cur->_right);
cur = maintain(cur);
}
return cur;
}
Node* add(Node*& cur, const pair<K, V>& kv)
{
if (cur == nullptr)
{
return new Node(kv);
}
else
{
cur->_size++;
if (cur->_kv.first > kv.first)
{
cur->_left = add(cur->_left, kv);
}
else
{
cur->_right = add(cur->_right, kv);
}
}
return maintain(cur);
}
bool insert(const pair<K, V>& kv)
{
Node* lastNode = findLastIndex(kv.first);
if (lastNode && lastNode->_kv.first == kv.first)
{
return false;
}
_root = add(_root, kv);
return true;
}
Node* deleteNode(Node*& cur, const K& key)
{
cur->_size--;
if (cur->_kv.first > key)
{
cur->_left = deleteNode(cur->_left, key);
}
else if (cur->_kv.first < key)
{
cur->_right = deleteNode(cur->_right, key);
}
else
{
if (!cur->_left && !cur->_right)
{
delete cur;
cur = nullptr;
}
else if (!cur->_left && cur->_right)
{
Node* subR = cur->_right;
delete cur;
cur = subR;
}
else if (cur->_left && !cur->_right)
{
Node* subL = cur->_left;
delete cur;
cur = subL;
}
else
{
Node* pre = nullptr;
Node* des = cur->_right;
des->_size--;
while (des->_left)
{
pre = des;
des = des->_left;
des->_size--;
}
if (pre)
{
pre->_left = des->_right;
des->_right = cur->_right;
}
des->_left = cur->_left;
des->_size = des->_left->_size + (des->_right ? des->_right->_size : 0) + 1;
delete cur;
cur = des;
}
}
cur = maintain(cur);
return cur;
}
void erase(const K& key)
{
Node* lastNode = findLastIndex(key);
if (lastNode)
_root = deleteNode(_root, key);
else
{
return;
}
}
Node* findLastIndex(const K& key)
{
Node* pre = _root;
Node* cur = _root;
while (cur != nullptr)
{
pre = cur;
if (cur->_kv.first == key)
{
break;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
cur = cur->_right;
}
}
return pre;
}
Node* findLastNoSmallIndex(const K& key)
{
Node* ans = nullptr;
Node* cur = _root;
while (cur != nullptr)
{
if (cur->_kv.first == key)
{
ans = cur;
break;
}
else if (cur->_kv.first > key)
{
ans = cur;
cur = cur->_left;
}
else
{
cur = cur->_right;
}
}
return ans;
}
Node* findLastNoBigIndex(const K& key)
{
Node* ans = nullptr;
Node* cur = _root;
while (cur != nullptr)
{
if (cur->_kv.first == key)
{
ans = cur;
break;
}
else if (cur->_kv.first > key)
{
cur = cur->_left;
}
else
{
ans = cur;
cur = cur->_right;
}
}
return ans;
}
bool containsKey(const K& key)
{
Node* lastNode = findLastIndex(key);
return lastNode && lastNode->_kv.first == key ? true : false;
}
void _Inorder(Node*& root)
{
if (!root)return;
_Inorder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_Inorder(root->_right);
}
void Inorder()
{
_Inorder(_root);
}
private:
Node* _root = nullptr;
};
|