[C++] Simulation implementation of binary search tree (K, KV tree) recursive and non-recursive methods


Preface

Insert image description here

1. K tree

K model: The K model only has key as the key code. Only the Key needs to be stored in the structure, and the key code is the value that needs to be searched.

1. Definition of nodes

template<class K>
struct BSTreeNode
{
    
    
	BSTreeNode<K>* _left;
	BSTreeNode<K>* _right;
	K _key;

	BSTreeNode(const K&key)
		:_left(nullptr),_right(nullptr),_key(key)
	{
    
    }
};

2. Constructor

template<class K>
class BSTree {
    
    
	typedef BSTreeNode<K> Node;
public:
	BSTree() {
    
    
		_root = nullptr;
	}

3. Copy constructor

BSTree(const BSTree<K>& t) {
    
    
		_root = Copy(t._root);
	}
Node* Copy(Node* root) {
    
    
		if (root == nullptr) {
    
    
			return nullptr;
		}
		//递归进行拷贝
		Node* copyroot = new Node(root->_key);
		copyroot->_left = Copy(root->_left);
		copyroot->_right = Copy(root->_right);
		return copyroot;
	}

4. Assignment operator overloading

BSTree<K>& operator=(BSTree<K> t) {
    
    
//先拷贝出t,让_root指向t的位置,进行交换
//后续调用析构函数直接析构t._root
		swap(_root, t._root);
		return *this;
	}

5. Destructor

~BSTree() {
    
    
		Destroy(_root);
	}
	void Destroy(Node*& root) {
    
    
		if (root == nullptr) {
    
    
			return;
		}
		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
		root = nullptr;
	}

6. Find in binary search tree (find)

Searching a binary search tree
a. Start comparing and searching from the root. If it is larger than the root, search to the right. If it is smaller than the root, search to the left.
b. Search the height at most times. If it reaches empty, it has not been found yet. This value does not exist.

1. Non-recursive

bool Find(const K& key) {
    
    
		Node* cur = _root;
		while (cur) {
    
    
			if (cur->_key < key) {
    
    
				//当前值比要查找的值小
				//到右树去查找
				cur = cur->_right;
			}
			else if (cur->_key > key) {
    
    
				cur = cur->_left;
			}
			else {
    
    
				//相等,说明找到了
				return true;
			}
		}
		return false;
	 }

2. Recursion

bool _FindR(Node*root,const K& key) {
    
    
		if (root == nullptr) {
    
    
			//说明已经找完没找到
			return false;
		}
		if (root->_key < key) {
    
    
			return _FindR(root->_right, key);
		}
		else if (root->_key > key) {
    
    
			return _FindR(root->_left, key);
		}
		else {
    
    
			return true;
		}
	}

7. Insertion of binary search tree (Insert)

. Insertion into a binary search tree.
The specific process of insertion is as follows:
a. If the tree is empty, add a node directly and assign it to the root pointer.
b. If the tree is not empty, find the insertion position according to the properties of the binary search tree and insert the new node.

1. Non-recursive

bool Insert(const K& key) {
    
    
		if (_root == nullptr) {
    
    
			_root = new Node(key);
			//树为空先建立结点
			return true;
		}
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur) {
    
    //寻找要插入位置
			if (cur->_key < key) {
    
    
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key) {
    
    
				parent = cur;
				cur = cur->_left;
			}
			else {
    
    
				//树中已经有key值不能再插入
				return false;
			}
		}
		cur = new Node(key);//cur为要插入结点
		if (parent->_key < key) {
    
    
			//判断cur插在父结点的左数还是右树
			parent->_right = cur;
		}
		else {
    
    
			parent->_left = cur;
		}
		return true;//插入成功
	 }

2. Recursion

Insert image description here

bool InsertR(const K&key) {
    
    
		return _InsertR(_root, key);
	}
	bool _InsertR(Node*& root, const K& key) {
    
    
		//这里为结点指针的引用,可以不需要父结点直接修改
		if (root == nullptr) {
    
    
			root = new Node(key);
			return true;
		}
		if (root->_key < key) {
    
    
			return 	_InsertR(root->_right, key);
		}
		else if (root->_key > key) {
    
    
			return _InsertR(root->_left, key);
		}
		else {
    
    return false;}
	}

