[C++] Search binary tree

Table of contents

overview

algorithm

source code

BSTree.h

test.cpp


overview

Search binary tree , also known as binary sorting tree , it follows the principle of binary tree, each node has rules:

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

Each node of the binary tree contains data: key value, left node pointer, right node pointer

Binary tree insertion: the newly inserted node must be a leaf node, first find the position where the node needs to be inserted according to the key value, and then create a new node to insert a new node at this position

Deletion of a binary tree: first find the node to be deleted, if it cannot be found, the deletion will fail; if it is found, judge according to the following three situations: 1. The left node of the node is empty; 2. The right node of the node is 3. The left and right nodes of this node are not empty. If it is the first two cases, the deletion can be completed by moving the non-empty subtree up. If it is the third case, it is necessary to find the largest node of the left subtree or the smallest node of the right subtree, and combine the found extreme value node with Exchange the values ​​of the nodes that need to be deleted, and then delete the found extreme value nodes.

algorithm

Strictly abide by the principle of searching binary trees: the left node must be smaller than the root node, the right node must be greater than the root node, and there are no duplicate values

The design schemes of looping and recursive modes are implemented respectively. The code of the recursive scheme is more concise, but the loss of stack frame space is greater

The average time complexity of searching a binary tree is O(log n), but it is unstable. There is an extreme value of O(n), and the extreme value is the case where all subsequent values ​​are inserted to one side. Based on this situation, AVL balance is designed later Binary tree to make up for this defect

source code

BSTree.h

#pragma once

#include <iostream>

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

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

template<class K>
class BSTree
{
	typedef BSTreeNode<K> Node;
public:
	BSTree()
		: _root(nullptr)
	{}
	BSTree(const BSTree<K>& t)
	{
		_root = copy(t._root);
	}
	BSTree<K>& operator=(BSTree<K> t)
	{
		std::swap(_root, t._root);
		return *this;
	}

	~BSTree()
	{
		destroy(_root);
		_root = nullptr;
	}

	bool insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}

		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
			{
				return false;
			}
		}

		cur = new Node(key);
		if (parent->_key < key)
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		return true;
	}

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

	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. 左为空
				// 2. 右为空
				// 3. 左右都不为空,替换删除
				if (cur->_left == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_right;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
					delete cur;
				}
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (parent->_left == cur)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
					}
					delete cur;
				}
				else
				{
					// 找右子树的最小节点(左子树的最大节点)
					Node* minParent = cur;
					Node* minRight = cur->_right;
					while (minRight->_left)
					{
						minParent = minRight;
						minRight = minRight->_left;
					}
					cur->_key = minRight->_key;
					if (minRight = minParent->_left)
					{
						minParent->_left = minRight->_right;
					}
					else
					{
						minParent->_right = minRight->_right;
					}
					delete minRight;
				}
				return true;
			}
		}
		return false;
	}

	// 用递归实现遍历、插入、查找、删除
	void in_order()
	{
		_in_order(_root);
		std::cout << std::endl;
	}

	bool insert_r(const K& key)
	{
		return _insert_r(_root, key);
	}

	bool find_r(const K& key)
	{
		return _find_r(_root, key);
	}

	bool erase_r(const K& key)
	{
		return _erase_r(_root, key);
	}

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

	void destroy(Node* root)
	{
		if (root != nullptr)
		{
			destroy(root->_left);
			destroy(root->_right);
			delete root;
		}
	}

	void _in_order(Node* root)
	{
		if (root != nullptr)
		{
			_in_order(root->_left);
			std::cout << root->_key << " ";
			_in_order(root->_right);
		}
	}

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

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

	bool _erase_r(Node*& root, const K& key)
	{
		if (root == nullptr)
		{
			return false;
		}

		if (root->_key < key)
		{
			return _erase_r(root->_right, key);
		}
		else if (root->_key > key)
		{
			return _erase_r(root->_left, key);
		}
		else
		{
			Node* del = root;
			if (root->_left == nullptr)
			{
				root = root->_right;
			}
			else if (root->_right == nullptr)
			{
				root = root->_left;
			}
			else
			{
				Node* minRight = root->_right;
				while (minRight->_left)
				{
					minRight = minRight->_left;
				}
				std::swap(root->_key, minRight->_key);
				
				// 转换成在子树中删除节点
				return _erase_r(root->_right, key);
			}
			delete del;
			return true;
		}
	}

private:
	Node* _root = nullptr;
};

test.cpp

#include "BSTree.h"

void test()
{
	BSTree<int> t1;
	t1.insert(2);
	t1.insert(4);
	t1.insert(6);
	t1.insert(8);
	t1.insert_r(1);
	t1.insert_r(3);
	t1.insert_r(5);
	t1.insert_r(7);
	t1.insert(-10);
	t1.insert(-10);		// 重复值无法插入
	t1.insert(-20);
	t1.insert(0);
	t1.in_order();		// -20 -10 0 1 2 3 4 5 6 7 8
						// 中序遍历,自动实现递增排序
	BSTree<int> t2(t1);
	t2.in_order();		// -20 -10 0 1 2 3 4 5 6 7 8
	std::cout << t2.find(0) << std::endl;		// 1
	std::cout << t2.find_r(10) << std::endl;	// 0
	t2.~BSTree();
	t2.in_order();

	BSTree<int> t3 = t1;
	t3.erase(0);
	t3.erase(8);
	t3.erase(4);
	t3.erase_r(1);	
	t3.erase_r(5);	
	t3.in_order();		// -20 -10 2 3 6 7

}

int main()
{
	test();

	return 0;
}

Guess you like

Origin blog.csdn.net/phoenixFlyzzz/article/details/130468203