c++ 二叉搜索树-Binary_Serach_Tree

一、二叉搜索树

1.1 定义

        若左子树不为空,那么左子树上的所有节点的值都小于根节点的值

        若右子树不为空,那么右子树上的所有节点的值都大于根节点的值

        其左右子树也是二叉搜索树。

1.2 意义

         有了这样的条件以后,可以非常方便且十分高效的进行数据查找。如果我们要哦查找1元素,首先和根节点5进行比较,因为比5小所以在5的左子树中进行进一步的查询,又因为1比3小所以再在3的左子树进行查询最后可以很顺利的找到 1 。

        普遍上来说二叉搜索树的查询效率为 logN  ,但是如果二叉树构建完成后是一条线的话,那么查找起来的效率也是 N 。

 二、搜索二叉树的实现

2.1 构造树的节点

树种的节点我们采用模板参数的方式来实现

其中有三个元素:左指针(left)、右指针(right)、存储值(key)。

#include<iostream>
using namespace std;
template<class K>
class BSTreeNode<K>
{
public:
    BSTreeNode(const K& key = K())
    :left(nullptr)
    ,right(nullptr)
    ,_key(key)
    {
    
    }
    BSTreeNode<k> * left;
    BSTreeNode<k> * right;
    K _key;
};

2.2 构造二叉搜索树

#include<iostream>
using namespace std;
template<class K>
class BSTreeNode<K>
{
public:
    BSTreeNode(const K& key = K())
    :left(nullptr)
    ,right(nullptr)
    ,_key(key)
    {
    
    }
    BSTreeNode<k> * left;
    BSTreeNode<k> * right;
    K _key;
};

template<class K>
class BSTree
{
typedef BSTreeNode<k> Node;

public:
    Node* _root = nullptr;
};

2.3 添加插入功能

 先判断是不是有一个空树,如果空树就新建一个节点并返回true。

如果不是空树,那就要确定插入的位置,首先和根节点的值进行比较比根节点小那就往左遍历,如果比根节点大那就往右遍历。具体实现如下所示,但是这么写会有一个问题,我们找到了具体应该插入的位置,并且新建了一个节点,但是 cur = new Node(key)这一步并没有真正的把节点插入到树中。

#include<iostream>
using namespace std;
template<class K>
class BSTreeNode<K>
{
public:
    BSTreeNode(const K& key = K())
    :left(nullptr)
    ,right(nullptr)
    ,_key(key)
    {
    
    }
    BSTreeNode<k> * left;
    BSTreeNode<k> * right;
    K _key;
};

template<class K>
class BSTree
{
typedef BSTreeNode<k> Node;
bool insert(const k& key)
{
    if(_root == nullptr)
    {
        _root = new Node(key);
        return true;
    }
    else
    {
        Node * cur = _root;
        while(cur)
        {
            if(cur->_key > key)
            {
                cur = cur->left;
            }
            else if(cur->_key < key)
            {
                cur = cur->right;
            }
            else 
            {
                return false;
            }
        }
        cur = new Node(key);
        return true;
    }
}

public:
    Node* _root = nullptr;
};

因为没有真正把节点插入到树种,所以我们需要保存一下插入节点位置的父节点,用父节点去指向这个新的位置即可。

#include<iostream>
using namespace std;
template<class K>
class BSTreeNode<K>
{
public:
    BSTreeNode(const K& key = K())
    :left(nullptr)
    ,right(nullptr)
    ,_key(key)
    {
    
    }
    BSTreeNode<k> * left;
    BSTreeNode<k> * right;
    K _key;
};

template<class K>
class BSTree
{
typedef BSTreeNode<k> Node;
bool insert(const k& key)
{
    if(_root == nullptr)
    {
        _root = new Node(key);
        return true;
    }
    else
    {
        Node * cur = _root;
        Node * parent = nullptr;
        while(cur)
        {
            parent = cur;
            if(cur->_key > key)
            {
                cur = cur->left;
            }
            else if(cur->_key < key)
            {
                cur = cur->right;
            }
            else 
            {
                return false;
            }
        }
        cur = new Node(key);
        if(parent->_key < key)
            parent->right = cur;
        else
            parent->left = cur;

        return true;
    }
}

public:
    Node* _root = nullptr;
};

 

#include<iostream>
using namespace std;
namespace key
{ 
	template<class k>
	struct BSTreeNode
	{
		BSTreeNode<k>* left;
		BSTreeNode<k>* right;
		k _key;
		BSTreeNode(const k& key)
			:left(nullptr)
			, right(nullptr)
			, _key(key)
		{

		}
	};
	template<class k>
	class BSTree
	{
		typedef BSTreeNode<k>Node;
	public:
		bool Insert(const k& key)
		{
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}
			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)
			{
				parent = cur;
				if (cur->_key < key)
				{
					cur = cur->right;
				}
				else if (cur->_key > key)
				{
					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 FindR(const k& key)
		{
			return _FindR(_root, key);
		}
		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;
			}
		}