8. Deletion of binary search tree (Erase)

First, check whether the element is in the binary search tree. If it does not exist, return it. Otherwise, the node to be deleted may be divided into the following four situations: a. The node to be deleted has no child
nodes
. b. The node to be deleted is only The left child node
c. The node to be deleted is only the right child node
d. The node to be deleted is the left and right child nodes.
It seems that there are 4 situations for the node to be deleted. The actual situation a can be merged with situation b or c. up, 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 left child node of the deleted node - direct deletion
case c: delete the node and make the deleted node's parent node point to the left child node of the deleted node. The parent node points to the right child node of the deleted node - direct deletion
case d: Find the first node in the middle order (the smallest key code) in its right subtree, and fill it with its value until it is deleted. node, and then deal with the deletion problem of the node-replacement method deletion

Insert image description here

Insert image description here

1. Non-recursive

	bool Erase(const K& key) {
    
    
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur) {
    
    //寻找要删除结点
			if (cur->_key < key) {
    
    
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key) {
    
    
				parent = cur;
				cur = cur->_left;
			}
			
			else {
    
    //找到要删除结点
				//1.   要删除节点左边为空
				if (cur->_left == nullptr) {
    
    
					if (cur == _root) {
    
    
						//要删除结点为根节点,则改变根节点位置
						_root = _root->_right;
					}
					else {
    
    
						//判断要删除结点在父结点的左子树还是右子树
						if (parent->_right == cur) {
    
    
							//在父结点右子树则让其指向删除结点的右子树
							parent->_right = cur->_right;
						}
						else {
    
    
							parent->_left = cur->_right;
						}
					}
				}
				//2.     要删除节点右边为空
				else if (cur->_right == nullptr) {
    
    
					if (cur == _root) {
    
    
						//要删除结点为根节点,则改变根节点位置
						_root = _root->_left;
					}
					else {
    
    
						//判断要删除结点在父结点的左子树还是右子树
						if (parent->_right == cur) {
    
    
							parent->_right = cur->_left;
						}
						else {
    
    
							parent->_left = cur->_left;
						}
					}
				}
				else {
    
    //3.要删除结点左右子树都不为空
					Node* parent = cur;
					Node* leftMax = cur->_left;
					//寻找可替代结点,替代过好要满足二叉搜索树的性质
					//要删除结点左子树的最大值,或者右子树的最小值
					while (leftMax->_right) {
    
    
						//寻找左子树的最大值
						parent = leftMax;
						leftMax = leftMax->_right;
					}
					swap(leftMax->_key, cur->_key);
					//替代结点与被删除结点的值交换
					//这样leftMax就为要被删除的结点
					if (parent->_left == leftMax) {
    
    
						//判断leftMax在父结点的左子树还是右子树
						parent->_left = leftMax->_left;
					}
					else {
    
    
						parent->_right = leftMax->_left;
					}//改变指向
					cur = leftMax;
				}
				delete cur;
				return true;
			}	
		}
		return false;
 }

2. Recursion

bool EraseR(const K&key) {
    
    
		return _EraseR(_root, key);
	}

bool _EraseR(Node*& root, const K& key) {
    
    
		//这里为结点指针的引用,可以不需要父结点直接修改
		if (root == nullptr) {
    
    
			return false;
		}
		if (root->_key < key) {
    
    
			return _Erase(root->_right, key);
		}
		else if (root->_key > key) {
    
    
			return _Erase(root->_left, key);
		}//寻找要删除结点
		else {
    
    
			Node* del = root;
			//1. 要删除节点左边为空
			if (root->_left == nullptr) {
    
    
				root = root->_right;
			}
			//2. 要删除节点右边为空
			else if (root->_right == nullptr) {
    
    
				root = root->_left;
			}
			else {
    
    
				//3.要删除结点左右都不为空
				Node* leftMax = root->_left;
				while (leftMax->_right) {
    
    
					//寻找替代结点
					leftMax = leftMax->_right;
				}
				swap(root->_key, leftMax->_key);
				//交换值后,要删除的结点为leftMax,其在root的左子树
				return _Erase(root->_left, key);
			}
			delete del;
			return true;
		}
	}

