[data structure] talk about a new tree -- binary search tree

preface

Binary search tree, also known as binary sort tree, is either an empty tree or a binary tree with the following properties:

  • If its left subtree is not empty, the value of all nodes on the left subtree is less than that of the root node
  • If its right subtree is not empty, the value of all nodes on the right subtree is greater than that of the root node
  • Its left and right subtrees are also binary search trees

You can do this:

So:

Or this:

It can be seen that the general binary search tree has different forms, because there are only the following constraints:

  • The left subtree is smaller than the root
  • The right subtree is larger than the root

Analyze the performance:

  • In the optimal case, the binary search tree is a complete binary tree, and its average comparison times is log(N)
  • In the worst case, the binary search tree degenerates into a single branch tree, and its average comparison times is N/2

Node insertion

To insert a node, you only need to meet the following requirements after insertion:

  • The left subtree is smaller than the root
  • The right subtree is larger than the root

The new node will become a new leaf

Here, we agree that the values of each node are different, that is, nodes with duplicate values cannot appear

We need a parent to connect the newly inserted node with the original tree:

bool Insert(K key) {
	if (_root == nullptr) {
		_root = new Node(key);
	}
	else {
		Node* cur = _root;
		Node* parent = _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 {
			parent->_right = cur;
		}
	}
	return true;
}

Node deletion

Deleting a node is slightly more complicated than inserting it. Please see the following three situations:

1. Delete leaf node

This is simple. Deleting a leaf node has no impact on the parent node. It doesn't need to be adjusted. Just delete it directly

2. The deleted node has only left children or only right children

This is also simple. After deleting a node, just connect the parent node with a single child tree

3. Left and right children of the deleted node exist

This is a little difficult. After deleting nodes, you have to adjust the tree

The substitution method can be used to solve:
1. Deleting is to overwrite the value of the original node, so we will directly replace the value of the deleted node with the value of a special node
2. After replacement, the special node will be killed, so when selecting a special node, the better it will be killed and the more suitable it is
3. Who'd better be killed? The first two cases, of course
4. We select a suitable leaf node to replace the position of the deleted node. After replacement, the tree is still a binary search tree
5. Therefore, we can take the point to be deleted as the root and select the largest of its left subtree or the smallest of its right subtree to replace the node to be deleted
Take the smallest right subtree as an example:

Of course, the right subtree here is a single branch tree, so the smallest is the right child. If it is not a single branch tree, it is the leftmost node of the right subtree

bool Erase(K key) {

	//			5
	//		3		     7
	//	1		4     6		 8
	//0	   2					9

	// leaf
	// Only one child
	// There are two children
	Node* parent = _root;
	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) {
				// Left child is empty
				// 1. cur is the root
				if (cur == _root) {
					_root = cur->_right;
				}
				// 2. cur is not root
				else {
					if (parent->_left == cur) {
						parent->_left = cur->_right;
					}
					else {
						parent->_right = cur->_right;
					}
				}
				delete cur;
				cur = nullptr;
			}
			else if (cur->_right == nullptr) {
				// Right child is empty
				// 1. cur is the root
				if (cur == _root) {
					_root = cur->_left;
				}
				// 2. cur is not root
				else {
					if (parent->_left == cur) {
						parent->_left = cur->_left;
					}
					else {
						parent->_right = cur->_left;
					}
				}
				delete cur;
				cur = nullptr;
			}
			else {
				// Left and right children are not empty
				Node* RLNode = cur->_right;
				Node* pRLNode = cur;
				Node* ppRLNode = cur;
				while (RLNode) {
					ppRLNode = pRLNode;
					pRLNode = RLNode;
					RLNode = RLNode->_left;
				}
				cur->_key = pRLNode->_key;
				if (ppRLNode->_left == pRLNode) {
					ppRLNode->_left = pRLNode->_right;
				}
				else {
					ppRLNode->_right = pRLNode->_right;
				}
				delete pRLNode;
				pRLNode = nullptr;
			}
			return true;
		}
	}
	return false;
}

code

namespace K {
	template<class K>
	struct BSTreeNode {
		K _key;
		BSTreeNode<K>* _left;
		BSTreeNode<K>* _right;
		BSTreeNode(K key)
			:_key(key)
			, _left(nullptr)
			, _right(nullptr) {}
		~BSTreeNode() {
			//delete 
			//cout << _key << endl;
		}
	};
	template <class K>
	class BSTree {
	public:
		typedef BSTreeNode<K> Node;
		BSTree()
			:_root(nullptr) {}
		bool Insert(K key) {
			if (_root == nullptr) {
				_root = new Node(key);
			}
			else {
				Node* cur = _root;
				Node* parent = _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 {
					parent->_right = cur;
				}
			}
			return true;
		}

		Node* Find(K key) {
			Node* cur = _root;
			while (cur) {
				if (key < cur->_key) {
					cur = cur->_left;
				}
				else if (key > cur->_key) {
					cur = cur->_right;
				}
				else {
					return cur;
				}
			}
			return nullptr;
		}