		/*bool _InsertR(Node* &root, const k& key)
		{
			if (root == nullptr)
			{
				root = new Node(key);
				return true;
			}
			if (root->_key > key)
				return _InsertR(root->left, key);
			else if (root->_key < key)
				return _InsertR(root->right, key);
			else
				return false;
		}
		bool Insert(const k& key)
		{
			return _Insert(_root, key);
		}*/

		//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 _EraseR(root->right, key);
		//	}
		//	else if (root->key > key)
		//	{
		//		return _EraseR(root->left, key);
		//	}
		//	else
		//	{
		//		if (root->left == nullptr)
		//		{
		//			Node* del = root;
		//			root = root->right;
		//			delete del;
		//			return true;
		//		}
		//		else if (root->right == nullptr)
		//		{
		//			Node* del = root;
		//			root = root->left;
		//			delete del;
		//			return  true;
		//		}
		//		else
		//		{
		//			Node* subLeft = cur->right;
		//			while (subLeft->left)
		//			{
		//				parent = subLeft;
		//				subLeft = subLeft->left;
		//			}
		//			swap(cur->_key, subLeft->_key);
		//			//转换为子树去递归删除
		//			return _Erase(root->right, key);
		//		}
		//	}
		//}

		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
				{
					//开始删除
					if (cur->left == nullptr)//节点左为空
					{
						if (cur == _root)
						{
							_root = cur->right;
						}
						else
						{
							if (cur == parent->left)
							{
								parent->left = cur->right;
							}
							else
							{
								parent->right = cur->right;
							}
						}
					}
					else if (cur->right == nullptr)//节点右为空
					{
						if (cur == _root)
						{
							_root = cur->left;
						}
						else
						{
							if (cur == parent->left)
							{
								parent->left = cur->left;
							}
							else
							{
								parent->right = cur->left;
							}
						}
					}//判断左为空或者右为空的情况

					else//节点左右都不为空
					{
						//右树的最小节点(最左节点)
						Node* parent = cur;
						Node* subLeft = cur->right;
						while (subLeft->left)
						{
							parent = subLeft;
							subLeft = subLeft->left;
						}
						swap(cur->_key, subLeft->_key);
						if (subLeft == parent->left)
							parent->left = subLeft->right;
						else
							parent->right = subLeft->right;
					}
					return true;
				}
			}
			return false;
		}
		void InOrder()
		{
			_InOrder(_root);
		}
		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->left);
			cout << root->_key << " ";
			_InOrder(root->right);
		}
		void Destory(Node*& root)
		{
			if (root == nullptr)
				return;
			Destory(root->left);
			Destory(root->right);
			delete root;
			root = nullptr;
		}
		~BSTree()
		{
			Destory(_root);
		}
		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;
		}
		//BSTree()
		//{

		//}
		BSTree() = default;//等于上面的写法,强制生成默认的构造函数
		BSTree(const BSTree<k>& t)
		{
			_root = Copy(t._root);
		}
		BSTree<k>& operator=(BSTree<k>t)
		{
			swap(_root, t._root);
			return *this;
		}
	private:
		Node* _root = nullptr;
	};
}

//namespace kv
//{
//	template<class k,class v>
//	class BSTreeNode
//	{
//	public:
//		BSTreeNode<k,v>* left;
//		BSTreeNode<k,v>* right;
//		k _key;
//		v _value;
//		BSTreeNode(const k& key = k(), const v& value = v())
//			:left(nullptr)
//			,right(nullptr)
//			,_key(key)
//			,_value(value)
//		{
//			/*left = nullptr;
//			right = nullptr;
//			_key = key;
//			_value = value;*/
//		}
//	};
//	template<class k,class v>
//	class BSTree
//	{
//		typedef BSTreeNode<k,v> Node;
//	public:
//		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)
//				{
//					cur = cur->right;
//				}
//				else if (cur->_key > key)
//				{
//					cur = cur->left;
//				}
//				else
//				{
//					return false;
//				}
//			}
//			cur = new Node(key,value);
//			if (parent->_key < key)
//			{
//				parent->right = cur;
//			}
//			else
//			{
//				parent->left = cur;
//			}
//			return true;
//		}
//		Node* 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 cur;
//			}
//			return nullptr;
//		}
//
//		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
//				{
//					//开始删除
//					if (cur->left == nullptr)//节点左为空
//					{
//						if (cur == _root)
//						{
//							_root = cur->right;
//						}
//						else
//						{
//							if (cur == parent->left)
//							{
//								parent->left = cur->right;
//							}
//							else
//							{
//								parent->right = cur->right;
//							}
//						}
//					}
//					else if (cur->right == nullptr)//节点右为空
//					{
//						if (cur == _root)
//						{
//							_root = cur->left;
//						}
//						else
//						{
//							if (cur == parent->left)
//							{
//								parent->left = cur->left;
//							}
//							else
//							{
//								parent->right = cur->left;
//							}
//						}
//					}//判断左为空或者右为空的情况
//
//					else//节点左右都不为空
//					{
//						//右树的最小节点(最左节点)
//						Node* parent = cur;
//						Node* subLeft = cur->right;
//						while (subLeft->left)
//						{
//							parent = subLeft;
//							subLeft = subLeft->left;
//						}
//						swap(cur->_key, subLeft->_key);
//						if (subLeft == parent->left)
//							parent->left = subLeft->right;
//						else
//							parent->right = subLeft->right;
//					}
//					return true;
//				}
//			}
//			return false;
//		}
//		void InOrder()
//		{
//			_InOrder(_root);
//		}
//		void _InOrder(Node* root)
//		{
//			if (root == nullptr)
//			{
//				return;
//			}
//			_InOrder(root->left);
//			cout << root->_key << ":" << root->_value << endl;
//			_InOrder(root->right);
//		}
//		void Destory(Node*& root)
//		{
//			if (root == nullptr)
//				return;
//			Destory(root->left);
//			Destory(root->right);
//			delete root;
//			root = nullptr;
//		}
//		~BSTree()
//		{
//			Destory(_root);
//		}
//		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;
//		}
//		BSTree() = default;//等于上面的写法,强制生成默认的构造函数
//	
//	private:
//		Node* _root = nullptr;
//	};
//}

