二叉搜索树--详细实现过程

目录

  • 二叉搜索树的概念
  • 二叉搜索树的实现
    • 基础结构:
    • 插入
    • 删除
    • 查找
    • 遍历
    • 整体实现代码:
  • 二叉搜索树的应用(KV模型)
  • 二叉搜索树性能分析

二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

二叉搜索树的实现

基础结构:

//定义节点
template <class T>
struct BNode
{
	T _data;
	typedef BNode<T> Node;
	Node* _left;
	Node* _right;

	BNode(const T& data)
		:_data(data)
		, _left(nullptr)
		, _right(nullptr)
	{}
};
//定义二叉树
template <class T>
class BTree
{
public:
	typedef BNode<T> Node;
	//构造函数
	BTree()
		:_root(nullptr)
	{}

	//拷贝二叉搜索树的数据和结构
	Node* copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		
		Node* newNode = new Node(root->_data);
		newNode->_left = copy(root->_left);
		newNode->_right = copy(root->_right);
		return newNode;
	}
	//拷贝构造(深拷贝)
	BTree(const BTree<T>& btree)
		:_root(copy(btree._root))
	{}
	
	void destroy(Node* root)
	{
		if (root)
		{
			destroy(root->_left);
			destroy(root->_right);
			cout << "destroy: " << root->_data << endl;
			delete root;
		}
	}
	//析构函数
	~BTree()
	{
		if (_root)
		{
			destroy(_root);
			_root = nullptr;
		}
	}

private:
	Node* _root;
};

插入

//不插入重复的值
	bool insert(const T& val)
	{
		if (_root == nullptr)
		{
			_root = new Node(val);
			return true;
		}
		//搜索,找到合适的插入位置
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (cur->_data == val)
				return false;
			else if (cur->_data > val)
				cur = cur->_left;
			else
				cur = cur->_right;
		}
		//插入
		cur = new Node(val);
		//链接
		if (parent->_data > val)
			parent->_left = cur;
		else
			parent->_right = cur;
	}

删除

	bool erase(const T& val)
		{
			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)
			{
				if (cur->_data == val)
					break;
				parent = cur;
				if (cur->_data > val)
					cur = cur->_left;
				else
					cur = cur->_right;
			}
			//判断需要删除的节点是否存在
			if (cur == nullptr)
				return false;
			else
			{
				//1.删除的为叶子节点
				if (cur->_left == nullptr && cur->_right == nullptr)
				{
					//判断是否为根节点
					if (cur == _root)
						_root == nullptr;
					else
					{
						if (parent->_left == cur)
							parent->_left = nullptr;
						else
							parent->_right = nullptr;
					}
					//删除节点
					delete cur;
				}
				//2.非叶子节点
				else if (cur->_left == cur)
				{
					//判断是否为根节点
					if (cur == _root)
					{
						//更新根节点
						_root = cur->_right;
					}
					else
					{
						if (parent->_left = cur)
							parent->_left = cur->_right;
						else
							parent->_right = cur->_right;
					}
					//删除节点
					delete cur;
				}
				//3.非叶子节点
				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;
				}
				//4.左右子树都存在
				else
				{
					//1.假设找左子树的最右节点
					Node* leftRightMost = cur->_left;
					parent = cur;
					while (leftRightMost->_right)
					{
						parent = leftRightMost;
						leftRightMost = leftRightMost->_right;
					}
					//交换最右节点和要删除节点的值
					swap(cur->_data, leftRightMost->_data);
					if (parent->_left == leftRightMost)
						parent->_left = leftRightMost->_left;
					else
						parent->_right = leftRightMost->_left;
					delete leftRightMost;
				}
				return true;
			}
		}

查找

	Node* find(const T& val)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_data == val)
					return cur;
				else if (cur->_data > val)
					return cur->_left;
				else
					return cur->_right;
			}
		}

遍历

	void inorder()
	{
		_inorder(_root);
	}
	
	//搜索树的中序遍历有序
	void _inorder(Node* root)
	{
		if (root)
		{
			_inorder(root->_left);
			cout << root->_data << " ";
			_inorder(root->_right);
		}
	}

