1. Basic concepts of binary search tree
A binary search tree is also called a binary sort tree. It is either an empty tree or a binary tree with the following properties:
- If the left subtree of node A is not empty, then the node value on the left subtree and the node values of all subtrees are smaller than the node value of node A
- If the right subtree of node A is not empty, then the node value on the right subtree and the node values of all its subtrees are greater than the node value of node A
- The left and right subtrees of node A are binary search trees
2. Finding a binary search tree
If the root node is not empty:
- If the root node value == the value to be found returns true
- If the root node value <the value to be searched, search on its left subtree
- If the root node value> the value to be searched, search on the right subtree
Otherwise, there is no such value in the tree
Node* Find(const T& data)
{
Node* cur = root;
while (cur)
{
if (data == cur->data)
return cur;
else if (data < cur->data)
cur = cur->left;
else
cur = cur->right;
}
return NULL;
}
3. Insertion of binary search tree
-
Tree is empty, insert directly
-
Find the position to be inserted, and save the parent node in each iteration
-
If the root node value <the value to be inserted, look for the insertion position on the left subtree
-
If the root node value >= the value to be inserted, look for the insertion position on the right subtree
-
If the root node is NULL, find the position to be inserted
-
-
Insert node
- If the value of the parent node <the value to be inserted, insert it on the left subtree
- If the root node value> the value to be inserted, insert it on the right subtree
bool Insert(const T& data)
{
if (nullptr == root)
{
root = new Node(data);
return true;
}
//1.找待插入节点在树中的位置
Node* cur = root;
Node* parent = root; //记录待插入节点插入位置的父节点
while (cur)
{
parent = cur;
if (data < cur->data)
cur = cur->left;
else if (data > cur->data)
cur = cur->right;
else
return false;
}
//2.插入节点
cur = new Node(data);
if (data < parent->data)
parent->left = cur;
else if (data > parent->data)
parent->right = cur;
else
return false;
return true;
}
4. Delete Binary Search Tree
First find whether the element is in the binary search tree, if it does not exist, return **,** otherwise the node to be deleted may be divided into the following four situations:
- The node to be deleted has no children
- The only node to be deleted is the left child node
- The only node to be deleted is the right child node
- The node to be deleted has left and right child nodes
It seems that there are 4 cases for the node to be deleted. Actual case a can be combined with case b or c, so the real deletion process is as follows:
Case b : delete the node and make the parent node of the deleted node point to the deleted node Left child node
Case c : Delete the node and make the parent node of the deleted node point to the right child node of the deleted node
Case d : Find the first node in the middle order in its right subtree **( Minimum key code )**, fill in the deleted node with its value, and
then deal with the deletion of the node
bool Erase(const T& data)
{
if (nullptr == root)
return false;
//寻找插入位置及其父节点
Node* cur = root;
Node* parent = root;
while (cur)
{
parent = cur;
if (data == cur->data)
break;
else if (data < cur->data)
parent = cur, cur = cur->left;
else
parent = cur, cur = cur->right;
}
if (cur == NULL)
return false;
if (nullptr == cur->left) //cur只存在右节点
{
if (nullptr == parent)
{
root = cur->right;
}
else
{
if (cur == parent->left)
{
parent->left = cur->right;
}
else
{
parent->right = cur->right;
}
}
}
else if (nullptr == cur->right) //cur只存在左节点
{
if (nullptr == parent)
root = root->left;
else
{
if (cur == parent->left)
parent->left = cur->left;
else
parent->right = cur->left;
}
}
else
{
//cur左右孩子都存在
Node* delNode = cur->right;
parent = cur;
while (delNode->right)
{
parent = delNode;
delNode = delNode->right;
}
cur->data = delNode->data;
if (parent->left == delNode)
parent->left = delNode->right;
else
parent->right = delNode->right;
cur = delNode;
}
delete cur;
return true;
}
5. Simulation implementation of binary search tree
template<class T>
struct BSTreeNode
{
BSTreeNode(T data)
{
left = nullptr;
right = nullptr;
this->data = data;
}
BSTreeNode* left;
BSTreeNode* right;
T data;
};
template<class T>
class BSTree
{
typedef BSTreeNode<T> Node;
public:
BSTree() : root(nullptr){
}
~BSTree()
{
Destroy(root);
}
//二叉树插入
bool Insert(const T& data)
{
if (nullptr == root)
{
root = new Node(data);
return true;
}
//1.找待插入节点在树中的位置
Node* cur = root;
Node* parent = root; //记录待插入节点插入位置的父节点
while (cur)
{
parent = cur;
if (data < cur->data)
cur = cur->left;
else if (data > cur->data)
cur = cur->right;
else
return false;
}
//2.插入节点
cur = new Node(data);
if (data < parent->data)
parent->left = cur;
else if (data > parent->data)
parent->right = cur;
else
return false;
return true;
}
Node* Find(const T& data)
{
Node* cur = root;
while (cur)
{
if (data == cur->data)
return cur;
else if (data < cur->data)
cur = cur->left;
else
cur = cur->right;
}
return NULL;
}
bool Erase(const T& data)
{
if (nullptr == root)
return false;
//寻找插入位置及其父节点
Node* cur = root;
Node* parent = root;
while (cur)
{
parent = cur;
if (data == cur->data)
break;
else if (data < cur->data)
parent = cur, cur = cur->left;
else
parent = cur, cur = cur->right;
}
if (cur == NULL)
return false;
if (nullptr == cur->left) //cur只存在右节点
{
if (nullptr == parent)
{
root = cur->right;
}
else
{
if (cur == parent->left)
{
parent->left = cur->right;
}
else
{
parent->right = cur->right;
}
}
}
else if (nullptr == cur->right) //cur只存在左节点
{
if (nullptr == parent)
root = root->left;
else
{
if (cur == parent->left)
parent->left = cur->left;
else
parent->right = cur->left;
}
}
else
{
//cur左右孩子都存在
Node* delNode = cur->right;
parent = cur;
while (delNode->right)
{
parent = delNode;
delNode = delNode->right;
}
cur->data = delNode->data;
if (parent->left == delNode)
parent->left = delNode->right;
else
parent->right = delNode->right;
cur = delNode;
}
delete cur;
return true;
}
void PrintTree()
{
InOrder(root);
cout << endl;
}
private:
//中序遍历
void InOrder(Node* pRoot)
{
if (pRoot)
{
if (pRoot->left)
InOrder(pRoot->left);
cout << pRoot->data << " ";
if (pRoot->right)
InOrder(pRoot->right);
}
}
//二叉树销毁
void Destroy(Node*& pRoot)
{
if (pRoot)
{
if (pRoot->left)
Destroy(pRoot->left);
if (pRoot->right)
Destroy(root->right);
delete pRoot;
pRoot = nullptr;
}
}
Node* root;
};
7. Realistic application of binary search tree
Binary tree application: search/find the data on the binary search tree
K model: each node stores a single type of value
For example: Check for spelling errors of words, build a binary search tree that contains all words, search the entire tree, if the word is found, it means there is no spelling error
KV model: each node stores data in the form of key-value pairs
For example: count an article and count the word frequency <word, frequency>
6. Performance analysis of binary search tree
If the binary search tree is a complete binary tree , the average number of comparisons: logN
If the binary search tree for the Single binary tree , then the average number of comparisons: N / 2
7. OJ problem of binary search tree
LeetCode 36. Binary search tree and doubly linked list
Link: Binary search tree and doubly linked list
Solution 1: Store in vector for link
- Ideas:
In order to traverse the tree, store the nodes in the vector container, then link from left to right, and return to the first node in the container
-
time complexity:
-
Space complexity: O( N)
-
Code
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node() {}
Node(int _val) {
val = _val;
left = NULL;
right = NULL;
}
Node(int _val, Node* _left, Node* _right) {
val = _val;
left = _left;
right = _right;
}
};
*/
class Solution {
public:
Node* treeToDoublyList(Node* root) {
if(root == NULL) return NULL;
vector<Node*> v;
InorderTraversal(v,root);
for(int i = 0; i < v.size(); i++)
{
if(i != v.size()-1)
v[i]->right = v[i+1];
else
v[i]->right = v[0];
if(i != 0)
v[i]->left = v[i-1];
else
v[i]->left = v[v.size()-1];
}
return v[0];
}
private:
void InorderTraversal(vector<Node*>& v, Node* root)
{
if(root == NULL)
return ;
else
{
InorderTraversal(v,root->left);
v.push_back(root);
InorderTraversal(v,root->right);
}
}
};
i]->right = v[0];
if(i != 0)
v[i]->left = v[i-1];
else
v[i]->left = v[v.size()-1];
}
return v[0];
}
private:
void InorderTraversal(vector<Node*>& v, Node* root)
{
if(root == NULL)
return ;
else
{
InorderTraversal(v,root->left);
v.push_back(root);
InorderTraversal(v,root->right);
}
}
};