[Data Structure---Binary Search Tree] An article to get a binary search tree

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

Insert picture description here

	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

  1. Tree is empty, insert directly

  2. 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

  3. 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

Insert picture description here

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:

  1. The node to be deleted has no children
  2. The only node to be deleted is the left child node
  3. The only node to be deleted is the right child node
  4. 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

Insert picture description here

If the binary search tree for the Single binary tree , then the average number of comparisons: N / 2

Insert picture description here

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);
        }
    }
};

Guess you like

Origin blog.csdn.net/weixin_45437022/article/details/112306154