9. Inorder traversal (InOrder)

void InOrder() {
    
    
		_InOrder(_root);
		cout << endl;
	}
void _InOrder(Node* root) {
    
    
		if (root == nullptr) {
    
    
			return;
		}
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}

2. KV tree

KV model: Each key key has a corresponding value Value, that is, the key-value pair of <Key, Value>

namespace key_value {
    
    
	template<class K, class V>
	struct BSTreeNode
	{
    
    
		BSTreeNode<K, V>* _left;
		BSTreeNode<K, V>* _right;
		K _key;
		V _value;

		BSTreeNode(const K& key, const V& value)
			:_left(nullptr), _right(nullptr), _key(key), _value(value)
		{
    
    }
	};

	template<class K, class V>
	class BSTree {
    
    
		typedef BSTreeNode<K, V> Node;
	public:
		BSTree() {
    
    
			_root = nullptr;
		}

		BSTree(const BSTree<K, V>& t) {
    
    
			_root = Copy(t._root);
		}

		BSTree<K, V>& operator=(BSTree<K, V> t) {
    
    
			swap(_root, t._root);
			return *this;
		}

		~BSTree() {
    
    
			Destroy(_root);
		}



		bool InsertR(const K& key, const V& value) {
    
    
			return _InsertR(_root, key, value);
		}

		bool EraseR(const K& key) {
    
    
			return _Erase(_root, key);
		}

		Node* FindR(const K& key) {
    
    
			return 	_FindR(_root, key);
		}
		void InOrder() {
    
    
			_InOrder(_root);
			cout << endl;
		}



	private:
		Node* Copy(Node* root) {
    
    
			if (root == nullptr) {
    
    
				return nullptr;
			}
			Node* copyroot = new Node(root->_key);
			copyroot->_left = Copy(root->_left);
			copyroot->_right = Copy(root->_right);
			return copyroot;
		}

		void Destroy(Node*& root) {
    
    
			if (root == nullptr) {
    
    
				return;
			}
			Destroy(root->_left);
			Destroy(root->_right);
			delete root;
			root = nullptr;
		}

		Node* _FindR(Node* root, const K& key) {
    
    
			if (root == nullptr) {
    
    
				return nullptr;
			}
			if (root->_key < key) {
    
    
				return _FindR(root->_right, key);
			}
			else if (root->_key > key) {
    
    
				return _FindR(root->_left, key);
			}
			else {
    
    
				return root;
			}

		}

		bool _InsertR(Node*& root, const K& key, const V& value) {
    
    
			if (root == nullptr) {
    
    
				root = new Node(key, value);
				return true;
			}
			if (root->_key < key) {
    
    
				return _InsertR(root->_right, key, value);
			}
			else if (root->_key > key) {
    
    
				return _InsertR(root->_left, key, value);
			}
			else {
    
    
				return false;
			}
		}

		bool _Erase(Node*& root, const K& key) {
    
    
			if (root == nullptr) {
    
    
				return false;
			}
			if (root->_key < key) {
    
    
				return _Erase(root->_right, key);
			}
			else if (root->_key > key) {
    
    
				return _Erase(root->_left, key);
			}
			else {
    
    
				Node* del = root;
				if (root->_left == nullptr) {
    
    
					root = root->_right;
				}
				else if (root->_right == nullptr) {
    
    
					root = root->_left;
				}
				else {
    
    
					Node* leftMax = root->_left;
					while (leftMax->_right) {
    
    
						leftMax = leftMax->_right;
					}
					swap(root->_key, leftMax->_key);
					return _Erase(root->_left, key);
				}
				delete del;
				return true;
			}
		}


		void _InOrder(Node* root)
		{
    
    
			if (root == NULL){
    
    return;}
			_InOrder(root->_left);
			cout << root->_key << ":" << root->_value << endl;
			_InOrder(root->_right);
		}

	private:
		Node* _root;
	};
}

Binary Search Tree Performance

Insert image description here

The highest search height times O(N)

Guess you like

Origin blog.csdn.net/m0_74774759/article/details/132210067