整体实现代码:

template <class T>
struct BNode
{
	T _data;
	typedef BNode<T> Node;
	Node* _left;
	Node* _right;

	BNode(const T& data)
		:_data(data)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

template <class T>
class BTree
{
public:
	typedef BNode<T> Node;
	
	BTree()
		:_root(nullptr)
	{}

	//拷贝二叉搜索树的数据和结构
	Node* copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		
		Node* newNode = new Node(root->_data);
		newNode->_left = copy(root->_left);
		newNode->_right = copy(root->_right);
		return newNode;
	}

	BTree(const BTree<T>& btree)
		:_root(copy(btree._root))
	{}

	//不插入重复的值
	bool insert(const T& val)
	{
		if (_root == nullptr)
		{
			_root = new Node(val);
			return true;
		}
		//搜索,找到合适的插入位置
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (cur->_data == val)
				return false;
			else if (cur->_data > val)
				cur = cur->_left;
			else
				cur = cur->_right;
		}
		//插入
		cur = new Node(val);
		//链接
		if (parent->_data > val)
			parent->_left = cur;
		else
			parent->_right = cur;
	}

	bool erase(const T& val)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_data == val)
				break;
			parent = cur;
			if (cur->_data > val)
				cur = cur->_left;
			else
				cur = cur->_right;
		}
		//判断需要删除的节点是否存在
		if (cur == nullptr)
			return false;
		else
		{
			//1.删除的为叶子节点
			if (cur->_left == nullptr && cur->_right == nullptr)
			{
				//判断是否为根节点
				if (cur == _root)
					_root == nullptr;
				else
				{
					if (parent->_left == cur)
						parent->_left = nullptr;
					else
						parent->_right = nullptr;
				}
				//删除节点
				delete cur;
			}
			//2.非叶子节点
			else if (cur->_left == cur)
			{
				//判断是否为根节点
				if (cur == _root)
				{
					//更新根节点
					_root = cur->_right;
				}
				else
				{
					if (parent->_left = cur)
						parent->_left = cur->_right;
					else
						parent->_right = cur->_right;
				}
				//删除节点
				delete cur;
			}
			//3.非叶子节点
			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;
			}
			//4.左右子树都存在
			else
			{
				//1.假设找左子树的最右节点
				Node* leftRightMost = cur->_left;
				parent = cur;
				while (leftRightMost->_right)
				{
					parent = leftRightMost;
					leftRightMost = leftRightMost->_right;
				}
				//交换最右节点和要删除节点的值
				swap(cur->_data, leftRightMost->_data);
				if (parent->_left == leftRightMost)
					parent->_left = leftRightMost->_left;
				else
					parent->_right = leftRightMost->_left;
				delete leftRightMost;
			}
			return true;
		}
	}

	Node* find(const T& val)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_data == val)
				return cur;
			else if (cur->_data > val)
				return cur->_left;
			else
				return cur->_right;
		}
	}

	void inorder()
	{
		_inorder(_root);
	}

	//搜索树的中序遍历有序
	void _inorder(Node* root)
	{
		if (root)
		{
			_inorder(root->_left);
			cout << root->_data << " ";
			_inorder(root->_right);
		}
	}

	void destroy(Node* root)
	{
		if (root)
		{
			destroy(root->_left);
			destroy(root->_right);
			cout << "destroy: " << root->_data << endl;
			delete root;
		}
	}

	~BTree()
	{
		if (_root)
		{
			destroy(_root);
			_root = nullptr;
		}
	}

private:
	Node* _root;
};

void test()
{
	BTree<int> b;
	b.insert(50);
	b.insert(90);
	b.insert(40);
	b.insert(20);
}

二叉搜索树的应用(KV模型)

KV模型:每一个关键码key,都有与之对应的值Value,即的键值对。该种方式在现实生活中非常常见:
比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文就构成一种键值对;