		bool Erase(K key) {

			//			5
			//		3		     7
			//	1		4     6		 8
			//0	   2					9

			// leaf
			// Only one child
			// There are two children
			Node* parent = _root;
			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) {
						// Left child is empty
						// 1. cur is the root
						if (cur == _root) {
							_root = cur->_right;
						}
						// 2. cur is not root
						else {
							if (parent->_left == cur) {
								parent->_left = cur->_right;
							}
							else {
								parent->_right = cur->_right;
							}
						}
						delete cur;
						cur = nullptr;
					}
					else if (cur->_right == nullptr) {
						// Right child is empty
						// 1. cur is the root
						if (cur == _root) {
							_root = cur->_left;
						}
						// 2. cur is not root
						else {
							if (parent->_left == cur) {
								parent->_left = cur->_left;
							}
							else {
								parent->_right = cur->_left;
							}
						}
						delete cur;
						cur = nullptr;
					}
					else {
						// Left and right children are not empty
						Node* RLNode = cur->_right;
						Node* pRLNode = cur;
						Node* ppRLNode = cur;
						while (RLNode) {
							ppRLNode = pRLNode;
							pRLNode = RLNode;
							RLNode = RLNode->_left;
						}
						cur->_key = pRLNode->_key;
						if (ppRLNode->_left == pRLNode) {
							ppRLNode->_left = pRLNode->_right;
						}
						else {
							ppRLNode->_right = pRLNode->_right;
						}
						delete pRLNode;
						pRLNode = nullptr;
					}
					return true;
				}
			}
			return false;
		}
		void InOrder() {
			_InOrder(_root);
			cout << endl;
		}
		void _InOrder(Node* root) {
			if (root != nullptr) {
				_InOrder(root->_left);
				cout << root->_key << " ";
				_InOrder(root->_right);
			}
		}
	private:
		Node* _root;
	};
}



namespace KV {
	template<class K, class V>
	struct BSTreeNode {
		K _key;
		V _val;
		BSTreeNode<K, V>* _left;
		BSTreeNode<K, V>* _right;
		BSTreeNode(K key, V val)
			:_key(key)
			, _val(val)
			, _left(nullptr)
			, _right(nullptr) {}
		~BSTreeNode() {
		}
	};
	template <class K, class V>
	class BSTree {
	public:
		typedef BSTreeNode<K, V> Node;
		BSTree()
			:_root(nullptr) {}

		V& operator[](K key) {
			pair<Node*, bool> ret = Insert(key, V());
			return ret.first->_val;

		}
		pair<Node*, bool> Insert(K key, V val) {
			if (_root == nullptr) {
				_root = new Node(key, val);
				return make_pair(_root, true);
			}
			else {
				Node* cur = _root;
				Node* parent = _root;
				while (cur) {
					if (key < cur->_key) {
						parent = cur;
						cur = cur->_left;
					}
					else if (key> cur->_key) {
						parent = cur;
						cur = cur->_right;
					}
					else {
						return make_pair(cur, false);
					}
				}
				cur = new Node(key, val);
				if (key < parent->_key) {
					parent->_left = cur;
				}
				else {
					parent->_right = cur;
				}
				return make_pair(cur, true);
			}
		}

		Node* Find(K key) {
			Node* cur = _root;
			while (cur) {
				if (key < cur->_key) {
					cur = cur->_left;
				}
				else if (key > cur->_key) {
					cur = cur->_right;
				}
				else {
					return cur;
				}
			}
			return nullptr;
		}

		bool Erase(K key) {

			//			5
			//		3		     7
			//	1		4     6		 8
			//0	   2					9

			// leaf
			// Only one child
			// There are two children
			Node* parent = _root;
			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) {
						// Left child is empty
						// 1. cur is the root
						if (cur == _root) {
							_root = cur->_right;
						}
						// 2. cur is not root
						else {
							if (parent->_left == cur) {
								parent->_left = cur->_right;
							}
							else {
								parent->_right = cur->_right;
							}
						}
						delete cur;
						cur = nullptr;
					}
					else if (cur->_right == nullptr) {
						// Right child is empty
						// 1. cur is the root
						if (cur == _root) {
							_root = cur->_left;
						}
						// 2. cur is not root
						else {
							if (parent->_left == cur) {
								parent->_left = cur->_left;
							}
							else {
								parent->_right = cur->_left;
							}
						}
						delete cur;
						cur = nullptr;
					}
					else {
						// Left and right children are not empty
						Node* RLNode = cur->_right;
						Node* pRLNode = cur;
						Node* ppRLNode = cur;
						while (RLNode) {
							ppRLNode = pRLNode;
							pRLNode = RLNode;
							RLNode = RLNode->_left;
						}
						cur->_key = pRLNode->_key;
						cur->_val = pRLNode->_val;
						if (ppRLNode->_left == pRLNode) {
							ppRLNode->_left = pRLNode->_right;
						}
						else {
							ppRLNode->_right = pRLNode->_right;
						}
						delete pRLNode;
						pRLNode = nullptr;
					}
					return true;
				}
			}
			return false;
		}
		void InOrder() {
			_InOrder(_root);
			cout << endl;
		}
		void _InOrder(Node* root) {
			if (root != nullptr) {
				_InOrder(root->_left);
				cout << root->_key << ":" << root->_val << " ";
				_InOrder(root->_right);
			}
		}
	private:
		Node* _root;
	};
}

Keywords: C++ data structure

Added by MatthewBJones on Sun, 06 Mar 2022 01:09:08 +0200