2.4 删除功能

2.4.1 删除的几种情况

        其中情况D在删除一个节点时,如果这个节点不是叶子结点,那我们就要进行替换法进行删除。

可替换的节点有两个。

其一是左子树的最大节点(为左子树的最右节点,右子树为空)

其二是右子树的最小节点(为右子树的最左节点,左子树为空)

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
				{
					//开始删除
					if (cur->left == nullptr)//节点左为空
					{
						if (cur == _root)
						{
							_root = cur->right;
						}
						else
						{
							if (cur == parent->left)
							{
								parent->left = cur->right;
							}
							else
							{
								parent->right = cur->right;
							}
						}
					}
					else if (cur->right == nullptr)//节点右为空
					{
						if (cur == _root)
						{
							_root = cur->left;
						}
						else
						{
							if (cur == parent->left)
							{
								parent->left = cur->left;
							}
							else
							{
								parent->right = cur->left;
							}
						}
					}//判断左为空或者右为空的情况

					else//节点左右都不为空
					{
						//右树的最小节点(最左节点)
						Node* parent = cur;
						Node* subLeft = cur->right;
						while (subLeft->left)
						{
							parent = subLeft;
							subLeft = subLeft->left;
						}
						swap(cur->_key, subLeft->_key);
						if (subLeft == parent->left)
							parent->left = subLeft->right;
						else
							parent->right = subLeft->right;
					}
					return true;
				}
			}
			return false;
		}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码看起来是一个CMake脚本,用于构建和安装CTK(Common Toolkit)项目。CTK是一个开源的C++工具包,用于开发医学图像处理和可视化应用。 这段代码的主要作用是使用ExternalProject_Add函数来添加CTK项目,并设置构建和安装选项。以下是对代码中各部分的解释: 1. 创建目录:首先,通过`if(NOT EXISTS ${CTK_BINARY_DIR}/CTK-build/bin)`判断`${CTK_BINARY_DIR}/CTK-build/bin`目录是否存在,如果不存在,则使用`file(MAKE_DIRECTORY ${CTK_BINARY_DIR}/CTK-build/bin)`创建该目录。这个目录可能用于存放编译后的可执行文件。 2. 设置项目名称:通过`set(proj CTK)`设置项目名称为CTK。 3. 设置C++标准:根据`${CMAKE_CXX_STANDARD}`的值,通过`set(ep_cxx_standard_arg "-DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD}")`设置CMake的C++标准选项。 4. 设置安装命令:根据当前操作系统的类型,通过`if(WIN32)`判断,如果是Windows系统,则设置`_INSTALL_CMD`为`nmake install`,否则设置为`make install`。这个命令将在构建完成后执行安装操作。 5. 设置安装目录:通过`set(_INSTALL_DIR ${CTK_BINARY_DIR}/../CTKInstall)`设置安装目录为`${CTK_BINARY_DIR}/../CTKInstall`。这个目录将用于安装CTK项目。 6. 添加CTK项目:通过`ExternalProject_Add`函数添加CTK项目,并设置相关的CMake选项和参数。其中,`SOURCE_DIR`指定CTK源码目录,`BINARY_DIR`指定CTK构建目录,`INSTALL_COMMAND`指定安装命令,`DEPENDS`指定CTK项目的依赖项。 以上就是这段代码的主要内容和作用。通过执行这段脚本,可以构建和安装CTK项目,并将结果安装到指定的目录中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值