template <class K, class V>
struct BNode
{
	//T _data;
	K _key;		//类似于索引
	V _value;	//类似于data
	typedef BNode<K, V> Node;
	Node* _left;
	Node* _right;

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

template <class K, class V>
class BTree
{
public:
	typedef BNode<K, V> Node;
	
	BTree()
		:_root(nullptr)
	{}

	//拷贝二叉搜索树的数据和结构
	Node* copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		
		Node* newNode = new Node(root->_key, root->_value);
		newNode->_left = copy(root->_left);
		newNode->_right = copy(root->_right);
		return newNode;
	}

	BTree(const BTree<K, V>& btree)
		:_root(copy(btree._root))
	{}

	//不插入重复的值
	bool insert(const K& key, const V& value)
	{
		if (_root == nullptr)
		{
			_root = new Node(key, value);
			return true;
		}
		//搜索,找到合适的插入位置
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (cur->_key == key)
				return false;
			else if (cur->_key > key)
				cur = cur->_left;
			else
				cur = cur->_right;
		}
		//插入
		cur = new Node(key, value);
		//链接
		if (parent->_key > key)
			parent->_left = cur;
		else
			parent->_right = cur;
	}

	bool erase(const key& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_key == key)
				break;
			parent = cur;
			if (cur->_key > key)
				cur = cur->_left;
			else
				cur = cur->_right;
		}
		//判断需要删除的节点是否存在
		if (cur == nullptr)
			return false;
		else
		{
			//1.删除的为叶子节点
			if (cur->_left == nullptr && cur->_right == nullptr)
			{
				//判断是否为根节点
				if (cur == _root)
					_root == nullptr;
				else
				{
					if (parent->_left == cur)
						parent->_left = nullptr;
					else
						parent->_right = nullptr;
				}
				//删除节点
				delete cur;
			}
			//2.非叶子节点
			else if (cur->_left == cur)
			{
				//判断是否为根节点
				if (cur == _root)
				{
					//更新根节点
					_root = cur->_right;
				}
				else
				{
					if (parent->_left = cur)
						parent->_left = cur->_right;
					else
						parent->_right = cur->_right;
				}
				//删除节点
				delete cur;
			}
			//3.非叶子节点
			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;
			}
			//4.左右子树都存在
			else
			{
				//1.假设找左子树的最右节点
				Node* leftRightMost = cur->_left;
				parent = cur;
				while (leftRightMost->_right)
				{
					parent = leftRightMost;
					leftRightMost = leftRightMost->_right;
				}
				//交换最右节点和要删除节点的值
				swap(cur->_key, leftRightMost->_key);
				swap(cur->_value, leftRightMost->_value);

				if (parent->_left == leftRightMost)
					parent->_left = leftRightMost->_left;
				else
					parent->_right = leftRightMost->_left;
				delete leftRightMost;
			}
			return true;
		}
	}

	Node* find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key == key)
				return cur;
			else if (cur->_key > key)
				return cur->_left;
			else
				return cur->_right;
		}
	}

	void inorder()
	{
		_inorder(_root);
	}

	//搜索树的中序遍历有序
	void _inorder(Node* root)
	{
		if (root)
		{
			_inorder(root->_left);
			cout << root->_key << "-->" << root->_value << " ";
			_inorder(root->_right);
		}
	}

	void destroy(Node* root)
	{
		if (root)
		{
			destroy(root->_left);
			destroy(root->_right);
			cout << "destroy: " << root->_key << "-->" << root->_value << endl;
			delete root;
		}
	}

	~BTree()
	{
		if (_root)
		{
			destroy(_root);
			_root = nullptr;
		}
	}

private:
	Node* _root;
};

void test()
{
	BTree<int, int> b;
	//value可以重复,k不能重复
	b.insert(5, 50);
	b.insert(3, 30);
	b.insert(7, 40);
	b.insert(1, 20);

}

二叉搜索树性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为:O(log_n)
最差情况下,二叉搜索树退化为单支树(或者类似单支),其平均比较次数为:O(n)
如果退化成单支树,二叉搜索树的性能就失去了。

你可能感兴趣的:(算法,数据结构,c++)