Detailed SizeBalanceTree (including code implementation)

content

1. The concept of SBT tree and its related properties

 2. Four types of violations of SBT tree

3. Insertion of BST tree

4. Deletion of SBT

 5. Code summary


1. The concept of SBT tree and its related properties

Size Balanced Tree (SBT) is a balanced binary search tree. Its thesis was completed in late 2006 by Chen Qifeng from Zhongshan Memorial Middle School in Guangdong, China, php

and presented at Winter Camp 2007. Because the spelling of SBT is easy to find Chinese homonyms, it is often called "silly X tree", html by Chinese Olers

"Super BT" etc. But its performance is not SB, and it is not BT to write. On the contrary, SBT is easy to implement, and according to Chen Qifeng's paper, node

"This is by far the fastest advanced binary search tree". It can complete all BST related operations in O(logn) time. And because SBT relies on arrays

In order to maintain the balance, it is the Size field instead of the other "useless" fields, which can easily implement the select and rank in the dynamic order statistics. data structure

1.2 SBT tree related properties:

The number of any uncle node cannot be less than the number of nephew nodes, for example, as shown in the figure:

 The uncle is the uncle node of T3 and T4, and the second uncle is the uncle node of T1 and T2. The number of uncle nodes in the SBT tree species must be greater than or equal to the number of any one of T3 and T4, and the number of second uncle nodes must be greater than T1 and T2. the number of any one of the nodes.

 The SBT tree does not have such strict balance as the AVL tree. The purpose of the SBT tree is to ensure that the height of the left does not exceed twice the height of the right tree or the height of the right tree does not exceed twice the height of the left tree. Specifically For proof, please see the article of the big guy

Chen Qifeng's SBT paper (translation)

1.3 Definition of SBT tree node:

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;//节点的个数
};

 2. Four types of violations of SBT tree

SBT trees, like AVL trees, have four types of violations:

1. Type LL violation

2. LR-type violations

3. RR-type violations

4. RL Type Violations

Type LL violation

LL-type violation means that the number of nodes in the left subtree of the uncle is greater than the number of nodes in the second-uncle. It becomes an LL-type violation similar to the AVL tree, but it is a bit different from the AVL tree. Please see the following explanation for details:

 After we rotate the root node to the right, we will find that the uncle's child node has changed, and the children of the root node have also changed. At this time, it is necessary to recursively check whether the uncle and the root node meet the definition of the SBT tree. This is the same as AVL trees are different. Why does the child node need to be checked after it has changed? This is because the object it compared to before has changed.

Corresponding code:

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;//返回调整后的新头部
	}

Note: The recursive adjustment is placed in the maintain method 

 Type RR Violations:

RR-type violation means that the number of T4 nodes is greater than the number of uncle nodes. The adjustment scheme performs a left-hand rotation on the root node as in the AVL tree.

The child nodes of the same root node and second uncle are changed, and the two nodes are recursively checked to see if they meet the definition of the SBT tree.

 Corresponding code:

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;//返回新的头部
	}

Type LR violation:

 The LR type means that the number of B nodes is greater than the number of second uncle nodes. The adjustment strategy is the same as the AVL tree, first perform a left rotation on the uncle, and then perform a right rotation on the root.

 After rotation, we found that the left and right children of the three nodes of root, uncle, and B have changed, so we need to check them to see if they meet the definition of SBT tree 

RL type Similarly, the old irons can go down and draw it by themselves.

 Corresponding adjustment code:

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) {//LL型
			cur = rightRotate(cur);//右旋
			cur->_right = maintain(cur->_right);//递归检查
			cur = maintain(cur);
		}
		else if (leftRightSize > rightSize) {//LR型,调整完成之后递归检查
			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) {//RR型,调整后并且检查
			cur = leftRotate(cur);
			cur->_left = maintain(cur->_left);
			cur = maintain(cur);
		}
		else if (rightLeftSize > leftSize) {//RL型,调整后并检查
			cur->_right = rightRotate(cur->_right);
			cur = leftRotate(cur);
			cur->_left = maintain(cur->_left);
			cur->_right = maintain(cur->_right);
			cur = maintain(cur);
		}
		return cur;//返回调整后的头部
   }

3. Insertion of BST tree

The insertion of the BST tree is basically the same as the insertion of the search binary tree, but there are more adjustment parts. If you are not sure, you can go to my previous blog.

Corresponding code:

// 现在,以cur为头的树上,新增,加(key, value)这样的记录
		// 加完之后,会对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;
	}

4. Deletion of SBT

The deletion of SBT is basically the same as the deletion of AVL tree, at least the adjustment method is different. If you are not sure, you can read my article.

Node* Delete(Node* cur, K key) {
		cur->_size--;
		if (cur->_kv.first > key) {
			cur->_left = Delete(cur->_left, key);
		}
		else if (cur->_kv.first < key) {
			cur->_right = Delete(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) {//链接cur的左右孩子
					pre->_left = des->_right;
					des->_right = cur->_right;
				}
				des->_left = cur->_left;
				des->_size = des->_left->_size + (des->_right ? des->_right->_size:0) + 1;//更新size
				delete cur;
				cur = des;
			}
		}
		cur = maintain(cur);//平衡
		return cur;//返回新头部
	}
	void Erase(K key) {
		Node* lastNode = findLastIndex(key);
		if(lastNode)
		_root = Delete(_root,key);
		else {
			return;
		}
}

 5. Code summary

#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) {//LL型
			cur = rightRotate(cur);//右旋
			cur->_right = maintain(cur->_right);//递归检查
			cur = maintain(cur);
		}
		else if (leftRightSize > rightSize) {//LR型,调整完成之后递归检查
			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) {//RR型,调整后并且检查
			cur = leftRotate(cur);
			cur->_left = maintain(cur->_left);
			cur = maintain(cur);
		}
		else if (rightLeftSize > leftSize) {//RL型,调整后并检查
			cur->_right = rightRotate(cur->_right);
			cur = leftRotate(cur);
			cur->_left = maintain(cur->_left);
			cur->_right = maintain(cur->_right);
			cur = maintain(cur);
		}
		return cur;//返回调整后的头部
   }
	// 现在,以cur为头的树上,新增,加(key, value)这样的记录
		// 加完之后,会对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* Delete(Node* cur, K key) {
		cur->_size--;
		if (cur->_kv.first > key) {
			cur->_left = Delete(cur->_left, key);
		}
		else if (cur->_kv.first < key) {
			cur->_right = Delete(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) {//链接cur的左右孩子
					pre->_left = des->_right;
					des->_right = cur->_right;
				}
				des->_left = cur->_left;
				des->_size = des->_left->_size + (des->_right ? des->_right->_size:0) + 1;//更新size
				delete cur;
				cur = des;
			}
		}
		cur = maintain(cur);//平衡
		return cur;//返回新头部
	}
	void Erase(K key) {
		Node* lastNode = findLastIndex(key);
		if(lastNode)
		_root = Delete(_root,key);
		else {
			return;
		}
	}

	Node* findLastIndex(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(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(K key) {
		  SBTNode<K, V> 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(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;
};

Guess you like

Origin blog.csdn.net/qq_56999918/article/details/122774352